From baf74d0bdd26e408b61f41226cae6c58563b71f8 Mon Sep 17 00:00:00 2001 From: Emagi Date: Sat, 2 Aug 2025 06:35:03 -0400 Subject: [PATCH] Added LUA Function to adjust hate position up or down: AdjustHatePosition(Caster, NPC, Increase) increase is boolean, true to increase, false to decrease --- source/WorldServer/LuaFunctions.cpp | 26 +++++++++++++++++ source/WorldServer/LuaFunctions.h | 1 + source/WorldServer/LuaInterface.cpp | 1 + source/WorldServer/NPC_AI.cpp | 44 +++++++++++++++++++++++++++++ source/WorldServer/NPC_AI.h | 2 ++ source/WorldServer/zoneserver.cpp | 2 +- 6 files changed, 75 insertions(+), 1 deletion(-) diff --git a/source/WorldServer/LuaFunctions.cpp b/source/WorldServer/LuaFunctions.cpp index 890dd18..a03ce19 100644 --- a/source/WorldServer/LuaFunctions.cpp +++ b/source/WorldServer/LuaFunctions.cpp @@ -14860,4 +14860,30 @@ int EQ2Emu_lua_GetRaid(lua_State* state) { } return 1; +} + + +int EQ2Emu_lua_AdjustHatePosition(lua_State* state) { + Spawn* entity = lua_interface->GetSpawn(state); + Spawn* npc = lua_interface->GetSpawn(state, 2); + bool increase = lua_interface->GetBooleanValue(state, 3); + + LuaSpell* luaspell = lua_interface->GetCurrentSpell(state); + if(luaspell && luaspell->resisted) { + return 0; + } + + if (luaspell) { + for (int32 id : luaspell->GetTargets()) { + Spawn* spawn = luaspell->zone->GetSpawnByID(id); + if (spawn && npc->IsNPC() && spawn->Alive()) { + ((NPC*)npc)->Brain()->AdjustHatePosition(entity->GetID(), increase); + } + } + } + else if (npc && npc->IsNPC() && entity->Alive()) { + ((NPC*)npc)->Brain()->AdjustHatePosition(entity->GetID(), increase); + } + lua_interface->ResetFunctionStack(state); + return 0; } \ No newline at end of file diff --git a/source/WorldServer/LuaFunctions.h b/source/WorldServer/LuaFunctions.h index 3d480ec..2894669 100644 --- a/source/WorldServer/LuaFunctions.h +++ b/source/WorldServer/LuaFunctions.h @@ -697,4 +697,5 @@ int EQ2Emu_lua_AttackAllowed(lua_State* state); int EQ2Emu_lua_IsInRaid(lua_State* state); int EQ2Emu_lua_InSameRaid(lua_State* state); int EQ2Emu_lua_GetRaid(lua_State* state); +int EQ2Emu_lua_AdjustHatePosition(lua_State* state); #endif \ No newline at end of file diff --git a/source/WorldServer/LuaInterface.cpp b/source/WorldServer/LuaInterface.cpp index 2e09737..62df51f 100644 --- a/source/WorldServer/LuaInterface.cpp +++ b/source/WorldServer/LuaInterface.cpp @@ -1837,6 +1837,7 @@ void LuaInterface::RegisterFunctions(lua_State* state) { lua_register(state,"IsInRaid", EQ2Emu_lua_IsInRaid); lua_register(state,"InSameRaid", EQ2Emu_lua_InSameRaid); lua_register(state,"GetRaid", EQ2Emu_lua_GetRaid); + lua_register(state,"AdjustHatePosition", EQ2Emu_lua_AdjustHatePosition); } void LuaInterface::LogError(const char* error, ...) { diff --git a/source/WorldServer/NPC_AI.cpp b/source/WorldServer/NPC_AI.cpp index 1e41f48..3e84ec2 100644 --- a/source/WorldServer/NPC_AI.cpp +++ b/source/WorldServer/NPC_AI.cpp @@ -271,6 +271,50 @@ void Brain::AddHate(Entity* entity, sint32 hate) { } } +bool Brain::AdjustHatePosition(int32 id, bool increase) { + // Lock the hate list, we are altering the list so use a write lock + MHateList.writelock(__FUNCTION__, __LINE__); + + auto it = m_hatelist.find(id); + if (it == m_hatelist.end()) { + MHateList.releasewritelock(__FUNCTION__, __LINE__); + return false; + } + + // Build a vector of (id, hate), sorted highest→lowest hate + std::vector> sorted; + sorted.reserve(m_hatelist.size()); + for (auto &kv : m_hatelist) + sorted.emplace_back(kv.first, kv.second); + std::sort(sorted.begin(), sorted.end(), + [](auto &a, auto &b){ return a.second > b.second; }); + + // Locate our position + auto posIt = std::find_if(sorted.begin(), sorted.end(), + [&](auto &p){ return p.first == id; }); + size_t idx = std::distance(sorted.begin(), posIt); + + if (increase) { + if (idx == 0) { + MHateList.releasewritelock(__FUNCTION__, __LINE__); + return false; // no higher to go + } + sint32 aboveHate = sorted[idx - 1].second; + it->second = aboveHate + 1; // move up + } + else { + if (idx + 1 >= sorted.size()) { + MHateList.releasewritelock(__FUNCTION__, __LINE__); + return false; // already at bottom + } + sint32 belowHate = sorted[idx + 1].second; + it->second = belowHate - 1; // move lower + } + + MHateList.releasewritelock(__FUNCTION__, __LINE__); + return true; +} + void Brain::ClearHate(bool lockSpawnList) { // Lock the hate list, we are altering the list so use a write lock MHateList.writelock(__FUNCTION__, __LINE__); diff --git a/source/WorldServer/NPC_AI.h b/source/WorldServer/NPC_AI.h index 40567ea..c4aaa5c 100644 --- a/source/WorldServer/NPC_AI.h +++ b/source/WorldServer/NPC_AI.h @@ -59,6 +59,8 @@ public: /// The entity we are adding to this NPC's hate list /// The amount of hate to add virtual void AddHate(Entity* entity, sint32 hate); + virtual bool AdjustHatePosition(int32 id, bool increase); + /// Completely clears the hate list for this npc void ClearHate(bool lockSpawnList = false); /// Removes the given entity from this NPC's hate list diff --git a/source/WorldServer/zoneserver.cpp b/source/WorldServer/zoneserver.cpp index e9c2f29..05b14ee 100644 --- a/source/WorldServer/zoneserver.cpp +++ b/source/WorldServer/zoneserver.cpp @@ -5170,7 +5170,7 @@ void ZoneServer::KillSpawn(bool spawnListLocked, Spawn* dead, Spawn* killer, boo //Check if caster is alive after death proc called, incase of deathsave if (dead->Alive()) return; - + RemoveSpellTimersFromSpawn(dead, true, !dead->IsPlayer(), true, !isSpell); ((Entity*)dead)->IsCasting(false);