90 lines
3.8 KiB
C++
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);
|
|
}
|