[Bots] Add support for Bot scripting. (#2515)

* [Bots] Add support for Bot scripting.

# Perl
- Add support for `zone/bot.pl` and `zone/bot_v#.pl`.
- Add support for `global/global_bot.pl`.
- Add `$bot->SignalBot(signal_id)` to Perl.
- Add `$bot->OwnerMessage(message)` to Perl.
- Add `$entity_list->SignalAllBotsByOwnerCharacterID(character_id, signal_id)` to Perl.
- Add `$entity_list->SignalBotByBotID(bot_id, signal_id)` to Perl.
- Add `$entity_list->SignalBotByBotName(bot_name, signal_id)` to Perl.
- Add `EVENT_SPELL_EFFECT_BOT` to Perl.
- Add `EVENT_SPELL_EFFECT_BUFF_TIC_BOT` to Perl.

# Lua
- Add support for `zone/bot.lua` and `zone/bot_v#.lua`.
- Add support for `global/global_bot.lua`.
- Add `bot:SignalBot(signal_id)` to Lua.
- Add `bot:OwnerMessage(message)` to Lua.
- Add `entity_list:SignalAllBotsByOwnerCharacterID(character_id, signal_id)` to Lua.
- Add `entity_list:SignalBotByBotID(bot_id, signal_id)` to Lua.
- Add `entity_list:SignalBotByBotName(bot_name, signal_id)` to Lua.
- Add `EVENT_SPELL_EFFECT_BOT` to Lua.
- Add `EVENT_SPELL_EFFECT_BUFF_TIC_BOT` to Lua.

# Supported Bot Events
1. `EVENT_CAST`
2. `EVENT_CAST_BEGIN`
3. `EVENT_CAST_ON`
4. `EVENT_COMBAT`
5. `EVENT_DEATH`
6. `EVENT_DEATH_COMPLETE`
7. `EVENT_SAY`
8. `EVENT_SIGNAL`
9. `EVENT_SLAY`
10. `EVENT_SLAY_NPC`
11. `EVENT_SPAWN`
12. `EVENT_TARGET_CHANGE`
13. `EVENT_TIMER`
14. `EVENT_USE_SKILL`

# Common
- Convert NPC pointers in common events to Mob pointers so bots are supported.
- Convert signal IDs to `int` where it wasn't already, allowing negative signals to be sent properly.

* Add EVENT_POPUP_RESPONSE.

* Cleanup and fix EVENT_COMBAT/EVENT_SLAY/EVENT_NPC_SLAY.

* Fix DoNPCEmote calls.

* Update attack.cpp

* Update event_codes.h

* Update bot_command.cpp
This commit is contained in:
Kinglykrab
2022-11-16 22:02:16 -05:00
committed by GitHub
parent 7ea77ee027
commit 856aa51cb8
42 changed files with 2709 additions and 621 deletions
+414 -113
View File
@@ -163,6 +163,11 @@ const char *QuestEventSubroutines[_LargestEventID] = {
"EVENT_TASK_BEFORE_UPDATE",
"EVENT_AA_BUY",
"EVENT_AA_GAIN"
#ifdef BOTS
,
"EVENT_SPELL_EFFECT_BOT",
"EVENT_SPELL_EFFECT_BUFF_TIC_BOT"
#endif
};
PerlembParser::PerlembParser() : perl(nullptr)
@@ -170,6 +175,11 @@ PerlembParser::PerlembParser() : perl(nullptr)
global_npc_quest_status_ = questUnloaded;
player_quest_status_ = questUnloaded;
global_player_quest_status_ = questUnloaded;
#ifdef BOTS
bot_quest_status_ = questUnloaded;
global_bot_quest_status_ = questUnloaded;
#endif
}
PerlembParser::~PerlembParser()
@@ -203,15 +213,28 @@ void PerlembParser::ReloadQuests()
global_npc_quest_status_ = questUnloaded;
player_quest_status_ = questUnloaded;
global_player_quest_status_ = questUnloaded;
#ifdef BOTS
bot_quest_status_ = questUnloaded;
global_bot_quest_status_ = questUnloaded;
#endif
item_quest_status_.clear();
spell_quest_status_.clear();
}
int PerlembParser::EventCommon(
QuestEventID event, uint32 objid, const char *data, NPC *npcmob, EQ::ItemInstance *item_inst, const SPDat_Spell_Struct* spell, Mob *mob,
uint32 extradata, bool global, std::vector<std::any> *extra_pointers
)
{
QuestEventID event,
uint32 objid,
const char *data,
Mob *npcmob,
EQ::ItemInstance *item_inst,
const SPDat_Spell_Struct* spell,
Mob *mob,
uint32 extradata,
bool global,
std::vector<std::any> *extra_pointers
) {
if (!perl) {
return 0;
}
@@ -220,20 +243,46 @@ int PerlembParser::EventCommon(
return 0;
}
bool isPlayerQuest = false;
bool isGlobalPlayerQuest = false;
bool isGlobalNPC = false;
bool isItemQuest = false;
bool isSpellQuest = false;
bool isPlayerQuest = false;
bool isGlobalPlayerQuest = false;
bool isGlobalNPC = false;
bool isBotQuest = false;
bool isGlobalBotQuest = false;
bool isItemQuest = false;
bool isSpellQuest = false;
std::string package_name;
GetQuestTypes(
isPlayerQuest, isGlobalPlayerQuest, isGlobalNPC, isItemQuest, isSpellQuest,
event, npcmob, item_inst, mob, global
isPlayerQuest,
isGlobalPlayerQuest,
isBotQuest,
isGlobalBotQuest,
isGlobalNPC,
isItemQuest,
isSpellQuest,
event,
npcmob,
item_inst,
mob,
global
);
GetQuestPackageName(
isPlayerQuest, isGlobalPlayerQuest, isGlobalNPC, isItemQuest, isSpellQuest,
package_name, event, objid, data, npcmob, item_inst, global
isPlayerQuest,
isGlobalPlayerQuest,
isBotQuest,
isGlobalBotQuest,
isGlobalNPC,
isItemQuest,
isSpellQuest,
package_name,
event,
objid,
data,
npcmob,
item_inst,
global
);
const char *sub_name = QuestEventSubroutines[event];
@@ -249,6 +298,8 @@ int PerlembParser::EventCommon(
ExportQGlobals(
isPlayerQuest,
isGlobalPlayerQuest,
isBotQuest,
isGlobalBotQuest,
isGlobalNPC,
isItemQuest,
isSpellQuest,
@@ -264,6 +315,8 @@ int PerlembParser::EventCommon(
ExportMobVariables(
isPlayerQuest,
isGlobalPlayerQuest,
isBotQuest,
isGlobalBotQuest,
isGlobalNPC,
isItemQuest,
isSpellQuest,
@@ -290,6 +343,8 @@ int PerlembParser::EventCommon(
if (isPlayerQuest || isGlobalPlayerQuest) {
return SendCommands(package_name.c_str(), sub_name, 0, mob, mob, nullptr, nullptr);
} else if (isBotQuest || isGlobalBotQuest) {
return SendCommands(package_name.c_str(), sub_name, 0, npcmob, mob, nullptr, nullptr);
} else if (isItemQuest) {
return SendCommands(package_name.c_str(), sub_name, 0, mob, mob, item_inst, nullptr);
} else if (isSpellQuest) {
@@ -304,19 +359,19 @@ int PerlembParser::EventCommon(
}
int PerlembParser::EventNPC(
QuestEventID evt, NPC *npc, Mob *init, std::string data, uint32 extra_data,
QuestEventID evt, NPC *npc, Mob *mob, std::string data, uint32 extra_data,
std::vector<std::any> *extra_pointers
)
{
return EventCommon(evt, npc->GetNPCTypeID(), data.c_str(), npc, nullptr, nullptr, init, extra_data, false, extra_pointers);
return EventCommon(evt, npc->GetNPCTypeID(), data.c_str(), npc, nullptr, nullptr, mob, extra_data, false, extra_pointers);
}
int PerlembParser::EventGlobalNPC(
QuestEventID evt, NPC *npc, Mob *init, std::string data, uint32 extra_data,
QuestEventID evt, NPC *npc, Mob *mob, std::string data, uint32 extra_data,
std::vector<std::any> *extra_pointers
)
{
return EventCommon(evt, npc->GetNPCTypeID(), data.c_str(), npc, nullptr, nullptr, init, extra_data, true, extra_pointers);
return EventCommon(evt, npc->GetNPCTypeID(), data.c_str(), npc, nullptr, nullptr, mob, extra_data, true, extra_pointers);
}
int PerlembParser::EventPlayer(
@@ -345,11 +400,11 @@ int PerlembParser::EventItem(
}
int PerlembParser::EventSpell(
QuestEventID evt, NPC *npc, Client *client, uint32 spell_id, std::string data, uint32 extra_data,
QuestEventID evt, Mob *mob, Client *client, uint32 spell_id, std::string data, uint32 extra_data,
std::vector<std::any> *extra_pointers
)
{
return EventCommon(evt, spell_id, data.c_str(), npc, nullptr, &spells[spell_id], client, extra_data, false, extra_pointers);
return EventCommon(evt, spell_id, data.c_str(), mob, nullptr, &spells[spell_id], client, extra_data, false, extra_pointers);
}
bool PerlembParser::HasQuestSub(uint32 npcid, QuestEventID evt)
@@ -860,77 +915,93 @@ int PerlembParser::SendCommands(
std::string qi = (std::string) "$" + (std::string) pkgprefix + (std::string) "::questitem";
std::string sp = (std::string) "$" + (std::string) pkgprefix + (std::string) "::spell";
std::string enl = (std::string) "$" + (std::string) pkgprefix + (std::string) "::entity_list";
#ifdef BOTS
std::string bot = (std::string) "$" + (std::string) pkgprefix + (std::string) "::bot";
#endif
if (clear_vars_.find(cl) != clear_vars_.end()) {
std::string eval_str = cl;
eval_str += " = undef;";
perl->eval(eval_str.c_str());
auto e = fmt::format("{} = undef;", cl);
perl->eval(e.c_str());
}
if (clear_vars_.find(np) != clear_vars_.end()) {
std::string eval_str = np;
eval_str += " = undef;";
perl->eval(eval_str.c_str());
auto e = fmt::format("{} = undef;", np);
perl->eval(e.c_str());
}
if (clear_vars_.find(qi) != clear_vars_.end()) {
std::string eval_str = qi;
eval_str += " = undef;";
perl->eval(eval_str.c_str());
auto e = fmt::format("{} = undef;", qi);
perl->eval(e.c_str());
}
if (clear_vars_.find(sp) != clear_vars_.end()) {
std::string eval_str = sp;
eval_str += " = undef;";
perl->eval(eval_str.c_str());
auto e = fmt::format("{} = undef;", sp);
perl->eval(e.c_str());
}
if (clear_vars_.find(enl) != clear_vars_.end()) {
std::string eval_str = enl;
eval_str += " = undef;";
perl->eval(eval_str.c_str());
auto e = fmt::format("{} = undef;", enl);
perl->eval(e.c_str());
}
#ifdef BOTS
if (clear_vars_.find(bot) != clear_vars_.end()) {
auto e = fmt::format("{} = undef;", bot);
perl->eval(e.c_str());
}
#endif
}
char namebuf[64];
std::string buf;
//init a couple special vars: client, npc, entity_list
Client *curc = quest_manager.GetInitiator();
snprintf(namebuf, 64, "%s::client", pkgprefix);
SV *client = get_sv(namebuf, true);
if (curc != nullptr) {
buf = fmt::format("{}::client", pkgprefix);
SV *client = get_sv(buf.c_str(), true);
if (curc) {
sv_setref_pv(client, "Client", curc);
}
else {
} else {
//clear out the value, mainly to get rid of blessedness
sv_setsv(client, _empty_sv);
}
//only export NPC if it's a npc quest
if (!other->IsClient()) {
if (!other->IsClient() && other->IsNPC()) {
NPC *curn = quest_manager.GetNPC();
snprintf(namebuf, 64, "%s::npc", pkgprefix);
SV *npc = get_sv(namebuf, true);
buf = fmt::format("{}::npc", pkgprefix);
SV *npc = get_sv(buf.c_str(), true);
sv_setref_pv(npc, "NPC", curn);
}
#ifdef BOTS
if (!other->IsClient() && other->IsBot()) {
Bot *curb = quest_manager.GetBot();
buf = fmt::format("{}::bot", pkgprefix);
SV *bot = get_sv(buf.c_str(), true);
sv_setref_pv(bot, "Bot", curb);
}
#endif
//only export QuestItem if it's an item quest
if (item_inst) {
EQ::ItemInstance *curi = quest_manager.GetQuestItem();
snprintf(namebuf, 64, "%s::questitem", pkgprefix);
SV *questitem = get_sv(namebuf, true);
buf = fmt::format("{}::questitem", pkgprefix);
SV *questitem = get_sv(buf.c_str(), true);
sv_setref_pv(questitem, "QuestItem", curi);
}
if (spell) {
const SPDat_Spell_Struct* current_spell = quest_manager.GetQuestSpell();
SPDat_Spell_Struct* real_spell = const_cast<SPDat_Spell_Struct*>(current_spell);
snprintf(namebuf, 64, "%s::spell", pkgprefix);
SV *spell = get_sv(namebuf, true);
buf = fmt::format("{}::spell", pkgprefix);
SV *spell = get_sv(buf.c_str(), true);
sv_setref_pv(spell, "Spell", (void *) real_spell);
}
snprintf(namebuf, 64, "%s::entity_list", pkgprefix);
SV *el = get_sv(namebuf, true);
buf = fmt::format("{}::entity_list", pkgprefix);
SV *el = get_sv(buf.c_str(), true);
sv_setref_pv(el, "EntityList", &entity_list);
#endif
@@ -944,11 +1015,20 @@ int PerlembParser::SendCommands(
std::string qi = (std::string) "$" + (std::string) pkgprefix + (std::string) "::questitem";
std::string sp = (std::string) "$" + (std::string) pkgprefix + (std::string) "::spell";
std::string enl = (std::string) "$" + (std::string) pkgprefix + (std::string) "::entity_list";
#ifdef BOTS
std::string bot = (std::string) "$" + (std::string) pkgprefix + (std::string) "::bot";
#endif
clear_vars_[cl] = 1;
clear_vars_[np] = 1;
clear_vars_[qi] = 1;
clear_vars_[sp] = 1;
clear_vars_[enl] = 1;
#ifdef BOTS
clear_vars_[bot] = 1;
#endif
}
#endif
@@ -967,19 +1047,16 @@ int PerlembParser::SendCommands(
#ifdef EMBPERL_XS_CLASSES
if (!quest_manager.QuestsRunning()) {
auto iter = clear_vars_.begin();
std::string eval_str;
while (iter != clear_vars_.end()) {
eval_str += iter->first;
eval_str += " = undef;";
++iter;
for (const auto &v : clear_vars_) {
eval_str += fmt::format("{} = undef;", v.first);
}
clear_vars_.clear();
try {
perl->eval(eval_str.c_str());
}
catch (std::string e) {
} catch (std::string e) {
AddError(
fmt::format(
"Script Clear Error | Error [{}]",
@@ -1023,29 +1100,61 @@ void PerlembParser::MapFunctions()
}
void PerlembParser::GetQuestTypes(
bool &isPlayerQuest, bool &isGlobalPlayerQuest, bool &isGlobalNPC, bool &isItemQuest,
bool &isSpellQuest, QuestEventID event, NPC *npcmob, EQ::ItemInstance *item_inst, Mob *mob, bool global
)
{
if (event == EVENT_SPELL_EFFECT_CLIENT ||
bool &isPlayerQuest,
bool &isGlobalPlayerQuest,
bool &isBotQuest,
bool &isGlobalBotQuest,
bool &isGlobalNPC,
bool &isItemQuest,
bool &isSpellQuest,
QuestEventID event,
Mob *npcmob,
EQ::ItemInstance *item_inst,
Mob *mob,
bool global
) {
if (
event == EVENT_SPELL_EFFECT_CLIENT ||
event == EVENT_SPELL_EFFECT_NPC ||
#ifdef BOTS
event == EVENT_SPELL_EFFECT_BOT ||
#endif
event == EVENT_SPELL_EFFECT_BUFF_TIC_CLIENT ||
event == EVENT_SPELL_EFFECT_BUFF_TIC_NPC ||
#ifdef BOTS
event == EVENT_SPELL_EFFECT_BUFF_TIC_BOT ||
#endif
event == EVENT_SPELL_FADE ||
event == EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE) {
event == EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE
) {
isSpellQuest = true;
}
else {
if (!npcmob && mob) {
} else {
if (npcmob) {
if (!item_inst) {
if (global) {
isGlobalPlayerQuest = true;
}
else {
isPlayerQuest = true;
if (npcmob->IsBot()) {
isGlobalBotQuest = true;
}
} else {
if (npcmob->IsBot()) {
isBotQuest = true;
}
}
} else {
isItemQuest = true;
}
else {
} else if (!npcmob && mob) {
if (!item_inst) {
if (global) {
if (mob->IsClient()) {
isGlobalPlayerQuest = true;
}
} else {
if (mob->IsClient()) {
isPlayerQuest = true;
}
}
} else {
isItemQuest = true;
}
}
@@ -1055,6 +1164,8 @@ void PerlembParser::GetQuestTypes(
void PerlembParser::GetQuestPackageName(
bool &isPlayerQuest,
bool &isGlobalPlayerQuest,
bool &isBotQuest,
bool &isGlobalBotQuest,
bool &isGlobalNPC,
bool &isItemQuest,
bool &isSpellQuest,
@@ -1062,7 +1173,7 @@ void PerlembParser::GetQuestPackageName(
QuestEventID event,
uint32 objid,
const char *data,
NPC *npcmob,
Mob *npcmob,
EQ::ItemInstance *item_inst,
bool global
)
@@ -1070,6 +1181,8 @@ void PerlembParser::GetQuestPackageName(
if (
!isPlayerQuest &&
!isGlobalPlayerQuest &&
!isBotQuest &&
!isGlobalBotQuest &&
!isItemQuest &&
!isSpellQuest
) {
@@ -1077,30 +1190,30 @@ void PerlembParser::GetQuestPackageName(
isGlobalNPC = true;
package_name = "qst_global_npc";
} else {
package_name = "qst_npc_";
package_name += std::to_string(npcmob->GetNPCTypeID());
package_name = fmt::format("qst_npc_{}", npcmob->GetNPCTypeID());
}
} else if (isItemQuest) {
// need a valid EQ::ItemInstance pointer check here..unsure how to cancel this process
const EQ::ItemData *item = item_inst->GetItem();
package_name = "qst_item_";
package_name += std::to_string(item->ID);
package_name = fmt::format("qst_item_{}", item->ID);
} else if (isPlayerQuest) {
package_name = "qst_player";
} else if (isGlobalPlayerQuest) {
package_name = "qst_global_player";
} else if (isBotQuest) {
package_name = "qst_bot";
} else if (isGlobalBotQuest) {
package_name = "qst_global_bot";
} else {
package_name = "qst_spell_";
package_name += std::to_string(objid);
package_name = fmt::format("qst_spell_{}", objid);
}
}
void PerlembParser::ExportCharID(const std::string &package_name, int &char_id, NPC *npcmob, Mob *mob)
void PerlembParser::ExportCharID(const std::string &package_name, int &char_id, Mob *npcmob, Mob *mob)
{
if (mob && mob->IsClient()) { // some events like waypoint and spawn don't have a player involved
char_id = mob->CastToClient()->CharacterID();
}
else {
} else {
if (npcmob) {
char_id = -static_cast<int>(npcmob->GetNPCTypeID()); // make char id negative npc id as a fudge
}
@@ -1112,29 +1225,54 @@ void PerlembParser::ExportCharID(const std::string &package_name, int &char_id,
}
void PerlembParser::ExportQGlobals(
bool isPlayerQuest, bool isGlobalPlayerQuest, bool isGlobalNPC, bool isItemQuest,
bool isSpellQuest, std::string &package_name, NPC *npcmob, Mob *mob, int char_id
)
{
bool isPlayerQuest,
bool isGlobalPlayerQuest,
bool isBotQuest,
bool isGlobalBotQuest,
bool isGlobalNPC,
bool isItemQuest,
bool isSpellQuest,
std::string &package_name,
Mob *npcmob,
Mob *mob,
int char_id
) {
//NPC quest
if (!isPlayerQuest && !isGlobalPlayerQuest && !isItemQuest && !isSpellQuest) {
if (
!isPlayerQuest &&
!isGlobalPlayerQuest &&
!isBotQuest &&
!isGlobalBotQuest &&
!isItemQuest &&
!isSpellQuest
) {
//only export for npcs that are global enabled.
if (npcmob && npcmob->GetQglobal()) {
std::map<std::string, std::string> globhash;
QGlobalCache *npc_c = nullptr;
QGlobalCache *char_c = nullptr;
QGlobalCache *zone_c = nullptr;
QGlobalCache *npc_c = nullptr;
QGlobalCache *char_c = nullptr;
QGlobalCache *zone_c = nullptr;
//retrieve our globals
npc_c = npcmob->GetQGlobals();
if (npcmob) {
if (npcmob->IsNPC()) {
npc_c = npcmob->CastToNPC()->GetQGlobals();
} else if (npcmob->IsClient()) {
char_c = npcmob->CastToClient()->GetQGlobals();
}
}
if (mob && mob->IsClient()) {
char_c = mob->CastToClient()->GetQGlobals();
}
zone_c = zone->GetQGlobals();
if (!npc_c) {
npc_c = npcmob->CreateQGlobals();
npc_c->LoadByNPCID(npcmob->GetNPCTypeID());
if (npcmob && npcmob->IsNPC()) {
npc_c = npcmob->CastToNPC()->CreateQGlobals();
npc_c->LoadByNPCID(npcmob->GetNPCTypeID());
}
}
if (!char_c) {
@@ -1157,7 +1295,8 @@ void PerlembParser::ExportQGlobals(
npc_c->GetBucket(),
npcmob->GetNPCTypeID(),
char_id,
zone->GetZoneID());
zone->GetZoneID())
;
}
if (char_c) {
@@ -1166,7 +1305,8 @@ void PerlembParser::ExportQGlobals(
char_c->GetBucket(),
npcmob->GetNPCTypeID(),
char_id,
zone->GetZoneID());
zone->GetZoneID()
);
}
if (zone_c) {
@@ -1175,7 +1315,8 @@ void PerlembParser::ExportQGlobals(
zone_c->GetBucket(),
npcmob->GetNPCTypeID(),
char_id,
zone->GetZoneID());
zone->GetZoneID()
);
}
auto iter = globalMap.begin();
@@ -1184,19 +1325,20 @@ void PerlembParser::ExportQGlobals(
ExportVar(package_name.c_str(), (*iter).name.c_str(), (*iter).value.c_str());
++iter;
}
ExportHash(package_name.c_str(), "qglobals", globhash);
}
}
else {
} else {
std::map<std::string, std::string> globhash;
QGlobalCache *char_c = nullptr;
QGlobalCache *zone_c = nullptr;
QGlobalCache *char_c = nullptr;
QGlobalCache *zone_c = nullptr;
//retrieve our globals
if (mob && mob->IsClient()) {
char_c = mob->CastToClient()->GetQGlobals();
}
zone_c = zone->GetQGlobals();
zone_c = zone->GetQGlobals();
if (!char_c) {
if (mob && mob->IsClient()) {
@@ -1226,15 +1368,23 @@ void PerlembParser::ExportQGlobals(
ExportVar(package_name.c_str(), (*iter).name.c_str(), (*iter).value.c_str());
++iter;
}
ExportHash(package_name.c_str(), "qglobals", globhash);
}
}
void PerlembParser::ExportMobVariables(
bool isPlayerQuest, bool isGlobalPlayerQuest, bool isGlobalNPC, bool isItemQuest,
bool isSpellQuest, std::string &package_name, Mob *mob, NPC *npcmob
)
{
bool isPlayerQuest,
bool isGlobalPlayerQuest,
bool isBotQuest,
bool isGlobalBotQuest,
bool isGlobalNPC,
bool isItemQuest,
bool isSpellQuest,
std::string &package_name,
Mob *mob,
Mob *npcmob
) {
uint8 fac = 0;
if (mob && mob->IsClient()) {
ExportVar(package_name.c_str(), "uguild_id", mob->CastToClient()->GuildID());
@@ -1242,8 +1392,21 @@ void PerlembParser::ExportMobVariables(
ExportVar(package_name.c_str(), "status", mob->CastToClient()->Admin());
}
if (!isPlayerQuest && !isGlobalPlayerQuest && !isItemQuest) {
if (mob && npcmob && mob->IsClient()) {
#ifdef BOTS
if (mob && mob->IsBot()) {
ExportVar(package_name.c_str(), "bot_id", mob->CastToBot()->GetBotID());
ExportVar(package_name.c_str(), "bot_owner_char_id", mob->CastToBot()->GetBotOwnerCharacterID());
}
#endif
if (
!isPlayerQuest &&
!isGlobalPlayerQuest &&
!isBotQuest &&
!isGlobalBotQuest &&
!isItemQuest
) {
if (mob && mob->IsClient() && npcmob && npcmob->IsNPC()) {
Client *client = mob->CastToClient();
fac = client->GetFactionLevel(
@@ -1261,8 +1424,15 @@ void PerlembParser::ExportMobVariables(
ExportVar(package_name.c_str(), "userid", mob->GetID());
}
if (!isPlayerQuest && !isGlobalPlayerQuest && !isItemQuest && !isSpellQuest) {
if (npcmob) {
if (
!isPlayerQuest &&
!isGlobalPlayerQuest &&
!isBotQuest &&
!isGlobalBotQuest &&
!isItemQuest &&
!isSpellQuest
) {
if (npcmob->IsNPC()) {
ExportVar(package_name.c_str(), "mname", npcmob->GetName());
ExportVar(package_name.c_str(), "mobid", npcmob->GetID());
ExportVar(package_name.c_str(), "mlevel", npcmob->GetLevel());
@@ -1331,14 +1501,20 @@ void PerlembParser::ExportItemVariables(std::string &package_name, Mob *mob)
}
void PerlembParser::ExportEventVariables(
std::string &package_name, QuestEventID event, uint32 objid, const char *data,
NPC *npcmob, EQ::ItemInstance *item_inst, Mob *mob, uint32 extradata, std::vector<std::any> *extra_pointers
)
{
std::string &package_name,
QuestEventID event,
uint32 objid,
const char *data,
Mob *npcmob,
EQ::ItemInstance *item_inst,
Mob *mob,
uint32 extradata,
std::vector<std::any> *extra_pointers
) {
switch (event) {
case EVENT_SAY: {
if (npcmob && mob) {
npcmob->DoQuestPause(mob);
if (npcmob && npcmob->IsNPC() && mob) {
npcmob->CastToNPC()->DoQuestPause(mob);
}
ExportVar(package_name.c_str(), "data", objid);
@@ -1568,8 +1744,15 @@ void PerlembParser::ExportEventVariables(
break;
}
#ifdef BOTS
case EVENT_SPELL_EFFECT_BUFF_TIC_BOT:
#endif
case EVENT_SPELL_EFFECT_BUFF_TIC_CLIENT:
case EVENT_SPELL_EFFECT_BUFF_TIC_NPC:
#ifdef BOTS
case EVENT_SPELL_EFFECT_BOT:
#endif
case EVENT_SPELL_EFFECT_CLIENT:
case EVENT_SPELL_EFFECT_NPC:
case EVENT_SPELL_FADE: {
@@ -1799,4 +1982,122 @@ void PerlembParser::ExportEventVariables(
}
}
#ifdef BOTS
void PerlembParser::LoadBotScript(std::string filename)
{
if (!perl) {
return;
}
if (bot_quest_status_ != questUnloaded) {
return;
}
try {
perl->eval_file("qst_bot", filename.c_str());
} catch (std::string e) {
AddError(
fmt::format(
"Error Compiling Bot Quest File [{}] Error [{}]",
filename,
e
)
);
bot_quest_status_ = questFailedToLoad;
return;
}
bot_quest_status_ = questLoaded;
}
void PerlembParser::LoadGlobalBotScript(std::string filename)
{
if (!perl) {
return;
}
if (global_bot_quest_status_ != questUnloaded) {
return;
}
try {
perl->eval_file("qst_global_bot", filename.c_str());
} catch (std::string e) {
AddError(
fmt::format(
"Error Compiling Global Bot Quest File [{}] Error [{}]",
filename,
e
)
);
global_bot_quest_status_ = questFailedToLoad;
return;
}
global_bot_quest_status_ = questLoaded;
}
bool PerlembParser::BotHasQuestSub(QuestEventID evt)
{
if (!perl) {
return false;
}
if (bot_quest_status_ != questLoaded) {
return false;
}
if (evt >= _LargestEventID) {
return false;
}
const char *subname = QuestEventSubroutines[evt];
return (perl->SubExists("qst_bot", subname));
}
bool PerlembParser::GlobalBotHasQuestSub(QuestEventID evt)
{
if (!perl) {
return false;
}
if (global_bot_quest_status_ != questLoaded) {
return false;
}
if (evt >= _LargestEventID) {
return false;
}
const char *subname = QuestEventSubroutines[evt];
return (perl->SubExists("qst_global_bot", subname));
}
int PerlembParser::EventBot(
QuestEventID evt,
Bot *bot,
Mob *mob,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
return EventCommon(evt, 0, data.c_str(), bot, nullptr, nullptr, mob, extra_data, false, extra_pointers);
}
int PerlembParser::EventGlobalBot(
QuestEventID evt,
Bot *bot,
Mob *mob,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
return EventCommon(evt, 0, data.c_str(), bot, nullptr, nullptr, mob, extra_data, true, extra_pointers);
}
#endif
#endif