Skip to content

Commit aa1f73f

Browse files
committed
fix(model): ModelScene spell animations do not play over a death
A unit without health plays only death animations: CGUnit_C:: PlayAnimation (0x005FE2F0) returns unless IsDeathAnimation (0x005FDA90, __stdcall) holds for the animation. An actor had no such gate, so a missile already in flight when the target died still played its wound (and its impact kit's animation) on arrival and replaced the death animation; StopSpellVisual only drops the casts still preparing. An actor whose own animation is a death animation now takes no kit animation over it, and setting a death drops the kit animation that plays. The missiles still land and show their impact effects.
1 parent 1d70cb3 commit aa1f73f

2 files changed

Lines changed: 21 additions & 0 deletions

File tree

‎src/Offsets.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6376,6 +6376,10 @@ enum Offsets {
63766376
// right hand (attachment 1) for the main-hand lane and the left (2) for
63776377
// the off hand (AttachItemModel 0x0047A0C0).
63786378
FUN_M2MODEL_HAS_ANIMATION = 0x00711960,
6379+
// IsDeathAnimation `int __stdcall(int anim)`, ret 4 (a jump table). A
6380+
// dead unit plays only death animations: CGUnit_C::PlayAnimation
6381+
// (0x005FE2F0) returns for health below 1 unless the animation is one.
6382+
FUN_IS_DEATH_ANIMATION = 0x005FDA90,
63796383
ANIM_STAND = 0,
63806384
ANIM_BOW_PULL = 160,
63816385
ANIM_BOW_RELEASE = 161,

‎src/model/SceneActor.cpp‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,9 +461,26 @@ void Actor::ClearModel() {
461461
RunScript(S_ONMODELCLEARED, 0);
462462
}
463463

464+
namespace {
465+
466+
bool IsDeathAnimation(int anim) {
467+
return reinterpret_cast<int(__stdcall *)(int)>(Offsets::FUN_IS_DEATH_ANIMATION)(anim) != 0;
468+
}
469+
470+
} // namespace
471+
472+
// An actor whose own animation is a death animation is dead to its spells, as
473+
// a unit without health is to its PlayAnimation (0x005FE2F0): a kit's
474+
// animation (a cast, an impact, a wound) does not play over the death, and a
475+
// death drops the one that plays.
464476
void Actor::PlayAnimation() {
465477
if (model == nullptr)
466478
return;
479+
if (kitAnimation >= 0 && IsDeathAnimation(static_cast<int>(animation)) && !IsDeathAnimation(kitAnimation)) {
480+
kitAnimation = -1;
481+
kitAnimationLoops = false;
482+
kitAnimationEnded = true;
483+
}
467484
heldPositionMs = -1; // a paused actor holds the new animation's first frame
468485
// An end the scene's advance reported for the animation this replaces is
469486
// not this one's: the engine reports a replaced play as reason 1, which

0 commit comments

Comments
 (0)