Files
rem-essentials-pub/third_party/flsharp/src/weapon_anim.cpp
T

90 lines
3.8 KiB
C++

#include "weapon_anim.h"
#include "utils.h"
#include "fl_func.h"
#include "logger.h"
DWORD setModelCallAddr = 0;
FL_FUNC(bool EngAnimation::SetModel(PDWORD unk, const EngModel* model), setModelCallAddr);
// There exist many animations for the weapon models in Freelancer (e.g. barrels rotating or moving back and forth while shooting).
// However, despite all weapon animations already being defined correctly in the ini files, there is a bug in engbase.dll that prevents these animations from playing properly.
// In vanilla FL the internal weapon animation structs have their model set to their actual gun, but this way they don't work.
// The fix is to set the animation structs model to its parent (the ship hull). With this the animations will play correctly.
bool EngAnimation::SetModel_Hook(PDWORD unk, const EngModel* model)
{
const EngModel* currentModel = model;
// Find the parent (ship hull) of the weapon model.
while (currentModel)
{
// If the parent has been found, ensure this is used as the model for the animation, but keep checking for greater parents.
if (currentModel->type == EngModelType::Object)
{
model = currentModel;
}
currentModel = currentModel->parent;
}
// Call original function.
return SetModel(unk, model);
}
// This hook allows for e.g. the Cruiser forward gun animation to work without having to modify the model.
// Normally in FL the gun .cmp files have their gun animation included.
// However, the cruiser gun model is part of the Cruiser ship model itself, and thus the animation is also in the ship model.
// In vanilla FL it's not possible to call ship animations when firing a gun.
// This hook allows an animation to be played on the parent of the gun if there is a leading underscore in the animation name (_).
int IAnimation2::Open_Hook(LPCSTR animationScript, int scriptIndex, const CAttachedEquip &equip)
{
// If the animation script has a leading underscore, open the animation on the parent of the equipment.
if (animationScript && animationScript[0] == '_')
{
// Remove the leading underscore.
// One could argue removing a leading underscore like this is bad practice
// since the address is no longer DWORD-aligned.
// However, these string addresses aren't DWORD-aligned out of the box, so it doesn't matter.
++animationScript;
if (CObject* parent = equip.parent)
{
// Open the animation on the parent.
return Open(parent->get_archetype()->scriptIndex, parent->engineInstance, animationScript);
}
}
// Open the animation on the attached equipment (normal routine).
return Open(scriptIndex, equip.GetRootIndex(), animationScript);
}
// Fixes the weapon animations and allows weapons to play ship animations (e.g. wings).
void InitWeaponAnimFix()
{
#define SET_MODEL_FUNC_FILE_OFFSET_ENGBASE 0xADC0
#define SET_MODEL_CALL_FILE_OFFSET_ENGBASE 0xB83F
#define GET_ROOT_INDEX_CALL_ADDR 0x52C8AF
#define PUSH_ZERO_ADDR 0x52C8BF
#define ANIM_OPEN_CALL_ADDR 0x52C8C2
DWORD engbaseHandle = (DWORD) GetModuleHandle("engbase.dll");
if (engbaseHandle)
{
setModelCallAddr = engbaseHandle + SET_MODEL_FUNC_FILE_OFFSET_ENGBASE;
Hook(engbaseHandle + SET_MODEL_CALL_FILE_OFFSET_ENGBASE, &EngAnimation::SetModel_Hook, 5);
}
else
{
Logger::PrintModuleError("InitWeaponAnimFix", "engbase.dll");
}
// Setup for IAnimation2::Open hook
Patch<WORD>(GET_ROOT_INDEX_CALL_ADDR, 0x5551); // Replace GetRootIndex call with push ecx + push ebx
Nop(GET_ROOT_INDEX_CALL_ADDR + 2, 4);
Nop(PUSH_ZERO_ADDR, 2); // Nop out two zero pushes
Nop(ANIM_OPEN_CALL_ADDR, 1); // Nop another instruction
Hook(ANIM_OPEN_CALL_ADDR + 1, &IAnimation2::Open_Hook, 5);
}