[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
{
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<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) {
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)) {

View File

@ -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<NPC*>(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;
}

View File

@ -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,

View File

@ -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_<Lua_Bot, Lua_Mob>("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)

View File

@ -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);

View File

@ -4615,7 +4615,9 @@ luabind::scope lua_register_events() {
luabind::value("aa_gain", static_cast<int>(EVENT_AA_GAIN)),
luabind::value("payload", static_cast<int>(EVENT_PAYLOAD)),
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_payload",
"event_level_down",
"event_gm_command"
"event_gm_command",
"event_despawn",
"event_despawn_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/emu_constants.h"
#include "combat_record.h"
#include "event_codes.h"
#include <any>
#include <set>
#include <vector>
#include <memory>
@ -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<std::any>* pointers);
#ifdef BOTS
// Bots HealRotation methods
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]);
}
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<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 "../common/loottable.h"
#include <any>
#include <deque>
#include <list>
@ -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<std::any>* pointers);
protected:
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);
}
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);