void StickyCombatModes::SetCombatModeHook(API::CNWSCreature* thisPtr, uint8_t newMode, bool forceNewMode) | |
{ | |
if (thisPtr->m_bPlayerCharacter) | |
{ | |
if (g_plugin->ShouldSkip(thisPtr, newMode)) | |
{ | |
return; | |
} | |
const uint8_t currentMode = thisPtr->m_nCombatMode; | |
if (g_plugin->m_dispatchMessages && currentMode != newMode) | |
{ | |
// ToggleMode gets called with modes which are +1 to what the script constants expect. | |
// It then calls SetCombatMode with the 'proper' modes. | |
// To simplify things, we just correct the mode we dispatch here, so the game events | |
// receive what they expect to. | |
auto messaging = g_plugin->GetServices()->m_messaging.get(); | |
if (currentMode != 0) | |
{ | |
messaging->BroadcastMessage("NWNX_EVENT_PUSH_EVENT_DATA", { "MODE", std::to_string(currentMode + 1) } ); | |
messaging->BroadcastMessage("NWNX_EVENT_SIGNAL_EVENT", { "NWNX_ON_MODE_OFF", ObjectIDToString(thisPtr->m_idSelf) }); | |
} | |
if (newMode != 0) | |
{ | |
messaging->BroadcastMessage("NWNX_EVENT_PUSH_EVENT_DATA", { "MODE", std::to_string(newMode + 1) } ); | |
messaging->BroadcastMessage("NWNX_EVENT_SIGNAL_EVENT", { "NWNX_ON_MODE_ON", ObjectIDToString(thisPtr->m_idSelf) }); | |
} | |
} | |
} | |
return g_setCombatModeHook->CallOriginal<void>(thisPtr, newMode, forceNewMode); | |
} | |
MI::TMI(const Plugin::CreateParams& params) | |
: Plugin(params) | |
{ | |
using namespace NWNXLib::Services; | |
GetServices()->m_events->RegisterEvent("GET_TMI", [this](Events::ArgumentStack&&) | |
{ | |
Events::ArgumentStack stack; | |
Events::InsertArgument(stack, GetTMI()); | |
return stack; | |
}); | |
GetServices()->m_events->RegisterEvent("SET_TMI", [this](Events::ArgumentStack&& args) | |
{ | |
SetTMI(Events::ExtractArgument<int32_t>(args)); | |
return Events::ArgumentStack(); | |
}); | |
SetTMI(GetTMI() * GetServices()->m_config->Get<int32_t>("MULTIPLIER", 1)); | |
} | |
TMI::~TMI() | |
{ | |
} | |
int32_t TMI::GetTMI() | |
{ | |
int32_t tmi = 0; | |
memcpy(&tmi, reinterpret_cast<int32_t*>(TMI_ADDR), 4); | |
return tmi; | |
} | |
void TMI::SetTMI(const int32_t newTmi) | |
{ | |
if (GetServices()->m_patching->PatchExists(TMI_ADDR)) | |
{ | |
GetServices()->m_patching->ClearPatch(TMI_ADDR); | |
} | |
GetServices()->m_patching->PatchWithValue(TMI_ADDR, newTmi); | |
} | |
//The patching service is very flexible. You can do stuff like ... | |
patcher->PatchWithCall(0x0804BBEE, 0x0804BBFE - 0x0804BBEE, &SleepTiming); NWNX_EXPECT_VERSION(8109); | |
//Or ... | |
patcher->PatchWithNoop(0x08096164, 0x08096169 - 0x08096164); NWNX_EXPECT_VERSION(8109); | |
GetServices()->m_patching->PatchWithInstructionsTrampoline(0x0807340D, 0x08073418 - 0x0807340D, | |
PushRegMemByteInstruction(Register::EBP, 16), // pAreaObject | |
PushRegMemByteInstruction(Register::EBP, 12), // pPlayer | |
CallRelInstruction(&ClientToPlayerID), | |
AddRegImmByteInstruction(Register::ESP, 4), | |
PushRegInstruction(Register::EAX), | |
PushRegMemByteInstruction(Register::EBP, 8), // this | |
CallRelInstruction(&WriteLastName) | |
); NWNX_EXPECT_VERSION(8109); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment