[Quest API] Add Despawn Events to Perl/Lua. (#2707)

# Perl
- Add `$bot->GetBotID()`.
- Add `EVENT_DESPAWN`.
- Add `EVENT_DESPAWN_ZONE`.

# Lua
- Add `bot:GetBotID()`.
- Add `event_despawn`.
- Add `event_despawn_zone`.

# Notes
- Allows operators to determine when a Bot or an NPC has been despawned via Depop.
- Bots call NPC::Depop on ^camp so we just put the code there.
- Adds the ability to get a bot's ID using their reference in case you're looping a list and need that value.
- Moves `DispatchZoneControllerEvent` from NPC to Mob so it can be used by any type.
This commit is contained in:
Alex King 2023-01-07 12:04:33 -05:00 committed by GitHub
parent 143c4fe6aa
commit c1ad086eaf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 120 additions and 37 deletions

View File

@ -1209,7 +1209,7 @@ void Bot::GenerateAppearance() {
if (GetRace() == BARBARIAN) // Barbarian w/Tatoo if (GetRace() == BARBARIAN) // Barbarian w/Tatoo
{ {
iFace = zone->random.Int(0, 79); iFace = zone->random.Int(0, 79);
} }
else else
{ {
iFace = zone->random.Int(0, 7); 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); insts[i - EQ::invslot::TRADE_BEGIN] = user_inv.GetItem(i);
client->DeleteItemInInventory(i); client->DeleteItemInInventory(i);
} }
// copy to be filtered by task updates, null trade slots preserved for quest event arg // copy to be filtered by task updates, null trade slots preserved for quest event arg
std::vector<EQ::ItemInstance*> items(insts, insts + std::size(insts)); std::vector<EQ::ItemInstance*> 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) { int32 Bot::GetActSpellDuration(uint16 spell_id, int32 duration) {
int increase = 100; int increase = 100;
increase += GetFocusEffect(focusSpellDuration, spell_id); increase += GetFocusEffect(focusSpellDuration, spell_id);
int64 tic_inc = 0; int64 tic_inc = 0;
tic_inc = GetFocusEffect(focusSpellDurByTic, spell_id); tic_inc = GetFocusEffect(focusSpellDurByTic, spell_id);
if(IsBeneficialSpell(spell_id)) { if(IsBeneficialSpell(spell_id)) {
@ -6758,7 +6758,7 @@ bool Bot::CastSpell(
(IsAmnesiad() && IsDiscipline(spell_id)) (IsAmnesiad() && IsDiscipline(spell_id))
) { ) {
LogSpellsModerate("[Bot::CastSpell] Spell casting canceled: not able to cast now. Valid? [{}] casting [{}] waiting? [{}] spellend? [{}] stunned? [{}] feared? [{}] mezed? [{}] silenced? [{}]", 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)) { if (IsSilenced() && !IsDiscipline(spell_id)) {
MessageString(Chat::White, SILENCED_STRING); 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); parse->EventBot(EVENT_SPAWN, new_bot, nullptr, "", 0);
new_bot->DispatchZoneControllerEvent(EVENT_SPAWN_ZONE, new_bot, "", 0, nullptr);
} }
bot_list.push_back(new_bot); bot_list.push_back(new_bot);
@ -9969,8 +9971,8 @@ std::string Bot::GetHPString(int8 min_hp, int8 max_hp)
return hp_string; 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; m_bot_archery_setting = bot_archer_setting;
if (save) { if (save) {
if (!database.botdb.SaveBotArcherSetting(GetBotID(), bot_archer_setting)) { if (!database.botdb.SaveBotArcherSetting(GetBotID(), bot_archer_setting)) {

View File

@ -166,6 +166,8 @@ const char *QuestEventSubroutines[_LargestEventID] = {
"EVENT_PAYLOAD", "EVENT_PAYLOAD",
"EVENT_LEVEL_DOWN", "EVENT_LEVEL_DOWN",
"EVENT_GM_COMMAND", "EVENT_GM_COMMAND",
"EVENT_DESPAWN",
"EVENT_DESPAWN_ZONE",
#ifdef BOTS #ifdef BOTS
"EVENT_SPELL_EFFECT_BOT", "EVENT_SPELL_EFFECT_BOT",
"EVENT_SPELL_EFFECT_BUFF_TIC_BOT", "EVENT_SPELL_EFFECT_BUFF_TIC_BOT",
@ -1838,7 +1840,18 @@ void PerlembParser::ExportEventVariables(
NPC* killed = std::any_cast<NPC*>(extra_pointers->at(1)); NPC* killed = std::any_cast<NPC*>(extra_pointers->at(1));
if (killed) 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_x", killed->GetX());
ExportVar(package_name.c_str(), "killed_y", killed->GetY()); ExportVar(package_name.c_str(), "killed_y", killed->GetY());
ExportVar(package_name.c_str(), "killed_z", killed->GetZ()); ExportVar(package_name.c_str(), "killed_z", killed->GetZ());
@ -1859,7 +1872,17 @@ void PerlembParser::ExportEventVariables(
case EVENT_SPAWN_ZONE: { case EVENT_SPAWN_ZONE: {
ExportVar(package_name.c_str(), "spawned_entity_id", mob->GetID()); 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; break;
} }
@ -2013,6 +2036,22 @@ void PerlembParser::ExportEventVariables(
break; 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: { default: {
break; break;
} }

View File

@ -109,6 +109,8 @@ typedef enum {
EVENT_PAYLOAD, EVENT_PAYLOAD,
EVENT_LEVEL_DOWN, EVENT_LEVEL_DOWN,
EVENT_GM_COMMAND, EVENT_GM_COMMAND,
EVENT_DESPAWN,
EVENT_DESPAWN_ZONE,
#ifdef BOTS #ifdef BOTS
EVENT_SPELL_EFFECT_BOT, EVENT_SPELL_EFFECT_BOT,
EVENT_SPELL_EFFECT_BUFF_TIC_BOT, EVENT_SPELL_EFFECT_BUFF_TIC_BOT,

View File

@ -355,6 +355,11 @@ void Lua_Bot::Stand() {
self->Stand(); self->Stand();
} }
uint32 Lua_Bot::GetBotID() {
Lua_Safe_Call_Int();
return self->GetBotID();
}
luabind::scope lua_register_bot() { luabind::scope lua_register_bot() {
return luabind::class_<Lua_Bot, Lua_Mob>("Bot") return luabind::class_<Lua_Bot, Lua_Mob>("Bot")
.def(luabind::constructor<>()) .def(luabind::constructor<>())
@ -390,6 +395,7 @@ luabind::scope lua_register_bot() {
.def("GetBaseSTA", (int(Lua_Bot::*)(void))&Lua_Bot::GetBaseSTA) .def("GetBaseSTA", (int(Lua_Bot::*)(void))&Lua_Bot::GetBaseSTA)
.def("GetBaseSTR", (int(Lua_Bot::*)(void))&Lua_Bot::GetBaseSTR) .def("GetBaseSTR", (int(Lua_Bot::*)(void))&Lua_Bot::GetBaseSTR)
.def("GetBaseWIS", (int(Lua_Bot::*)(void))&Lua_Bot::GetBaseWIS) .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("GetBotItem", (Lua_ItemInst(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItem)
.def("GetBotItemIDBySlot", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItemIDBySlot) .def("GetBotItemIDBySlot", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItemIDBySlot)
.def("GetExpansionBitmask", (int(Lua_Bot::*)(void))&Lua_Bot::GetExpansionBitmask) .def("GetExpansionBitmask", (int(Lua_Bot::*)(void))&Lua_Bot::GetExpansionBitmask)

View File

@ -55,6 +55,7 @@ public:
bool HasBotSpellEntry(uint16 spellid); bool HasBotSpellEntry(uint16 spellid);
void SendPayload(int payload_id); void SendPayload(int payload_id);
void SendPayload(int payload_id, std::string payload_value); void SendPayload(int payload_id, std::string payload_value);
uint32 GetBotID();
void ApplySpell(int spell_id); void ApplySpell(int spell_id);
void ApplySpell(int spell_id, int duration); void ApplySpell(int spell_id, int duration);

View File

@ -4615,7 +4615,9 @@ luabind::scope lua_register_events() {
luabind::value("aa_gain", static_cast<int>(EVENT_AA_GAIN)), luabind::value("aa_gain", static_cast<int>(EVENT_AA_GAIN)),
luabind::value("payload", static_cast<int>(EVENT_PAYLOAD)), luabind::value("payload", static_cast<int>(EVENT_PAYLOAD)),
luabind::value("level_down", static_cast<int>(EVENT_LEVEL_DOWN)), luabind::value("level_down", static_cast<int>(EVENT_LEVEL_DOWN)),
luabind::value("gm_command", static_cast<int>(EVENT_GM_COMMAND)) luabind::value("gm_command", static_cast<int>(EVENT_GM_COMMAND)),
luabind::value("despawn", static_cast<int>(EVENT_DESPAWN)),
luabind::value("despawn_zone", static_cast<int>(EVENT_DESPAWN_ZONE))
)]; )];
} }

View File

@ -152,7 +152,9 @@ const char *LuaEvents[_LargestEventID] = {
"event_aa_gain", "event_aa_gain",
"event_payload", "event_payload",
"event_level_down", "event_level_down",
"event_gm_command" "event_gm_command",
"event_despawn",
"event_despawn_zone",
}; };
extern Zone *zone; extern Zone *zone;

View File

@ -7041,3 +7041,28 @@ void Mob::CopyHateList(Mob* to) {
} }
} }
} }
int Mob::DispatchZoneControllerEvent(
QuestEventID evt,
Mob* init,
const std::string& data,
uint32 extra,
std::vector<std::any>* 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;
}

View File

@ -29,6 +29,9 @@
#include "../common/light_source.h" #include "../common/light_source.h"
#include "../common/emu_constants.h" #include "../common/emu_constants.h"
#include "combat_record.h" #include "combat_record.h"
#include "event_codes.h"
#include <any>
#include <set> #include <set>
#include <vector> #include <vector>
#include <memory> #include <memory>
@ -1432,6 +1435,8 @@ public:
std::string GetBucketRemaining(std::string bucket_name); std::string GetBucketRemaining(std::string bucket_name);
void SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration = ""); 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<std::any>* pointers);
#ifdef BOTS #ifdef BOTS
// Bots HealRotation methods // Bots HealRotation methods
bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); } bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); }

View File

@ -1111,14 +1111,25 @@ void NPC::UpdateEquipmentLight()
m_Light.Level[EQ::lightsource::LightEquipment] = EQ::lightsource::TypeToLevel(m_Light.Type[EQ::lightsource::LightEquipment]); m_Light.Level[EQ::lightsource::LightEquipment] = EQ::lightsource::TypeToLevel(m_Light.Type[EQ::lightsource::LightEquipment]);
} }
void NPC::Depop(bool StartSpawnTimer) { void NPC::Depop(bool start_spawn_timer) {
uint32 emoteid = GetEmoteID(); const auto emote_id = GetEmoteID();
if(emoteid != 0) if (emote_id) {
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDespawn,emoteid); 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; p_depop = true;
if (respawn2) if (respawn2) {
{ if (start_spawn_timer) {
if (StartSpawnTimer) {
respawn2->DeathReset(); respawn2->DeathReset();
} else { } else {
respawn2->Depop(); respawn2->Depop();
@ -3779,18 +3790,3 @@ int NPC::GetRolledItemCount(uint32 item_id)
return rolled_count; return rolled_count;
} }
int NPC::DispatchZoneControllerEvent(QuestEventID evt, Mob* init,
const std::string& data, uint32 extra, std::vector<std::any>* 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;
}

View File

@ -27,7 +27,6 @@
#include "zonedump.h" #include "zonedump.h"
#include "../common/loottable.h" #include "../common/loottable.h"
#include <any>
#include <deque> #include <deque>
#include <list> #include <list>
@ -251,7 +250,7 @@ public:
inline void MerchantOpenShop() { merchant_open = true; } inline void MerchantOpenShop() { merchant_open = true; }
inline void MerchantCloseShop() { merchant_open = false; } inline void MerchantCloseShop() { merchant_open = false; }
inline bool IsMerchantOpen() { return merchant_open; } inline bool IsMerchantOpen() { return merchant_open; }
void Depop(bool StartSpawnTimer = false); void Depop(bool start_spawn_timer = false);
void Stun(int duration); void Stun(int duration);
void UnStun(); void UnStun();
uint32 GetSwarmOwner(); uint32 GetSwarmOwner();
@ -539,8 +538,6 @@ public:
static LootDropEntries_Struct NewLootDropEntry(); static LootDropEntries_Struct NewLootDropEntry();
int DispatchZoneControllerEvent(QuestEventID evt, Mob* init, const std::string& data, uint32 extra, std::vector<std::any>* pointers);
protected: protected:
const NPCType* NPCTypedata; const NPCType* NPCTypedata;

View File

@ -371,6 +371,11 @@ void Perl_Bot_SendPayload(Bot* self, int payload_id, std::string payload_value)
self->SendPayload(payload_id, payload_value); self->SendPayload(payload_id, payload_value);
} }
uint32 Perl_Bot_GetBotID(Bot* self) // @categories Script Utility
{
return self->GetBotID();
}
void perl_register_bot() void perl_register_bot()
{ {
perl::interpreter state(PERL_GET_THX); 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))&Perl_Bot_ApplySpellGroup);
package.add("ApplySpellGroup", (void(*)(Bot*, int, int, bool))&Perl_Bot_ApplySpellGroup); package.add("ApplySpellGroup", (void(*)(Bot*, int, int, bool))&Perl_Bot_ApplySpellGroup);
package.add("CountAugmentEquippedByID", &Perl_Bot_CountAugmentEquippedByID); 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("CountItemEquippedByID", &Perl_Bot_CountItemEquippedByID);
package.add("Escape", &Perl_Bot_Escape); package.add("Escape", &Perl_Bot_Escape);
package.add("Fling", (void(*)(Bot*, float, float, float))&Perl_Bot_Fling); 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("GetBaseSTA", &Perl_Bot_GetBaseSTA);
package.add("GetBaseSTR", &Perl_Bot_GetBaseSTR); package.add("GetBaseSTR", &Perl_Bot_GetBaseSTR);
package.add("GetBaseWIS", &Perl_Bot_GetBaseWIS); package.add("GetBaseWIS", &Perl_Bot_GetBaseWIS);
package.add("GetBotID", &Perl_Bot_GetBotID);
package.add("GetBotItem", &Perl_Bot_GetBotItem); package.add("GetBotItem", &Perl_Bot_GetBotItem);
package.add("GetBotItemIDBySlot", &Perl_Bot_GetBotItemIDBySlot); package.add("GetBotItemIDBySlot", &Perl_Bot_GetBotItemIDBySlot);
package.add("GetExpansionBitmask", &Perl_Bot_GetExpansionBitmask); package.add("GetExpansionBitmask", &Perl_Bot_GetExpansionBitmask);