Skip to content

Fix NPC-to-NPC damage checking the shooter instead of the target - #1291

Open
GuiBoneVowt wants to merge 1 commit into
openmultiplayer:masterfrom
GuiBoneVowt:fix-npc-shot-target-checks
Open

GuiBoneVowt wants to merge 1 commit into
openmultiplayer:masterfrom
GuiBoneVowt:fix-npc-shot-target-checks

Conversation

@GuiBoneVowt

Copy link
Copy Markdown

When an NPC shoots another NPC, NPC::shoot only applies the damage if (!dead_ && !invulnerable_), and those are the shooter's fields. The player → NPC path (NPCComponent::onPlayerGiveDamage) checks the target with npc->isInvulnerable(), which matches what NPC_SetInvulnerable is for ("Sets whether an NPC is invulnerable to damage").

On current master this means:

  • an invulnerable NPC still takes damage from other NPCs;
  • an invulnerable NPC can't damage other NPCs;
  • shooting an NPC that is already dead still calls OnNPCTakeDamage.

This PR checks the target's dead and invulnerable state. The shooter's dead check stays, so a dead NPC still can't hurt anyone.

Testing

Windows, RelWithDebInfo, Win32 + ClangCL, on top of current master (72bf89c). Headless gamemode: two NPCs 2 units apart, NPC_Shoot with a Deagle and NPC_ENTITY_CHECK_NONE. Ran twice on each build, same results.

Case master this PR
Target invulnerable, shot once health 100 → 53.7, OnNPCTakeDamage called health stays 100, no callback
Shooter invulnerable, shoots once target health stays 100 target health 100 → 53.7
Target shot three times dies, OnNPCDeath once same
Already-dead target shot once OnNPCTakeDamage called not called
NPC_Respawn, then shot three times dies again, OnNPCDeath twice same
Core of the test
new shooter = NPC_Create("shooter"), target = NPC_Create("target");
NPC_Spawn(shooter);
NPC_Spawn(target);
NPC_SetPos(shooter, 0.0, 0.0, 3.0);
NPC_SetPos(target, 2.0, 0.0, 3.0);

// A second later:
NPC_SetInvulnerable(target, true);
NPC_Shoot(shooter, WEAPON_DEAGLE, target, _:BULLET_HIT_TYPE_PLAYER, 2.0, 0.0, 3.0, 0.0, 0.0, 0.0, true, NPC_ENTITY_CHECK_NONE);
printf("%.1f", NPC_GetHealth(target)); // master: 53.7, this PR: 100.0

clang-format 13 with the repo's .clang-format: no changes.

NPC::shoot applied NPC-to-NPC damage only if the shooter was alive and not
invulnerable. So an invulnerable NPC still took damage from other NPCs, an
invulnerable NPC could not damage them, and a dead NPC kept getting
OnNPCTakeDamage. Check the target's dead and invulnerable state, as
onPlayerGiveDamage already does for damage from players. The shooter's dead
check stays.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant