diff --git a/zone/bot.cpp b/zone/bot.cpp index de599718d..8016d4542 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -1209,7 +1209,7 @@ void Bot::GenerateAppearance() { if (GetRace() == BARBARIAN) // Barbarian w/Tatoo { iFace = zone->random.Int(0, 79); - } + } else { iFace = zone->random.Int(0, 7); @@ -5142,7 +5142,7 @@ void Bot::PerformTradeWithClient(int16 begin_slot_id, int16 end_slot_id, Client* insts[i - EQ::invslot::TRADE_BEGIN] = user_inv.GetItem(i); client->DeleteItemInInventory(i); } - + // copy to be filtered by task updates, null trade slots preserved for quest event arg std::vector items(insts, insts + std::size(insts)); @@ -6659,7 +6659,7 @@ float Bot::GetActSpellRange(uint16 spell_id, float range) { int32 Bot::GetActSpellDuration(uint16 spell_id, int32 duration) { int increase = 100; increase += GetFocusEffect(focusSpellDuration, spell_id); - int64 tic_inc = 0; + int64 tic_inc = 0; tic_inc = GetFocusEffect(focusSpellDurByTic, spell_id); if(IsBeneficialSpell(spell_id)) { @@ -6758,7 +6758,7 @@ bool Bot::CastSpell( (IsAmnesiad() && IsDiscipline(spell_id)) ) { LogSpellsModerate("[Bot::CastSpell] Spell casting canceled: not able to cast now. Valid? [{}] casting [{}] waiting? [{}] spellend? [{}] stunned? [{}] feared? [{}] mezed? [{}] silenced? [{}]", - IsValidSpell(spell_id), casting_spell_id, delaytimer, spellend_timer.Enabled(), IsStunned(), IsFeared(), IsMezzed(), IsSilenced() + IsValidSpell(spell_id), casting_spell_id, delaytimer, spellend_timer.Enabled(), IsStunned(), IsFeared(), IsMezzed(), IsSilenced() ); if (IsSilenced() && !IsDiscipline(spell_id)) { MessageString(Chat::White, SILENCED_STRING); @@ -8762,6 +8762,8 @@ void EntityList::AddBot(Bot *new_bot, bool send_spawn_packet, bool dont_queue) { } parse->EventBot(EVENT_SPAWN, new_bot, nullptr, "", 0); + + new_bot->DispatchZoneControllerEvent(EVENT_SPAWN_ZONE, new_bot, "", 0, nullptr); } bot_list.push_back(new_bot); @@ -9969,8 +9971,8 @@ std::string Bot::GetHPString(int8 min_hp, int8 max_hp) return hp_string; } -void Bot::SetBotArcherySetting(bool bot_archer_setting, bool save) -{ +void Bot::SetBotArcherySetting(bool bot_archer_setting, bool save) +{ m_bot_archery_setting = bot_archer_setting; if (save) { if (!database.botdb.SaveBotArcherSetting(GetBotID(), bot_archer_setting)) { diff --git a/zone/embparser.cpp b/zone/embparser.cpp index 30994bf1a..35ce029da 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -166,6 +166,8 @@ const char *QuestEventSubroutines[_LargestEventID] = { "EVENT_PAYLOAD", "EVENT_LEVEL_DOWN", "EVENT_GM_COMMAND", + "EVENT_DESPAWN", + "EVENT_DESPAWN_ZONE", #ifdef BOTS "EVENT_SPELL_EFFECT_BOT", "EVENT_SPELL_EFFECT_BUFF_TIC_BOT", @@ -1838,7 +1840,18 @@ void PerlembParser::ExportEventVariables( NPC* killed = std::any_cast(extra_pointers->at(1)); if (killed) { - ExportVar(package_name.c_str(), "killed_npc_id", killed->GetNPCTypeID()); + ExportVar(package_name.c_str(), "killed_entity_id", killed->GetID()); + + if (killed->IsNPC()) { + ExportVar(package_name.c_str(), "killed_bot_id", 0); + ExportVar(package_name.c_str(), "killed_npc_id", killed->GetNPCTypeID()); +#ifdef BOTS + } else if (killed->IsBot()) { + ExportVar(package_name.c_str(), "killed_bot_id", killed->CastToBot()->GetBotID()); + ExportVar(package_name.c_str(), "killed_npc_id", 0); +#endif + } + 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()); @@ -1859,7 +1872,17 @@ void PerlembParser::ExportEventVariables( case EVENT_SPAWN_ZONE: { ExportVar(package_name.c_str(), "spawned_entity_id", mob->GetID()); - ExportVar(package_name.c_str(), "spawned_npc_id", mob->GetNPCTypeID()); + + if (mob->IsNPC()) { + ExportVar(package_name.c_str(), "spawned_bot_id", 0); + ExportVar(package_name.c_str(), "spawned_npc_id", mob->GetNPCTypeID()); +#ifdef BOTS + } else if (mob->IsBot()) { + ExportVar(package_name.c_str(), "spawned_bot_id", mob->CastToBot()->GetBotID()); + ExportVar(package_name.c_str(), "spawned_npc_id", 0); +#endif + } + break; } @@ -2013,6 +2036,22 @@ void PerlembParser::ExportEventVariables( break; } + case EVENT_DESPAWN_ZONE: { + ExportVar(package_name.c_str(), "despawned_entity_id", mob->GetID()); + + if (mob->IsNPC()) { + ExportVar(package_name.c_str(), "despawned_bot_id", 0); + ExportVar(package_name.c_str(), "despawned_npc_id", mob->GetNPCTypeID()); +#ifdef BOTS + } else if (mob->IsBot()) { + ExportVar(package_name.c_str(), "despawned_bot_id", mob->CastToBot()->GetBotID()); + ExportVar(package_name.c_str(), "despawned_npc_id", 0); +#endif + } + + break; + } + default: { break; } diff --git a/zone/event_codes.h b/zone/event_codes.h index af576cdda..d525306f6 100644 --- a/zone/event_codes.h +++ b/zone/event_codes.h @@ -109,6 +109,8 @@ typedef enum { EVENT_PAYLOAD, EVENT_LEVEL_DOWN, EVENT_GM_COMMAND, + EVENT_DESPAWN, + EVENT_DESPAWN_ZONE, #ifdef BOTS EVENT_SPELL_EFFECT_BOT, EVENT_SPELL_EFFECT_BUFF_TIC_BOT, diff --git a/zone/lua_bot.cpp b/zone/lua_bot.cpp index 5dcf7f971..5c120f7e9 100644 --- a/zone/lua_bot.cpp +++ b/zone/lua_bot.cpp @@ -355,6 +355,11 @@ void Lua_Bot::Stand() { self->Stand(); } +uint32 Lua_Bot::GetBotID() { + Lua_Safe_Call_Int(); + return self->GetBotID(); +} + luabind::scope lua_register_bot() { return luabind::class_("Bot") .def(luabind::constructor<>()) @@ -390,6 +395,7 @@ luabind::scope lua_register_bot() { .def("GetBaseSTA", (int(Lua_Bot::*)(void))&Lua_Bot::GetBaseSTA) .def("GetBaseSTR", (int(Lua_Bot::*)(void))&Lua_Bot::GetBaseSTR) .def("GetBaseWIS", (int(Lua_Bot::*)(void))&Lua_Bot::GetBaseWIS) + .def("GetBotID", (uint32(Lua_Bot::*)(void))&Lua_Bot::GetBotID) .def("GetBotItem", (Lua_ItemInst(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItem) .def("GetBotItemIDBySlot", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItemIDBySlot) .def("GetExpansionBitmask", (int(Lua_Bot::*)(void))&Lua_Bot::GetExpansionBitmask) diff --git a/zone/lua_bot.h b/zone/lua_bot.h index 01b364149..92d8d9faa 100644 --- a/zone/lua_bot.h +++ b/zone/lua_bot.h @@ -55,6 +55,7 @@ public: bool HasBotSpellEntry(uint16 spellid); void SendPayload(int payload_id); void SendPayload(int payload_id, std::string payload_value); + uint32 GetBotID(); void ApplySpell(int spell_id); void ApplySpell(int spell_id, int duration); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index bb6d6e8c0..0a3dccde1 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -4615,7 +4615,9 @@ luabind::scope lua_register_events() { luabind::value("aa_gain", static_cast(EVENT_AA_GAIN)), luabind::value("payload", static_cast(EVENT_PAYLOAD)), luabind::value("level_down", static_cast(EVENT_LEVEL_DOWN)), - luabind::value("gm_command", static_cast(EVENT_GM_COMMAND)) + luabind::value("gm_command", static_cast(EVENT_GM_COMMAND)), + luabind::value("despawn", static_cast(EVENT_DESPAWN)), + luabind::value("despawn_zone", static_cast(EVENT_DESPAWN_ZONE)) )]; } diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index 1020233f3..9f6dad3fc 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -152,7 +152,9 @@ const char *LuaEvents[_LargestEventID] = { "event_aa_gain", "event_payload", "event_level_down", - "event_gm_command" + "event_gm_command", + "event_despawn", + "event_despawn_zone", }; extern Zone *zone; diff --git a/zone/mob.cpp b/zone/mob.cpp index 992231dcb..204faa36d 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -7041,3 +7041,28 @@ void Mob::CopyHateList(Mob* to) { } } } + +int Mob::DispatchZoneControllerEvent( + QuestEventID evt, + Mob* init, + const std::string& data, + uint32 extra, + std::vector* pointers +) { + auto ret = 0; + + if ( + RuleB(Zone, UseZoneController) && + ( + !IsNPC() || + (IsNPC() && 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/mob.h b/zone/mob.h index b0604a4cb..0c1a2281f 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -29,6 +29,9 @@ #include "../common/light_source.h" #include "../common/emu_constants.h" #include "combat_record.h" +#include "event_codes.h" + +#include #include #include #include @@ -1432,6 +1435,8 @@ public: std::string GetBucketRemaining(std::string bucket_name); void SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration = ""); + int DispatchZoneControllerEvent(QuestEventID evt, Mob* init, const std::string& data, uint32 extra, std::vector* pointers); + #ifdef BOTS // Bots HealRotation methods bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); } diff --git a/zone/npc.cpp b/zone/npc.cpp index c498dcef6..71de4e8cf 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -1111,14 +1111,25 @@ void NPC::UpdateEquipmentLight() m_Light.Level[EQ::lightsource::LightEquipment] = EQ::lightsource::TypeToLevel(m_Light.Type[EQ::lightsource::LightEquipment]); } -void NPC::Depop(bool StartSpawnTimer) { - uint32 emoteid = GetEmoteID(); - if(emoteid != 0) - DoNPCEmote(EQ::constants::EmoteEventTypes::OnDespawn,emoteid); +void NPC::Depop(bool start_spawn_timer) { + const auto emote_id = GetEmoteID(); + if (emote_id) { + DoNPCEmote(EQ::constants::EmoteEventTypes::OnDespawn, emoteid); + } + + if (IsNPC()) { + parse->EventNPC(EVENT_DESPAWN, this, nullptr, "", 0); + DispatchZoneControllerEvent(EVENT_DESPAWN_ZONE, this, "", 0, nullptr); +#ifdef BOTS + } else if (IsBot()) { + parse->EventBot(EVENT_DESPAWN, CastToBot(), nullptr, "", 0); + DispatchZoneControllerEvent(EVENT_DESPAWN_ZONE, this, "", 0, nullptr); +#endif + } + p_depop = true; - if (respawn2) - { - if (StartSpawnTimer) { + if (respawn2) { + if (start_spawn_timer) { respawn2->DeathReset(); } else { respawn2->Depop(); @@ -3779,18 +3790,3 @@ 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 8977e5c79..e1e1e3ae5 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -27,7 +27,6 @@ #include "zonedump.h" #include "../common/loottable.h" -#include #include #include @@ -251,7 +250,7 @@ public: inline void MerchantOpenShop() { merchant_open = true; } inline void MerchantCloseShop() { merchant_open = false; } inline bool IsMerchantOpen() { return merchant_open; } - void Depop(bool StartSpawnTimer = false); + void Depop(bool start_spawn_timer = false); void Stun(int duration); void UnStun(); uint32 GetSwarmOwner(); @@ -539,8 +538,6 @@ public: static LootDropEntries_Struct NewLootDropEntry(); - int DispatchZoneControllerEvent(QuestEventID evt, Mob* init, const std::string& data, uint32 extra, std::vector* pointers); - protected: const NPCType* NPCTypedata; diff --git a/zone/perl_bot.cpp b/zone/perl_bot.cpp index 89e6eb544..5442b3b5c 100644 --- a/zone/perl_bot.cpp +++ b/zone/perl_bot.cpp @@ -371,6 +371,11 @@ void Perl_Bot_SendPayload(Bot* self, int payload_id, std::string payload_value) self->SendPayload(payload_id, payload_value); } +uint32 Perl_Bot_GetBotID(Bot* self) // @categories Script Utility +{ + return self->GetBotID(); +} + void perl_register_bot() { perl::interpreter state(PERL_GET_THX); @@ -393,7 +398,7 @@ void perl_register_bot() package.add("ApplySpellGroup", (void(*)(Bot*, int, int))&Perl_Bot_ApplySpellGroup); package.add("ApplySpellGroup", (void(*)(Bot*, int, int, bool))&Perl_Bot_ApplySpellGroup); package.add("CountAugmentEquippedByID", &Perl_Bot_CountAugmentEquippedByID); - package.add("CountBotItem", &Perl_Bot_CountBotItem); + package.add("CountBotItem", &Perl_Bot_CountBotItem); package.add("CountItemEquippedByID", &Perl_Bot_CountItemEquippedByID); package.add("Escape", &Perl_Bot_Escape); package.add("Fling", (void(*)(Bot*, float, float, float))&Perl_Bot_Fling); @@ -411,6 +416,7 @@ void perl_register_bot() package.add("GetBaseSTA", &Perl_Bot_GetBaseSTA); package.add("GetBaseSTR", &Perl_Bot_GetBaseSTR); package.add("GetBaseWIS", &Perl_Bot_GetBaseWIS); + package.add("GetBotID", &Perl_Bot_GetBotID); package.add("GetBotItem", &Perl_Bot_GetBotItem); package.add("GetBotItemIDBySlot", &Perl_Bot_GetBotItemIDBySlot); package.add("GetExpansionBitmask", &Perl_Bot_GetExpansionBitmask);