NEO-98: Set melee strike to 2 m and elite slam to 4 m.
parent
99aa2b455f
commit
44fb4adbe5
|
|
@ -5,7 +5,7 @@
|
||||||
"id": "prototype_npc_melee_strike",
|
"id": "prototype_npc_melee_strike",
|
||||||
"displayName": "NPC Melee Strike",
|
"displayName": "NPC Melee Strike",
|
||||||
"baseDamage": 15,
|
"baseDamage": 15,
|
||||||
"maxRange": 1.0,
|
"maxRange": 2.0,
|
||||||
"cooldownSeconds": 3.0,
|
"cooldownSeconds": 3.0,
|
||||||
"abilityKind": "attack"
|
"abilityKind": "attack"
|
||||||
},
|
},
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
"id": "prototype_npc_elite_slam",
|
"id": "prototype_npc_elite_slam",
|
||||||
"displayName": "NPC Elite Slam",
|
"displayName": "NPC Elite Slam",
|
||||||
"baseDamage": 25,
|
"baseDamage": 25,
|
||||||
"maxRange": 8.0,
|
"maxRange": 4.0,
|
||||||
"cooldownSeconds": 5.0,
|
"cooldownSeconds": 5.0,
|
||||||
"abilityKind": "attack"
|
"abilityKind": "attack"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@
|
||||||
|
|
||||||
| Archetype | Instance id | Marker | maxHp | Pulses to defeat | NPC damage | Strike range | Windup | Cooldown |
|
| Archetype | Instance id | Marker | maxHp | Pulses to defeat | NPC damage | Strike range | Windup | Cooldown |
|
||||||
|-----------|-------------|--------|-------|------------------|------------|--------------|--------|----------|
|
|-----------|-------------|--------|-------|------------------|------------|--------------|--------|----------|
|
||||||
| Melee | `prototype_npc_melee` | orange west **`(-3, -3)`** | 100 | **4** | 15 | **1 m** (close) | 1.5 s | 3.0 s |
|
| Melee | `prototype_npc_melee` | orange west **`(-3, -3)`** | 100 | **4** | 15 | **2 m** (close) | 1.5 s | 3.0 s |
|
||||||
| Ranged | `prototype_npc_ranged` | purple SE **`(3, 3)`** | 80 | **4** | 12 | 10 m | 2.0 s | 4.0 s |
|
| Ranged | `prototype_npc_ranged` | purple SE **`(3, 3)`** | 80 | **4** | 12 | 10 m | 2.0 s | 4.0 s |
|
||||||
| Elite | `prototype_npc_elite` | gold origin **`(0, 0)`** | 200 | **8** | 25 | 8 m | 2.5 s | 5.0 s |
|
| Elite | `prototype_npc_elite` | gold origin **`(0, 0)`** | 200 | **8** | 25 | **4 m** | 2.5 s | 5.0 s |
|
||||||
|
|
||||||
Player casts **`prototype_pulse`** (**25** damage, ~**3 s** cooldown).
|
Player casts **`prototype_pulse`** (**25** damage, ~**3 s** cooldown).
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ Player casts **`prototype_pulse`** (**25** damage, ~**3 s** cooldown).
|
||||||
5. Press **1** (damaging cast): **`CastFeedbackLabel`** shows damage; **`NpcStateLabel`** eventually shows **`NPC state: Melee → aggro`** (~1 Hz poll).
|
5. Press **1** (damaging cast): **`CastFeedbackLabel`** shows damage; **`NpcStateLabel`** eventually shows **`NPC state: Melee → aggro`** (~1 Hz poll).
|
||||||
6. **`PlayerCombatHpLabel`** shows **`Player HP: 100/100`** once combat poll starts.
|
6. **`PlayerCombatHpLabel`** shows **`Player HP: 100/100`** once combat poll starts.
|
||||||
7. Wait **≥ 3 s** from first cast: **`NpcStateLabel`** shows **`telegraph_windup`**; **`TelegraphLabel`** shows countdown (e.g. **`Telegraph: Melee … · ~1.x s (melee)`**) ticking between polls.
|
7. Wait **≥ 3 s** from first cast: **`NpcStateLabel`** shows **`telegraph_windup`**; **`TelegraphLabel`** shows countdown (e.g. **`Telegraph: Melee … · ~1.x s (melee)`**) ticking between polls.
|
||||||
8. Wait **≥ 4.5 s** total from first cast (windup completes): stay **within ~1 m** of the melee marker (close combat — tab-lock is 6 m but strike range is **1 m**). **`PlayerCombatHpLabel`** drops to **`85/100`** (melee **15** damage). Back off during windup → telegraph may finish but **no** player damage (whiff).
|
8. Wait **≥ 4.5 s** total from first cast (windup completes): stay **within ~2 m** of the melee marker (close combat — tab-lock is 6 m but strike range is **2 m**). **`PlayerCombatHpLabel`** drops to **`85/100`** (melee **15** damage). Back off during windup → telegraph may finish but **no** player damage (whiff).
|
||||||
9. Press **1** three more times (respect ~3 s cooldown) until **`CombatTargetHpLabel`** shows **`0/100 (defeated)`** per defeat table above.
|
9. Press **1** three more times (respect ~3 s cooldown) until **`CombatTargetHpLabel`** shows **`0/100 (defeated)`** per defeat table above.
|
||||||
10. Press **1** again: **`ability_cast_denied: target_defeated`**.
|
10. Press **1** again: **`ability_cast_denied: target_defeated`**.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ public class AbilityDefinitionCatalogLoaderTests
|
||||||
"id": "prototype_npc_melee_strike",
|
"id": "prototype_npc_melee_strike",
|
||||||
"displayName": "NPC Melee Strike",
|
"displayName": "NPC Melee Strike",
|
||||||
"baseDamage": 15,
|
"baseDamage": 15,
|
||||||
"maxRange": 1.0,
|
"maxRange": 2.0,
|
||||||
"cooldownSeconds": 3.0,
|
"cooldownSeconds": 3.0,
|
||||||
"abilityKind": "attack"
|
"abilityKind": "attack"
|
||||||
},
|
},
|
||||||
|
|
@ -78,7 +78,7 @@ public class AbilityDefinitionCatalogLoaderTests
|
||||||
"id": "prototype_npc_elite_slam",
|
"id": "prototype_npc_elite_slam",
|
||||||
"displayName": "NPC Elite Slam",
|
"displayName": "NPC Elite Slam",
|
||||||
"baseDamage": 25,
|
"baseDamage": 25,
|
||||||
"maxRange": 8.0,
|
"maxRange": 4.0,
|
||||||
"cooldownSeconds": 5.0,
|
"cooldownSeconds": 5.0,
|
||||||
"abilityKind": "attack"
|
"abilityKind": "attack"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,6 @@ public class AbilityDefinitionsWorldApiTests
|
||||||
|
|
||||||
var meleeStrike = body.Abilities.Single(a => a.Id == "prototype_npc_melee_strike");
|
var meleeStrike = body.Abilities.Single(a => a.Id == "prototype_npc_melee_strike");
|
||||||
Assert.Equal(15, meleeStrike.BaseDamage);
|
Assert.Equal(15, meleeStrike.BaseDamage);
|
||||||
Assert.Equal(1.0, meleeStrike.MaxRange);
|
Assert.Equal(2.0, meleeStrike.MaxRange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ public static class PrototypeNpcTestFixtures
|
||||||
"NPC Melee Strike",
|
"NPC Melee Strike",
|
||||||
15,
|
15,
|
||||||
3.0,
|
3.0,
|
||||||
1.0,
|
2.0,
|
||||||
"attack"),
|
"attack"),
|
||||||
[PrototypeNpcAttackAbilityRegistry.PrototypeNpcRangedShot] = new(
|
[PrototypeNpcAttackAbilityRegistry.PrototypeNpcRangedShot] = new(
|
||||||
PrototypeNpcAttackAbilityRegistry.PrototypeNpcRangedShot,
|
PrototypeNpcAttackAbilityRegistry.PrototypeNpcRangedShot,
|
||||||
|
|
@ -58,7 +58,7 @@ public static class PrototypeNpcTestFixtures
|
||||||
"NPC Elite Slam",
|
"NPC Elite Slam",
|
||||||
25,
|
25,
|
||||||
5.0,
|
5.0,
|
||||||
8.0,
|
4.0,
|
||||||
"attack"),
|
"attack"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,7 @@ Per-NPC aggro holders live in **`Game/Npc/`** as **`IThreatStateStore`** + **`In
|
||||||
| Rule | Behavior |
|
| Rule | Behavior |
|
||||||
|------|----------|
|
|------|----------|
|
||||||
| **Acquire** | First **damaging** cast on an NPC sets holder to the casting player when the row is empty (**`AggroOperations.TryAcquire`** from **`AbilityCastApi`**). Zero-damage abilities do not acquire. |
|
| **Acquire** | First **damaging** cast on an NPC sets holder to the casting player when the row is empty (**`AggroOperations.TryAcquire`** from **`AbilityCastApi`**). Zero-damage abilities do not acquire. |
|
||||||
| **Attack range** | At telegraph resolve, damage applies only when the holder is within the bound attack ability's catalog **`maxRange`** of the NPC anchor (horizontal X/Z, inclusive). Melee strike **1 m**, ranged shot **10 m**, elite slam **8 m** — distinct from behavior **`aggroRadius`** (re-aggro) and tab-lock **6 m**. Out-of-range windups whiff (no damage; state still advances). |
|
| **Attack range** | At telegraph resolve, damage applies only when the holder is within the bound attack ability's catalog **`maxRange`** of the NPC anchor (horizontal X/Z, inclusive). Melee strike **2 m**, ranged shot **10 m**, elite slam **4 m** — distinct from behavior **`aggroRadius`** (re-aggro) and tab-lock **6 m**. Out-of-range windups whiff (no damage; state still advances). |
|
||||||
| **Leash clear** | Holder clears when that player moves beyond the bound behavior def **`leashRadius`** from the NPC anchor (horizontal X/Z distance). Wired on **`POST /move`**, **`POST /move-stream`**, and before acquire on cast. |
|
| **Leash clear** | Holder clears when that player moves beyond the bound behavior def **`leashRadius`** from the NPC anchor (horizontal X/Z distance). Wired on **`POST /move`**, **`POST /move-stream`**, and before acquire on cast. |
|
||||||
| **Defeat clear** | When **`ICombatEntityHealthStore`** marks the NPC **`defeated`**, **`NpcRuntimeOperations.TryStopOnTargetDefeat`** clears holder and resets runtime to **`idle`** (cast accept + lazy advance guard). |
|
| **Defeat clear** | When **`ICombatEntityHealthStore`** marks the NPC **`defeated`**, **`NpcRuntimeOperations.TryStopOnTargetDefeat`** clears holder and resets runtime to **`idle`** (cast accept + lazy advance guard). |
|
||||||
| **Re-aggro** | After clear, the same first-hit rule applies — no proximity auto-aggro in this slice. |
|
| **Re-aggro** | After clear, the same first-hit rule applies — no proximity auto-aggro in this slice. |
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue