diff --git a/zone/attack.cpp b/zone/attack.cpp index 8136fe5e0..c218a3906 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3820,6 +3820,98 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons //final damage has been determined. SetHP(int64(GetHP() - damage)); + const auto has_bot_given_event = parse->BotHasQuestSub(EVENT_DAMAGE_GIVEN); + + const auto has_bot_taken_event = parse->BotHasQuestSub(EVENT_DAMAGE_TAKEN); + + const auto has_npc_given_event = ( + ( + IsNPC() && + parse->HasQuestSub(CastToNPC()->GetNPCTypeID(), EVENT_DAMAGE_GIVEN) + ) || + ( + attacker->IsNPC() && + parse->HasQuestSub(attacker->CastToNPC()->GetNPCTypeID(), EVENT_DAMAGE_GIVEN) + ) + ); + + const auto has_npc_taken_event = ( + ( + IsNPC() && + parse->HasQuestSub(CastToNPC()->GetNPCTypeID(), EVENT_DAMAGE_TAKEN) + ) || + ( + attacker->IsNPC() && + parse->HasQuestSub(attacker->CastToNPC()->GetNPCTypeID(), EVENT_DAMAGE_TAKEN) + ) + ); + + const auto has_player_given_event = parse->PlayerHasQuestSub(EVENT_DAMAGE_GIVEN); + + const auto has_player_taken_event = parse->PlayerHasQuestSub(EVENT_DAMAGE_TAKEN); + + const auto has_given_event = ( + has_bot_given_event || + has_npc_given_event || + has_player_given_event + ); + + const auto has_taken_event = ( + has_bot_taken_event || + has_npc_taken_event || + has_player_taken_event + ); + + std::vector args; + + if (has_taken_event) { + const auto export_string = fmt::format( + "{} {} {} {} {} {} {} {} {}", + attacker ? attacker->GetID() : 0, + damage, + spell_id, + static_cast(skill_used), + FromDamageShield ? 1 : 0, + avoidable ? 1 : 0, + buffslot, + iBuffTic ? 1 : 0, + static_cast(special) + ); + + if (IsBot() && has_bot_taken_event) { + parse->EventBot(EVENT_DAMAGE_TAKEN, CastToBot(), attacker ? attacker : nullptr, export_string, 0); + } else if (IsClient() && has_player_taken_event) { + args.push_back(attacker ? attacker : nullptr); + parse->EventPlayer(EVENT_DAMAGE_TAKEN, CastToClient(), export_string, 0, &args); + } else if (IsNPC() && has_npc_taken_event) { + parse->EventNPC(EVENT_DAMAGE_TAKEN, CastToNPC(), attacker ? attacker : nullptr, export_string, 0); + } + } + + if (has_given_event && attacker) { + const auto export_string = fmt::format( + "{} {} {} {} {} {} {} {} {}", + GetID(), + damage, + spell_id, + static_cast(skill_used), + FromDamageShield ? 1 : 0, + avoidable ? 1 : 0, + buffslot, + iBuffTic ? 1 : 0, + static_cast(special) + ); + + if (attacker->IsBot() && has_bot_given_event) { + parse->EventBot(EVENT_DAMAGE_GIVEN, attacker->CastToBot(), this, export_string, 0); + } else if (attacker->IsClient() && has_player_given_event) { + args.push_back(this); + parse->EventPlayer(EVENT_DAMAGE_GIVEN, attacker->CastToClient(), export_string, 0, &args); + } else if (attacker->IsNPC() && has_npc_given_event) { + parse->EventNPC(EVENT_DAMAGE_GIVEN, attacker->CastToNPC(), this, export_string, 0); + } + } + if (HasDied()) { bool IsSaved = false; diff --git a/zone/embparser.cpp b/zone/embparser.cpp index 2d8bf4bf4..af41b61c8 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -171,6 +171,8 @@ const char *QuestEventSubroutines[_LargestEventID] = { "EVENT_AUGMENT_REMOVE_CLIENT", "EVENT_EQUIP_ITEM_BOT", "EVENT_UNEQUIP_ITEM_BOT", + "EVENT_DAMAGE_GIVEN", + "EVENT_DAMAGE_TAKEN", // Add new events before these or Lua crashes "EVENT_SPELL_EFFECT_BOT", "EVENT_SPELL_EFFECT_BUFF_TIC_BOT" @@ -2031,6 +2033,21 @@ void PerlembParser::ExportEventVariables( break; } + case EVENT_DAMAGE_GIVEN: + case EVENT_DAMAGE_TAKEN:{ + Seperator sep(data); + ExportVar(package_name.c_str(), "entity_id", sep.arg[0]); + ExportVar(package_name.c_str(), "damage", sep.arg[1]); + ExportVar(package_name.c_str(), "spell_id", sep.arg[2]); + ExportVar(package_name.c_str(), "skill_id", sep.arg[3]); + ExportVar(package_name.c_str(), "is_damage_shield", sep.arg[4]); + ExportVar(package_name.c_str(), "is_avoidable", sep.arg[5]); + ExportVar(package_name.c_str(), "buff_slot", sep.arg[6]); + ExportVar(package_name.c_str(), "is_buff_tic", sep.arg[7]); + ExportVar(package_name.c_str(), "special_attack", sep.arg[8]); + break; + } + default: { break; } diff --git a/zone/event_codes.h b/zone/event_codes.h index b48838d19..0d1e1243f 100644 --- a/zone/event_codes.h +++ b/zone/event_codes.h @@ -116,6 +116,8 @@ typedef enum { EVENT_AUGMENT_REMOVE_CLIENT, EVENT_EQUIP_ITEM_BOT, EVENT_UNEQUIP_ITEM_BOT, + EVENT_DAMAGE_GIVEN, + EVENT_DAMAGE_TAKEN, // Add new events before these or Lua crashes EVENT_SPELL_EFFECT_BOT, EVENT_SPELL_EFFECT_BUFF_TIC_BOT, diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index 541996e56..d44fc5f9e 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -158,6 +158,8 @@ const char *LuaEvents[_LargestEventID] = { "event_augment_remove_client", "event_equip_item_bot", "event_unequip_item_bot", + "event_damage_given", + "event_damage_taken" }; extern Zone *zone; @@ -213,6 +215,8 @@ LuaParser::LuaParser() { NPCArgumentDispatch[EVENT_SPAWN_ZONE] = handle_npc_spawn_zone; NPCArgumentDispatch[EVENT_PAYLOAD] = handle_npc_payload; NPCArgumentDispatch[EVENT_DESPAWN_ZONE] = handle_npc_despawn_zone; + NPCArgumentDispatch[EVENT_DAMAGE_GIVEN] = handle_npc_damage; + NPCArgumentDispatch[EVENT_DAMAGE_TAKEN] = handle_npc_damage; PlayerArgumentDispatch[EVENT_SAY] = handle_player_say; PlayerArgumentDispatch[EVENT_ENVIRONMENTAL_DAMAGE] = handle_player_environmental_damage; @@ -273,6 +277,8 @@ LuaParser::LuaParser() { PlayerArgumentDispatch[EVENT_BOT_CREATE] = handle_player_bot_create; PlayerArgumentDispatch[EVENT_AUGMENT_INSERT_CLIENT] = handle_player_augment_insert; PlayerArgumentDispatch[EVENT_AUGMENT_REMOVE_CLIENT] = handle_player_augment_remove; + PlayerArgumentDispatch[EVENT_DAMAGE_GIVEN] = handle_player_damage; + PlayerArgumentDispatch[EVENT_DAMAGE_TAKEN] = handle_player_damage; ItemArgumentDispatch[EVENT_ITEM_CLICK] = handle_item_click; ItemArgumentDispatch[EVENT_ITEM_CLICK_CAST] = handle_item_click; @@ -312,6 +318,8 @@ LuaParser::LuaParser() { BotArgumentDispatch[EVENT_PAYLOAD] = handle_bot_payload; BotArgumentDispatch[EVENT_EQUIP_ITEM_BOT] = handle_bot_equip_item; BotArgumentDispatch[EVENT_UNEQUIP_ITEM_BOT] = handle_bot_equip_item; + BotArgumentDispatch[EVENT_DAMAGE_GIVEN] = handle_bot_damage; + BotArgumentDispatch[EVENT_DAMAGE_TAKEN] = handle_bot_damage; #endif L = nullptr; diff --git a/zone/lua_parser_events.cpp b/zone/lua_parser_events.cpp index 31bdc76dc..9f59a16cb 100644 --- a/zone/lua_parser_events.cpp +++ b/zone/lua_parser_events.cpp @@ -453,6 +453,50 @@ void handle_npc_despawn_zone( lua_setfield(L, -2, "other"); } +void handle_npc_damage( + QuestInterface *parse, + lua_State* L, + NPC* npc, + Mob* init, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + Seperator sep(data.c_str()); + + lua_pushnumber(L, std::stoul(sep.arg[0])); + lua_setfield(L, -2, "entity_id"); + + lua_pushnumber(L, std::stoll(sep.arg[1])); + lua_setfield(L, -2, "damage"); + + lua_pushnumber(L, std::stoi(sep.arg[2])); + lua_setfield(L, -2, "spell_id"); + + lua_pushnumber(L, std::stoi(sep.arg[3])); + lua_setfield(L, -2, "skill_id"); + + lua_pushboolean(L, std::stoi(sep.arg[4]) == 0 ? false : true); + lua_setfield(L, -2, "is_damage_shield"); + + lua_pushboolean(L, std::stoi(sep.arg[5]) == 0 ? false : true); + lua_setfield(L, -2, "is_avoidable"); + + lua_pushnumber(L, std::stoi(sep.arg[6])); + lua_setfield(L, -2, "buff_slot"); + + lua_pushboolean(L, std::stoi(sep.arg[7]) == 0 ? false : true); + lua_setfield(L, -2, "is_buff_tic"); + + lua_pushnumber(L, std::stoi(sep.arg[8])); + lua_setfield(L, -2, "special_attack"); + + Lua_Mob l_mob(init); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); + l_mob_o.push(L); + lua_setfield(L, -2, "other"); +} + // Player void handle_player_say( QuestInterface *parse, @@ -1168,6 +1212,51 @@ void handle_player_bot_create( lua_setfield(L, -2, "bot_gender"); } +void handle_player_damage( + QuestInterface *parse, + lua_State* L, + Client* client, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + Seperator sep(data.c_str()); + + lua_pushnumber(L, std::stoul(sep.arg[0])); + lua_setfield(L, -2, "entity_id"); + + lua_pushnumber(L, std::stoll(sep.arg[1])); + lua_setfield(L, -2, "damage"); + + lua_pushnumber(L, std::stoi(sep.arg[2])); + lua_setfield(L, -2, "spell_id"); + + lua_pushnumber(L, std::stoi(sep.arg[3])); + lua_setfield(L, -2, "skill_id"); + + lua_pushboolean(L, std::stoi(sep.arg[4]) == 0 ? false : true); + lua_setfield(L, -2, "is_damage_shield"); + + lua_pushboolean(L, std::stoi(sep.arg[5]) == 0 ? false : true); + lua_setfield(L, -2, "is_avoidable"); + + lua_pushnumber(L, std::stoi(sep.arg[6])); + lua_setfield(L, -2, "buff_slot"); + + lua_pushboolean(L, std::stoi(sep.arg[7]) == 0 ? false : true); + lua_setfield(L, -2, "is_buff_tic"); + + lua_pushnumber(L, std::stoi(sep.arg[8])); + lua_setfield(L, -2, "special_attack"); + + if (extra_pointers && extra_pointers->size() >= 1) { + Lua_Mob l_mob(std::any_cast(extra_pointers->at(1))); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); + l_mob_o.push(L); + lua_setfield(L, -2, "other"); + } +} + // Item void handle_item_click( QuestInterface *parse, @@ -1977,7 +2066,7 @@ void handle_bot_equip_item( lua_setfield(L, -2, "item"); } -void handle_bot_unequip_item( +void handle_bot_damage( QuestInterface *parse, lua_State* L, Bot* bot, @@ -1986,22 +2075,39 @@ void handle_bot_unequip_item( uint32 extra_data, std::vector *extra_pointers ) { - lua_pushnumber(L, extra_data); - lua_setfield(L, -2, "item_id"); - Seperator sep(data.c_str()); - lua_pushnumber(L, std::stoi(sep.arg[0])); - lua_setfield(L, -2, "item_quantity"); + lua_pushnumber(L, std::stoul(sep.arg[0])); + lua_setfield(L, -2, "entity_id"); - lua_pushnumber(L, std::stoi(sep.arg[1])); - lua_setfield(L, -2, "slot_id"); + lua_pushnumber(L, std::stoll(sep.arg[1])); + lua_setfield(L, -2, "damage"); - Lua_ItemInst l_item(extra_data); - luabind::adl::object l_item_o = luabind::adl::object(L, l_item); - l_item_o.push(L); - lua_setfield(L, -2, "item"); + lua_pushnumber(L, std::stoi(sep.arg[2])); + lua_setfield(L, -2, "spell_id"); + + lua_pushnumber(L, std::stoi(sep.arg[3])); + lua_setfield(L, -2, "skill_id"); + + lua_pushboolean(L, std::stoi(sep.arg[4]) == 0 ? false : true); + lua_setfield(L, -2, "is_damage_shield"); + + lua_pushboolean(L, std::stoi(sep.arg[5]) == 0 ? false : true); + lua_setfield(L, -2, "is_avoidable"); + + lua_pushnumber(L, std::stoi(sep.arg[6])); + lua_setfield(L, -2, "buff_slot"); + + lua_pushboolean(L, std::stoi(sep.arg[7]) == 0 ? false : true); + lua_setfield(L, -2, "is_buff_tic"); + + lua_pushnumber(L, std::stoi(sep.arg[8])); + lua_setfield(L, -2, "special_attack"); + + Lua_Mob l_mob(init); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); + l_mob_o.push(L); + lua_setfield(L, -2, "other"); } - #endif diff --git a/zone/lua_parser_events.h b/zone/lua_parser_events.h index 8decb37eb..3533ef011 100644 --- a/zone/lua_parser_events.h +++ b/zone/lua_parser_events.h @@ -210,6 +210,16 @@ void handle_npc_despawn_zone( std::vector *extra_pointers ); +void handle_npc_damage( + 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, @@ -652,6 +662,14 @@ void handle_player_augment_remove( std::vector *extra_pointers ); +void handle_player_damage( + QuestInterface *parse, + lua_State* L, + Client* client, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); // Item void handle_item_click( @@ -965,7 +983,7 @@ void handle_bot_equip_item( std::vector *extra_pointers ); -void handle_bot_unequip_item( +void handle_bot_damage( QuestInterface *parse, lua_State* L, Bot* bot,