diff --git a/zone/attack.cpp b/zone/attack.cpp index f71ccbf43..2dbe06c8b 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -2318,52 +2318,37 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy LogCombat("Fatal blow dealt by [{}] with [{}] damage, spell [{}], skill [{}]", ((killer_mob) ? (killer_mob->GetName()) : ("[nullptr]")), damage, spell, attack_skill); - Mob *oos = nullptr; - if (killer_mob) { - oos = killer_mob->GetOwnerOrSelf(); - std::string export_string = fmt::format( - "{} {} {} {}", - killer_mob->GetID(), - damage, - spell, - static_cast(attack_skill) - ); - if (parse->EventNPC(EVENT_DEATH, this, oos, export_string, 0) != 0) { - if (GetHP() < 0) { - SetHP(0); - } - return false; - } + Mob* oos = killer_mob ? killer_mob->GetOwnerOrSelf() : nullptr; - if ((killer_mob->IsClient() || killer_mob->IsBot()) && (spell != SPELL_UNKNOWN) && damage > 0) { - char val1[20] = { 0 }; + std::string export_string = fmt::format( + "{} {} {} {}", + killer_mob ? killer_mob->GetID() : 0, + damage, + spell, + static_cast(attack_skill) + ); - entity_list.MessageCloseString( - this, /* Sender */ - false, /* Skip Sender */ - RuleI(Range, DamageMessages), - Chat::NonMelee, /* 283 */ - HIT_NON_MELEE, /* %1 hit %2 for %3 points of non-melee damage. */ - killer_mob->GetCleanName(), /* Message1 */ - GetCleanName(), /* Message2 */ - ConvertArray(damage, val1) /* Message3 */ - ); + // todo: multiple attacks causes this to fire multiple times (DoAttackRounds, DoMain/OffHandAttackRounds, DoRiposte, spells?) + if (parse->EventNPC(EVENT_DEATH, this, oos, export_string, 0) != 0) { + if (GetHP() < 0) { + SetHP(0); } + return false; } - else { - std::string export_string = fmt::format( - "{} {} {} {}", - 0, - damage, - spell, - static_cast(attack_skill) + + if (killer_mob && (killer_mob->IsClient() || killer_mob->IsBot()) && (spell != SPELL_UNKNOWN) && damage > 0) { + char val1[20] = { 0 }; + + entity_list.MessageCloseString( + this, /* Sender */ + false, /* Skip Sender */ + RuleI(Range, DamageMessages), + Chat::NonMelee, /* 283 */ + HIT_NON_MELEE, /* %1 hit %2 for %3 points of non-melee damage. */ + killer_mob->GetCleanName(), /* Message1 */ + GetCleanName(), /* Message2 */ + ConvertArray(damage, val1) /* Message3 */ ); - if (parse->EventNPC(EVENT_DEATH, this, nullptr, export_string, 0) != 0) { - if (GetHP() < 0) { - SetHP(0); - } - return false; - } } if (IsEngaged()) { @@ -2752,35 +2737,12 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy entity_list.UpdateFindableNPCState(this, true); - std::string export_string = fmt::format( - "{} {} {} {}", - killer_mob ? killer_mob->GetID() : 0, - damage, - spell, - static_cast(attack_skill) - ); parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, export_string, 0); combat_record.Stop(); /* Zone controller process EVENT_DEATH_ZONE (Death events) */ - if (RuleB(Zone, UseZoneController)) { - auto controller = entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID); - if (controller && GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID) { - export_string = fmt::format( - "{} {} {} {} {} {:.2f} {:.2f} {:.2f} {:.2f}", - killer_mob ? killer_mob->GetID() : 0, - damage, - spell, - static_cast(attack_skill), - GetNPCTypeID(), - GetX(), - GetY(), - GetZ(), - GetHeading() - ); - parse->EventNPC(EVENT_DEATH_ZONE, controller, nullptr, export_string, 0); - } - } + std::vector args = { this }; + DispatchZoneControllerEvent(EVENT_DEATH_ZONE, oos, export_string, 0, &args); return true; } diff --git a/zone/embparser.cpp b/zone/embparser.cpp index 58e31e57d..663ffa6de 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -1599,6 +1599,7 @@ void PerlembParser::ExportEventVariables( break; } + case EVENT_DEATH_ZONE: case EVENT_DEATH: case EVENT_DEATH_COMPLETE: { Seperator sep(data); @@ -1606,6 +1607,18 @@ void PerlembParser::ExportEventVariables( ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]); ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]); ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]); + if (extra_pointers && !extra_pointers->empty()) + { + NPC* killed = std::any_cast(extra_pointers->at(0)); + if (killed) + { + ExportVar(package_name.c_str(), "killed_npc_id", killed->GetNPCTypeID()); + ExportVar(package_name.c_str(), "killed_x", killed->GetX()); + ExportVar(package_name.c_str(), "killed_y", killed->GetY()); + ExportVar(package_name.c_str(), "killed_z", killed->GetZ()); + ExportVar(package_name.c_str(), "killed_h", killed->GetHeading()); + } + } break; } case EVENT_DROP_ITEM: { @@ -1617,22 +1630,8 @@ void PerlembParser::ExportEventVariables( break; } case EVENT_SPAWN_ZONE: { - Seperator sep(data); - ExportVar(package_name.c_str(), "spawned_entity_id", sep.arg[0]); - ExportVar(package_name.c_str(), "spawned_npc_id", sep.arg[1]); - break; - } - case EVENT_DEATH_ZONE: { - Seperator sep(data); - ExportVar(package_name.c_str(), "killer_id", sep.arg[0]); - ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]); - ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]); - ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]); - ExportVar(package_name.c_str(), "killed_npc_id", sep.arg[4]); - ExportVar(package_name.c_str(), "killed_x", sep.arg[5]); - ExportVar(package_name.c_str(), "killed_y", sep.arg[6]); - ExportVar(package_name.c_str(), "killed_z", sep.arg[7]); - ExportVar(package_name.c_str(), "killed_h", sep.arg[8]); + ExportVar(package_name.c_str(), "spawned_entity_id", mob->GetID()); + ExportVar(package_name.c_str(), "spawned_npc_id", mob->GetNPCTypeID()); break; } case EVENT_USE_SKILL: { diff --git a/zone/entity.cpp b/zone/entity.cpp index beca9aa3b..cf13392fe 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -729,17 +729,7 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue) entity_list.ScanCloseMobs(npc->close_mobs, npc, true); /* Zone controller process EVENT_SPAWN_ZONE */ - if (RuleB(Zone, UseZoneController)) { - auto controller = entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID); - if (controller && npc->GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID){ - std::string export_string = fmt::format( - "{} {}", - npc->GetID(), - npc->GetNPCTypeID() - ); - parse->EventNPC(EVENT_SPAWN_ZONE, controller, nullptr, export_string, 0); - } - } + npc->DispatchZoneControllerEvent(EVENT_SPAWN_ZONE, npc, "", 0, nullptr); /** * Set whether NPC was spawned in or out of water diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index 32fb760a9..f33483e7c 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -194,12 +194,14 @@ LuaParser::LuaParser() { NPCArgumentDispatch[EVENT_TIMER] = handle_npc_timer; NPCArgumentDispatch[EVENT_DEATH] = handle_npc_death; NPCArgumentDispatch[EVENT_DEATH_COMPLETE] = handle_npc_death; + NPCArgumentDispatch[EVENT_DEATH_ZONE] = handle_npc_death; NPCArgumentDispatch[EVENT_CAST] = handle_npc_cast; NPCArgumentDispatch[EVENT_CAST_BEGIN] = handle_npc_cast; NPCArgumentDispatch[EVENT_FEIGN_DEATH] = handle_npc_single_client; NPCArgumentDispatch[EVENT_ENTER_AREA] = handle_npc_area; NPCArgumentDispatch[EVENT_LEAVE_AREA] = handle_npc_area; NPCArgumentDispatch[EVENT_LOOT_ZONE] = handle_npc_loot_zone; + NPCArgumentDispatch[EVENT_SPAWN_ZONE] = handle_npc_spawn_zone; PlayerArgumentDispatch[EVENT_SAY] = handle_player_say; PlayerArgumentDispatch[EVENT_ENVIRONMENTAL_DAMAGE] = handle_player_environmental_damage; diff --git a/zone/lua_parser_events.cpp b/zone/lua_parser_events.cpp index e4fa69b7f..11c4d2c55 100644 --- a/zone/lua_parser_events.cpp +++ b/zone/lua_parser_events.cpp @@ -189,9 +189,12 @@ void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, Seperator sep(data.c_str()); lua_pushinteger(L, std::stoi(sep.arg[0])); + lua_setfield(L, -2, "killer_id"); + + lua_pushinteger(L, std::stoi(sep.arg[1])); lua_setfield(L, -2, "damage"); - int spell_id = std::stoi(sep.arg[1]); + int spell_id = std::stoi(sep.arg[2]); if(IsValidSpell(spell_id)) { Lua_Spell l_spell(&spells[spell_id]); luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); @@ -204,8 +207,16 @@ void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, lua_setfield(L, -2, "spell"); } - lua_pushinteger(L, std::stoi(sep.arg[2])); + lua_pushinteger(L, std::stoi(sep.arg[3])); lua_setfield(L, -2, "skill_id"); + + if (extra_pointers && !extra_pointers->empty()) + { + Lua_NPC l_npc(std::any_cast(extra_pointers->at(0))); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); + l_npc_o.push(L); + lua_setfield(L, -2, "killed"); + } } void handle_npc_cast(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, @@ -255,6 +266,14 @@ void handle_npc_loot_zone(QuestInterface *parse, lua_State* L, NPC* npc, Mob *in lua_setfield(L, -2, "corpse"); } +void handle_npc_spawn_zone(QuestInterface* parse, lua_State* L, NPC* npc, Mob* init, std::string data, uint32 extra_data, + std::vector *extra_pointers) { + Lua_NPC l_npc(std::any_cast(init->CastToNPC())); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); + l_npc_o.push(L); + lua_setfield(L, -2, "other"); +} + //Player void handle_player_say(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { @@ -289,9 +308,12 @@ void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, st lua_setfield(L, -2, "other"); lua_pushinteger(L, std::stoi(sep.arg[1])); + lua_setfield(L, -2, "killer_id"); + + lua_pushinteger(L, std::stoi(sep.arg[2])); lua_setfield(L, -2, "damage"); - int spell_id = std::stoi(sep.arg[2]); + int spell_id = std::stoi(sep.arg[3]); if(IsValidSpell(spell_id)) { Lua_Spell l_spell(&spells[spell_id]); luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); @@ -304,7 +326,7 @@ void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, st lua_setfield(L, -2, "spell"); } - lua_pushinteger(L, std::stoi(sep.arg[3])); + lua_pushinteger(L, std::stoi(sep.arg[4])); lua_setfield(L, -2, "skill"); } diff --git a/zone/lua_parser_events.h b/zone/lua_parser_events.h index 124e97490..53010058a 100644 --- a/zone/lua_parser_events.h +++ b/zone/lua_parser_events.h @@ -43,6 +43,8 @@ void handle_npc_null(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, s std::vector *extra_pointers); void handle_npc_loot_zone(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers); +void handle_npc_spawn_zone(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, + std::vector *extra_pointers); //Player void handle_player_say(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, diff --git a/zone/npc.cpp b/zone/npc.cpp index cb1244288..bc3b5985f 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -3764,3 +3764,18 @@ int NPC::GetRolledItemCount(uint32 item_id) return rolled_count; } + +int NPC::DispatchZoneControllerEvent(QuestEventID evt, Mob* init, + const std::string& data, uint32 extra, std::vector* pointers) +{ + int ret = 0; + if (RuleB(Zone, UseZoneController) && GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID) + { + auto controller = entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID); + if (controller) + { + ret = parse->EventNPC(evt, controller, init, data, extra, pointers); + } + } + return ret; +} diff --git a/zone/npc.h b/zone/npc.h index 4aa09bf1a..fa70c3b88 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -27,6 +27,7 @@ #include "zonedump.h" #include "../common/loottable.h" +#include #include #include @@ -549,6 +550,9 @@ public: void ReloadSpells(); static LootDropEntries_Struct NewLootDropEntry(); + + int DispatchZoneControllerEvent(QuestEventID evt, Mob* init, const std::string& data, uint32 extra, std::vector* pointers); + protected: const NPCType* NPCTypedata;