mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Implemented an improved animation registration process
This commit is contained in:
@@ -37,12 +37,15 @@ enum AnimFlags {
|
|||||||
e_Append = 0x100, // sfall flag
|
e_Append = 0x100, // sfall flag
|
||||||
};
|
};
|
||||||
|
|
||||||
//static int animationLimit = 32;
|
static int animationLimit = 32;
|
||||||
|
static int lockLimit;
|
||||||
|
|
||||||
//pointers to new animation struct arrays
|
//pointers to new animation struct arrays
|
||||||
static std::vector<fo::AnimationSet> sf_anim_set;
|
static std::vector<fo::AnimationSet> sf_anim_set;
|
||||||
static std::vector<fo::AnimationSad> sf_sad;
|
static std::vector<fo::AnimationSad> sf_sad;
|
||||||
|
|
||||||
|
static std::vector<int8_t> lockAnimSet;
|
||||||
|
|
||||||
static fo::AnimationSet* animSet = (fo::AnimationSet*)FO_VAR_anim_set;
|
static fo::AnimationSet* animSet = (fo::AnimationSet*)FO_VAR_anim_set;
|
||||||
static fo::AnimationSad* animSad = (fo::AnimationSad*)FO_VAR_sad;
|
static fo::AnimationSad* animSad = (fo::AnimationSad*)FO_VAR_sad;
|
||||||
|
|
||||||
@@ -90,8 +93,9 @@ static struct AnimSetHack {
|
|||||||
0x413AA4, 0x413DBC,
|
0x413AA4, 0x413DBC,
|
||||||
};
|
};
|
||||||
|
|
||||||
const DWORD anim_set_10[6] = { // anim_0.animType
|
const DWORD anim_set_10[5] = { // anim_0.animType
|
||||||
0x413C7E, 0x413E8A, 0x413F17, 0x415C24, 0x415D16, 0x415D44,
|
0x413C7E, 0x413F17, 0x415C24, 0x415D16, 0x415D44,
|
||||||
|
/*0x413E8A, - conflict with 0x413E88*/
|
||||||
};
|
};
|
||||||
|
|
||||||
const DWORD anim_set_14[6] = { // anim_0.source
|
const DWORD anim_set_14[6] = { // anim_0.source
|
||||||
@@ -168,6 +172,236 @@ static struct SadHack {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
long regSlot = -2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
When the check_registry_ function finds an object for which a new animation
|
||||||
|
is being registered in the list of a sequence of already registered
|
||||||
|
animations, the engine stops registering animations for this object.
|
||||||
|
|
||||||
|
This implementation will copy all currently registered animations from the
|
||||||
|
current slot to another slot with already registered animations, appending
|
||||||
|
them to the end of the sequence.
|
||||||
|
|
||||||
|
This allows the engine to continue to animate the object sequentially.
|
||||||
|
*/
|
||||||
|
static long __fastcall CopyRegistry(long checkSlot) {
|
||||||
|
long currRegSlot = fo::var::curr_anim_set;
|
||||||
|
if (!(animSet[currRegSlot].flags & AnimFlags::e_Reserved)) return 0;
|
||||||
|
|
||||||
|
if (currRegSlot == checkSlot) { // this will be bug!
|
||||||
|
#ifndef NDEBUG
|
||||||
|
BREAKPOINT;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
long currRegAnims = fo::var::curr_anim_counter;
|
||||||
|
long lastAnim = animSet[checkSlot].totalAnimCount;
|
||||||
|
|
||||||
|
devlog_f("\n\nCopyRegistry: animSet[%d] anims:%d >> animSet[%d] anims:%d", 0, currRegSlot, currRegAnims, checkSlot, lastAnim);
|
||||||
|
devlog_f("\n checkSlot: currAnim:%d, counter:%d", 0, animSet[checkSlot].currentAnim, animSet[checkSlot].counter);
|
||||||
|
|
||||||
|
for (long i = animSet[checkSlot].counter; i < lastAnim; i++) {
|
||||||
|
long animType = animSet[checkSlot].animations[i].animType;
|
||||||
|
devlog_f("\n anim[%d]: animType:%d, animCode:%d", 0, i, animType, animSet[checkSlot].animations[i].animCode);
|
||||||
|
if (animType < 4) return 0; // don't add to "move to" types of animations
|
||||||
|
}
|
||||||
|
|
||||||
|
long totalRegAnims = (animSet[checkSlot].flags & AnimFlags::e_Append) ? currRegAnims : lastAnim + currRegAnims;
|
||||||
|
if (totalRegAnims >= 55) return 0; // not enough slots for animations
|
||||||
|
|
||||||
|
// copy the animations of the registered slot to the slot with the existing animations
|
||||||
|
for (long i = 0; i < currRegAnims; i++) {
|
||||||
|
devlog_f("\n Copy slot: animSet[%d].anim[%d] >> animSet[%d].anim[%d]", 0, currRegSlot, i, checkSlot, lastAnim);
|
||||||
|
animSet[checkSlot].animations[lastAnim++] = animSet[currRegSlot].animations[i];
|
||||||
|
|
||||||
|
//std::memset(&animSet[currRegSlot].animations[i], -1, 48);
|
||||||
|
}
|
||||||
|
animSet[checkSlot].flags |= animSet[currRegSlot].flags | AnimFlags::e_Append | AnimFlags::e_Suspend; // set flags
|
||||||
|
animSet[currRegSlot].flags = 0;
|
||||||
|
|
||||||
|
fo::var::curr_anim_counter = totalRegAnims; // set the current number of registered animations in the slot
|
||||||
|
fo::var::curr_anim_set = checkSlot; // replace the currently registered slot with a slot with existing registered animations
|
||||||
|
|
||||||
|
regSlot = checkSlot;
|
||||||
|
return lastAnim;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) check_registry_hack() {
|
||||||
|
__asm {
|
||||||
|
mov eax, animSet;
|
||||||
|
cmp [eax][edx][0x10], 0x0B; // animSet[].anim[].animType == Must_Call
|
||||||
|
je skip;
|
||||||
|
//cmp [eax][edx][0x10], 0x0C; // animSet[].anim[].animType == Call3
|
||||||
|
//je skip;
|
||||||
|
test [eax][esi][0x0C], e_EndAnim; // anim_set[].flags
|
||||||
|
jnz skip;
|
||||||
|
push ecx;
|
||||||
|
push edx;
|
||||||
|
call CopyRegistry;
|
||||||
|
test eax, eax;
|
||||||
|
cmovnz ebx, eax; // set ebx to the current count of animations to check the next anim_set slot
|
||||||
|
pop edx;
|
||||||
|
pop ecx;
|
||||||
|
// (re)set ZF
|
||||||
|
setz al;
|
||||||
|
test al, al;
|
||||||
|
skip:
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static long __fastcall anim_cleanup_sub(long currAnims) {
|
||||||
|
//long currAnims = fo::var::curr_anim_counter;
|
||||||
|
fo::AnimationSet* set = &animSet[fo::var::curr_anim_set];
|
||||||
|
if (set->flags & AnimFlags::e_Append) {
|
||||||
|
set->flags ^= AnimFlags::e_Append;
|
||||||
|
if (set->currentAnim == -1000 || set->totalAnimCount >= currAnims) return -1;
|
||||||
|
return set->totalAnimCount;
|
||||||
|
}
|
||||||
|
// default
|
||||||
|
return (currAnims <= 0) ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) anim_cleanup_hack() {
|
||||||
|
__asm {
|
||||||
|
call anim_cleanup_sub;
|
||||||
|
mov ecx, eax; // ecx - anims slot index
|
||||||
|
mov ebx, eax; // ebx - anims counter
|
||||||
|
test eax, eax;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static long __fastcall LockAnimSlot(long slot) {
|
||||||
|
if (animSet[slot].counter != animSet[slot].totalAnimCount) {
|
||||||
|
lockAnimSet[slot] = 8;
|
||||||
|
}
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long __fastcall UnlockAnimSlot(long slot) {
|
||||||
|
long lockCount = 0;
|
||||||
|
for (auto it = lockAnimSet.begin(); it != lockAnimSet.end(); ++it) {
|
||||||
|
if (*it > 0) {
|
||||||
|
(*it)--;
|
||||||
|
lockCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lockCount > lockLimit) fo::func::debug_printf("\n[SFALL] Warning: The number of animated slots in the lock is too large, locked %d of %d", lockCount, animationLimit);
|
||||||
|
|
||||||
|
//if (slot) slot /= sizeof(fo::AnimationSet);
|
||||||
|
//lockAnimSet[slot] = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BYTE __fastcall CheckLockAnimSlot(long, long slot) {
|
||||||
|
return lockAnimSet[slot];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
static void CheckReg() {
|
||||||
|
long s = regSlot;
|
||||||
|
regSlot = -2;
|
||||||
|
if (s != fo::var::curr_anim_set) return;
|
||||||
|
|
||||||
|
dlog_f("\nregister_end: anim_set: %d, total_anim: %d", 0, fo::var::curr_anim_set, fo::var::curr_anim_counter);
|
||||||
|
for (long i = 0; i < fo::var::curr_anim_counter; i++) {
|
||||||
|
dlog_f("\n anim[%d]: animType:%d, animCode:%d, source:%d (%s), callFunc:%d, callFunc3:%d", 0, i,
|
||||||
|
animSet[s].animations[i].animType, animSet[s].animations[i].animCode,
|
||||||
|
animSet[s].animations[i].source, fo::func::critter_name(animSet[s].animations[i].source),
|
||||||
|
animSet[s].animations[i].callFunc, animSet[s].animations[i].callFunc3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void __declspec(naked) register_end_hack_begin() {
|
||||||
|
__asm {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
pushadc;
|
||||||
|
call CheckReg;
|
||||||
|
popadc;
|
||||||
|
#endif
|
||||||
|
mov edx, ds:[FO_VAR_curr_anim_counter];
|
||||||
|
mov esi, animSet;
|
||||||
|
and [esi][eax][0xC], ~e_InUse; // animSet[].flags (unset inUse flag)
|
||||||
|
test word ptr [esi][eax][0xC], e_Append; // animSet[].flags
|
||||||
|
jnz isAppend; // is set
|
||||||
|
retn;
|
||||||
|
isAppend:
|
||||||
|
mov [esi][eax][0x8], edx; // animSet[].totalAnimCount
|
||||||
|
add esp, 4;
|
||||||
|
mov edx, 0x413D14;
|
||||||
|
mov esi, eax; // keep offset to anim_set slot
|
||||||
|
jmp edx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) register_end_hack_end() {
|
||||||
|
__asm {
|
||||||
|
mov eax, animSet;
|
||||||
|
mov dx, [eax][esi][0xC]; // animSet[].flags
|
||||||
|
test dx, e_Append; // slot with added animation?
|
||||||
|
jz skip;
|
||||||
|
and dx, ~(e_Append | e_Suspend); // unset flags
|
||||||
|
skip:
|
||||||
|
mov [eax][esi][0xC], dx; // animSet[].flags
|
||||||
|
//mov ecx, esi;
|
||||||
|
call UnlockAnimSlot;
|
||||||
|
pop esi;
|
||||||
|
pop edx;
|
||||||
|
pop ecx;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) register_clear_hook() {
|
||||||
|
__asm {
|
||||||
|
mov ecx, eax;
|
||||||
|
call LockAnimSlot;
|
||||||
|
jmp fo::funcoffs::anim_set_end_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) anim_free_slot_hack() {
|
||||||
|
static const DWORD anim_free_slot_next = 0x413BD5;
|
||||||
|
using namespace fo;
|
||||||
|
__asm {
|
||||||
|
pushadc;
|
||||||
|
call CheckLockAnimSlot;
|
||||||
|
test al, al;
|
||||||
|
popadc;
|
||||||
|
jnz isLock;
|
||||||
|
test word ptr [esp + 0x10 - 0x10 + 4], RB_UNKNOWN; // command & RB_100_ (register_ping_)
|
||||||
|
retn;
|
||||||
|
isLock:
|
||||||
|
add esp, 4;
|
||||||
|
jmp anim_free_slot_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ClearAllLock() {
|
||||||
|
std::fill(lockAnimSet.begin(), lockAnimSet.end(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) anim_stop_hack() {
|
||||||
|
__asm {
|
||||||
|
call ClearAllLock;
|
||||||
|
mov edx, 1;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
static void __fastcall ClearDataAnimations(long slot) {
|
||||||
|
std::memset(animSet[slot].animations, 0, sizeof(fo::AnimationSet) - 16);
|
||||||
|
//dlog_f("\nanim_set_end: clear all animations data in slot %d", 0, slot);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void __declspec(naked) anim_set_end_hack() {
|
static void __declspec(naked) anim_set_end_hack() {
|
||||||
__asm {
|
__asm {
|
||||||
test dl, e_InCombat; // is combat flag set?
|
test dl, e_InCombat; // is combat flag set?
|
||||||
@@ -176,6 +410,10 @@ static void __declspec(naked) anim_set_end_hack() {
|
|||||||
skip:
|
skip:
|
||||||
mov eax, animSet;
|
mov eax, animSet;
|
||||||
mov [eax][esi], ebx; // anim_set[].curr_anim = -1000
|
mov [eax][esi], ebx; // anim_set[].curr_anim = -1000
|
||||||
|
#ifndef NDEBUG
|
||||||
|
mov ecx, [esp + 0x2C - 0x1C + 4]; // current slot
|
||||||
|
call ClearDataAnimations;
|
||||||
|
#endif
|
||||||
retn;
|
retn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,8 +480,6 @@ skip:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ApplyAnimationsAtOncePatches(signed char aniMax) {
|
void ApplyAnimationsAtOncePatches(signed char aniMax) {
|
||||||
if (aniMax <= 32) return;
|
|
||||||
|
|
||||||
//allocate memory to store larger animation struct arrays
|
//allocate memory to store larger animation struct arrays
|
||||||
sf_anim_set.resize(aniMax + 1); // include a dummy
|
sf_anim_set.resize(aniMax + 1); // include a dummy
|
||||||
sf_sad.resize(aniMax + 1); // -8?
|
sf_sad.resize(aniMax + 1); // -8?
|
||||||
@@ -299,7 +535,8 @@ void ApplyAnimationsAtOncePatches(signed char aniMax) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Animations::init() {
|
void Animations::init() {
|
||||||
int animationLimit = IniReader::GetConfigInt("Misc", "AnimationsAtOnceLimit", 32);
|
animationLimit = IniReader::GetConfigInt("Misc", "AnimationsAtOnceLimit", 32);
|
||||||
|
if (animationLimit < 32) animationLimit = 32;
|
||||||
if (animationLimit > 32) {
|
if (animationLimit > 32) {
|
||||||
if (animationLimit > 127) {
|
if (animationLimit > 127) {
|
||||||
animationLimit = 127;
|
animationLimit = 127;
|
||||||
@@ -309,6 +546,26 @@ void Animations::init() {
|
|||||||
dlogr(" Done", DL_INIT);
|
dlogr(" Done", DL_INIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Improved implementation of animation registration
|
||||||
|
MakeCall(0x413E88, check_registry_hack, 2);
|
||||||
|
MakeCall(0x413DCE, anim_cleanup_hack, 1);
|
||||||
|
SafeWrite16(0x413DD4, 0x4478); // js 0x413E1A
|
||||||
|
MakeCall(0x413CE8, register_end_hack_begin, 1);
|
||||||
|
MakeJump(0x413D64, register_end_hack_end);
|
||||||
|
SafeWrite16(0x413D0B, 0xC689); // and dl, not 8 > mov esi, eax (keep offset to anim_set slot)
|
||||||
|
SafeWrite8(0x413D0D, CodeType::Nop);
|
||||||
|
|
||||||
|
// Implement a temporary lock on an animation slot after it is cleared by the register_clear_ function
|
||||||
|
// to prevent it from being used as a free slot when registering a nested animation
|
||||||
|
HookCall(0x413C97, register_clear_hook);
|
||||||
|
MakeCall(0x413BB7, anim_free_slot_hack);
|
||||||
|
MakeCall(0x4186CF, anim_stop_hack);
|
||||||
|
|
||||||
|
lockAnimSet.resize(animationLimit);
|
||||||
|
lockLimit = animationLimit / 4;
|
||||||
|
|
||||||
|
LoadGameHook::OnGameReset() += ClearAllLock;
|
||||||
|
|
||||||
// Fix for calling anim() functions in combat
|
// Fix for calling anim() functions in combat
|
||||||
MakeCall(0x415DE2, anim_set_end_hack, 1);
|
MakeCall(0x415DE2, anim_set_end_hack, 1);
|
||||||
SafeWrite8(0x415DEB, CodeType::JumpShort); // jz > jmp
|
SafeWrite8(0x415DEB, CodeType::JumpShort); // jz > jmp
|
||||||
|
|||||||
Reference in New Issue
Block a user