mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-03 00:52:25 +00:00
- License was intended to be GPLv3 per earlier commit of GPLv3 LICENSE FILE - This is confirmed by the inclusion of libraries that are incompatible with GPLv2 - This is also confirmed by KLS and the agreement of KLS's predecessors - Added GPLv3 license headers to the compilable source files - Removed Folly licensing in strings.h since the string functions do not match the Folly functions and are standard functions - this must have been left over from previous implementations - Removed individual contributor license headers since the project has been under the "developer" mantle for many years - Removed comments on files that were previously automatically generated since they've been manually modified multiple times and there are no automatic scripts referencing them (removed in 2023)
1886 lines
47 KiB
C++
1886 lines
47 KiB
C++
/* EQEmu: EQEmulator
|
|
|
|
Copyright (C) 2001-2026 EQEmu Development Team
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "quest_parser_collection.h"
|
|
|
|
#include "common/features.h"
|
|
#include "common/file.h"
|
|
#include "common/misc_functions.h"
|
|
#include "common/path_manager.h"
|
|
#include "common/repositories/perl_event_export_settings_repository.h"
|
|
#include "zone/quest_interface.h"
|
|
#include "zone/questmgr.h"
|
|
#include "zone/zone.h"
|
|
|
|
#include <cstdio>
|
|
|
|
// an encounter can register events before the object is loaded
|
|
// examples
|
|
// eq.register_npc_event(Event.death_complete, -1, AllDeath);
|
|
// eq.register_npc_event(Event.say, -1, All_Say);
|
|
const std::string ENCOUNTER_NO_ENTITY_ID = "-1";
|
|
|
|
extern Zone* zone;
|
|
extern void MapOpcodes();
|
|
|
|
QuestParserCollection::QuestParserCollection()
|
|
{
|
|
_player_quest_status = QuestUnloaded;
|
|
_global_player_quest_status = QuestUnloaded;
|
|
_global_npc_quest_status = QuestUnloaded;
|
|
_bot_quest_status = QuestUnloaded;
|
|
_global_bot_quest_status = QuestUnloaded;
|
|
_merc_quest_status = QuestUnloaded;
|
|
_global_merc_quest_status = QuestUnloaded;
|
|
_zone_quest_status = QuestUnloaded;
|
|
_global_zone_quest_status = QuestUnloaded;
|
|
}
|
|
|
|
QuestParserCollection::~QuestParserCollection() { }
|
|
|
|
void QuestParserCollection::RegisterQuestInterface(QuestInterface* qi, std::string ext)
|
|
{
|
|
_interfaces[qi->GetIdentifier()] = qi;
|
|
_extensions[qi->GetIdentifier()] = ext;
|
|
_load_precedence.push_back(qi);
|
|
}
|
|
|
|
void QuestParserCollection::ClearInterfaces()
|
|
{
|
|
_interfaces.clear();
|
|
_extensions.clear();
|
|
_load_precedence.clear();
|
|
}
|
|
|
|
void QuestParserCollection::AddVar(std::string name, std::string val)
|
|
{
|
|
for (const auto& e: _load_precedence) {
|
|
e->AddVar(name, val);
|
|
}
|
|
}
|
|
|
|
void QuestParserCollection::Init()
|
|
{
|
|
for (const auto& e: _load_precedence) {
|
|
e->Init();
|
|
}
|
|
}
|
|
|
|
void QuestParserCollection::ReloadQuests(bool reset_timers)
|
|
{
|
|
if (reset_timers) {
|
|
quest_manager.ClearAllTimers();
|
|
zone->StopAllTimers();
|
|
}
|
|
|
|
MapOpcodes();
|
|
|
|
_npc_quest_status.clear();
|
|
|
|
_player_quest_status = QuestUnloaded;
|
|
_global_player_quest_status = QuestUnloaded;
|
|
_global_npc_quest_status = QuestUnloaded;
|
|
_bot_quest_status = QuestUnloaded;
|
|
_global_bot_quest_status = QuestUnloaded;
|
|
_merc_quest_status = QuestUnloaded;
|
|
_global_merc_quest_status = QuestUnloaded;
|
|
_zone_quest_status = QuestUnloaded;
|
|
_global_zone_quest_status = QuestUnloaded;
|
|
|
|
_spell_quest_status.clear();
|
|
_item_quest_status.clear();
|
|
_encounter_quest_status.clear();
|
|
|
|
for (const auto& e: _load_precedence) {
|
|
e->ReloadQuests();
|
|
}
|
|
}
|
|
|
|
void QuestParserCollection::RemoveEncounter(const std::string& name)
|
|
{
|
|
for (const auto& e: _load_precedence) {
|
|
e->RemoveEncounter(name);
|
|
}
|
|
}
|
|
|
|
bool QuestParserCollection::HasQuestSub(uint32 npc_id, QuestEventID event_id)
|
|
{
|
|
return (
|
|
HasQuestSubLocal(npc_id, event_id) ||
|
|
HasQuestSubGlobal(event_id) ||
|
|
NPCHasEncounterSub(npc_id, event_id)
|
|
);
|
|
}
|
|
|
|
bool QuestParserCollection::NPCHasEncounterSub(uint32 npc_id, QuestEventID event_id)
|
|
{
|
|
return HasEncounterSub(event_id, fmt::format("npc_{}", npc_id)) || HasEncounterSub(event_id, "npc_" + ENCOUNTER_NO_ENTITY_ID);
|
|
}
|
|
|
|
bool QuestParserCollection::HasQuestSubLocal(uint32 npc_id, QuestEventID event_id)
|
|
{
|
|
auto iter = _npc_quest_status.find(npc_id);
|
|
|
|
if (iter != _npc_quest_status.end()) {
|
|
if (iter->second != QuestFailedToLoad) { //loaded or failed to load
|
|
auto qiter = _interfaces.find(iter->second);
|
|
if (qiter->second->HasQuestSub(npc_id, event_id)) {
|
|
return true;
|
|
}
|
|
}
|
|
} else {
|
|
std::string filename;
|
|
auto qi = GetQIByNPCQuest(npc_id, filename);
|
|
|
|
if (qi) {
|
|
_npc_quest_status[npc_id] = qi->GetIdentifier();
|
|
|
|
qi->LoadNPCScript(filename, npc_id);
|
|
if (qi->HasQuestSub(npc_id, event_id)) {
|
|
return true;
|
|
}
|
|
} else {
|
|
_npc_quest_status[npc_id] = QuestFailedToLoad;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QuestParserCollection::HasQuestSubGlobal(QuestEventID event_id)
|
|
{
|
|
if (_global_npc_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByGlobalNPCQuest(filename);
|
|
|
|
if (qi) {
|
|
qi->LoadGlobalNPCScript(filename);
|
|
_global_npc_quest_status = qi->GetIdentifier();
|
|
if (qi->HasGlobalQuestSub(event_id)) {
|
|
return true;
|
|
}
|
|
}
|
|
} else {
|
|
if (_global_npc_quest_status != QuestFailedToLoad) {
|
|
auto qiter = _interfaces.find(_global_npc_quest_status);
|
|
if (qiter->second->HasGlobalQuestSub(event_id)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QuestParserCollection::PlayerHasQuestSub(QuestEventID event_id)
|
|
{
|
|
return (
|
|
PlayerHasQuestSubLocal(event_id) ||
|
|
PlayerHasQuestSubGlobal(event_id) ||
|
|
PlayerHasEncounterSub(event_id)
|
|
);
|
|
}
|
|
|
|
bool QuestParserCollection::PlayerHasEncounterSub(QuestEventID event_id)
|
|
{
|
|
return HasEncounterSub(event_id, "player");
|
|
}
|
|
|
|
bool QuestParserCollection::PlayerHasQuestSubLocal(QuestEventID event_id)
|
|
{
|
|
if (_player_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByPlayerQuest(filename);
|
|
|
|
if (qi) {
|
|
_player_quest_status = qi->GetIdentifier();
|
|
qi->LoadPlayerScript(filename);
|
|
return qi->PlayerHasQuestSub(event_id);
|
|
}
|
|
} else if (_player_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_player_quest_status);
|
|
return iter->second->PlayerHasQuestSub(event_id);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QuestParserCollection::PlayerHasQuestSubGlobal(QuestEventID event_id)
|
|
{
|
|
if (_global_player_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByGlobalPlayerQuest(filename);
|
|
|
|
if (qi) {
|
|
_global_player_quest_status = qi->GetIdentifier();
|
|
qi->LoadGlobalPlayerScript(filename);
|
|
return qi->GlobalPlayerHasQuestSub(event_id);
|
|
}
|
|
} else if (_global_player_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_global_player_quest_status);
|
|
return iter->second->GlobalPlayerHasQuestSub(event_id);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QuestParserCollection::SpellHasEncounterSub(uint32 spell_id, QuestEventID event_id)
|
|
{
|
|
return HasEncounterSub(event_id, fmt::format("spell_{}", spell_id)) ||
|
|
HasEncounterSub(event_id, "spell_" + ENCOUNTER_NO_ENTITY_ID);
|
|
}
|
|
|
|
bool QuestParserCollection::SpellHasQuestSub(uint32 spell_id, QuestEventID event_id)
|
|
{
|
|
if (SpellHasEncounterSub(spell_id, event_id)) {
|
|
return true;
|
|
}
|
|
|
|
auto iter = _spell_quest_status.find(spell_id);
|
|
if (iter != _spell_quest_status.end()) {
|
|
//loaded or failed to load
|
|
if (iter->second != QuestFailedToLoad) {
|
|
auto qiter = _interfaces.find(iter->second);
|
|
return qiter->second->SpellHasQuestSub(spell_id, event_id);
|
|
}
|
|
} else if (_spell_quest_status[spell_id] != QuestFailedToLoad) {
|
|
std::string filename;
|
|
auto qi = GetQIBySpellQuest(spell_id, filename);
|
|
|
|
if (qi) {
|
|
_spell_quest_status[spell_id] = qi->GetIdentifier();
|
|
qi->LoadSpellScript(filename, spell_id);
|
|
return qi->SpellHasQuestSub(spell_id, event_id);
|
|
} else {
|
|
_spell_quest_status[spell_id] = QuestFailedToLoad;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QuestParserCollection::ItemHasEncounterSub(EQ::ItemInstance *inst, QuestEventID event_id)
|
|
{
|
|
if (inst) {
|
|
return HasEncounterSub(event_id, fmt::format("item_{}", inst->GetID())) ||
|
|
HasEncounterSub(event_id, "item_" + ENCOUNTER_NO_ENTITY_ID);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QuestParserCollection::ItemHasQuestSub(EQ::ItemInstance* inst, QuestEventID event_id)
|
|
{
|
|
if (!inst) {
|
|
return false;
|
|
}
|
|
|
|
if (ItemHasEncounterSub(inst, event_id)) {
|
|
return true;
|
|
}
|
|
|
|
std::string item_script;
|
|
if (inst->GetItem()->ScriptFileID != 0) {
|
|
item_script = fmt::format(
|
|
"script_{}",
|
|
inst->GetItem()->ScriptFileID
|
|
);
|
|
} else if (strlen(inst->GetItem()->CharmFile) > 0) {
|
|
item_script = inst->GetItem()->CharmFile;
|
|
} else {
|
|
item_script = std::to_string(inst->GetID());
|
|
}
|
|
|
|
uint32 item_id = inst->GetID();
|
|
auto iter = _item_quest_status.find(item_id);
|
|
if (iter != _item_quest_status.end()) {
|
|
//loaded or failed to load
|
|
if (iter->second != QuestFailedToLoad) {
|
|
auto qiter = _interfaces.find(iter->second);
|
|
return qiter->second->ItemHasQuestSub(inst, event_id);
|
|
}
|
|
} else {
|
|
std::string filename;
|
|
auto qi = GetQIByItemQuest(item_script, filename);
|
|
if (qi) {
|
|
_item_quest_status[item_id] = qi->GetIdentifier();
|
|
qi->LoadItemScript(filename, inst);
|
|
return qi->ItemHasQuestSub(inst, event_id);
|
|
} else {
|
|
_item_quest_status[item_id] = QuestFailedToLoad;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QuestParserCollection::HasEncounterSub(QuestEventID event_id, const std::string& package_name)
|
|
{
|
|
for (auto it = _encounter_quest_status.begin(); it != _encounter_quest_status.end(); ++it) {
|
|
if (it->second != QuestFailedToLoad) {
|
|
auto qit = _interfaces.find(it->second);
|
|
if (qit != _interfaces.end() && qit->second->HasEncounterSub(package_name, event_id)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QuestParserCollection::BotHasQuestSubLocal(QuestEventID event_id)
|
|
{
|
|
if (_bot_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByBotQuest(filename);
|
|
|
|
if (qi) {
|
|
_bot_quest_status = qi->GetIdentifier();
|
|
qi->LoadBotScript(filename);
|
|
return qi->BotHasQuestSub(event_id);
|
|
}
|
|
} else if (_bot_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_bot_quest_status);
|
|
return iter->second->BotHasQuestSub(event_id);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QuestParserCollection::BotHasQuestSubGlobal(QuestEventID event_id)
|
|
{
|
|
if (_global_bot_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByGlobalBotQuest(filename);
|
|
|
|
if (qi) {
|
|
_global_bot_quest_status = qi->GetIdentifier();
|
|
qi->LoadGlobalBotScript(filename);
|
|
return qi->GlobalBotHasQuestSub(event_id);
|
|
}
|
|
} else if (_global_bot_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_global_bot_quest_status);
|
|
return iter->second->GlobalBotHasQuestSub(event_id);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QuestParserCollection::BotHasQuestSub(QuestEventID event_id)
|
|
{
|
|
return BotHasQuestSubLocal(event_id) || BotHasQuestSubGlobal(event_id);
|
|
}
|
|
|
|
bool QuestParserCollection::MercHasQuestSubLocal(QuestEventID event_id)
|
|
{
|
|
if (_merc_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByMercQuest(filename);
|
|
|
|
if (qi) {
|
|
_merc_quest_status = qi->GetIdentifier();
|
|
qi->LoadMercScript(filename);
|
|
return qi->MercHasQuestSub(event_id);
|
|
}
|
|
} else if (_merc_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_merc_quest_status);
|
|
return iter->second->MercHasQuestSub(event_id);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QuestParserCollection::MercHasQuestSubGlobal(QuestEventID event_id)
|
|
{
|
|
if (_global_merc_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByGlobalMercQuest(filename);
|
|
|
|
if (qi) {
|
|
_global_merc_quest_status = qi->GetIdentifier();
|
|
qi->LoadGlobalMercScript(filename);
|
|
return qi->GlobalMercHasQuestSub(event_id);
|
|
}
|
|
} else if (_global_merc_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_global_merc_quest_status);
|
|
return iter->second->GlobalMercHasQuestSub(event_id);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QuestParserCollection::MercHasQuestSub(QuestEventID event_id)
|
|
{
|
|
return MercHasQuestSubLocal(event_id) || MercHasQuestSubGlobal(event_id);
|
|
}
|
|
|
|
bool QuestParserCollection::ZoneHasQuestSubLocal(QuestEventID event_id)
|
|
{
|
|
if (_zone_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByZoneQuest(filename);
|
|
|
|
if (qi) {
|
|
_zone_quest_status = qi->GetIdentifier();
|
|
qi->LoadZoneScript(filename);
|
|
return qi->ZoneHasQuestSub(event_id);
|
|
}
|
|
} else if (_zone_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_zone_quest_status);
|
|
return iter->second->ZoneHasQuestSub(event_id);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QuestParserCollection::ZoneHasQuestSubGlobal(QuestEventID event_id)
|
|
{
|
|
if (_global_zone_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByGlobalZoneQuest(filename);
|
|
|
|
if (qi) {
|
|
_global_zone_quest_status = qi->GetIdentifier();
|
|
qi->LoadGlobalZoneScript(filename);
|
|
return qi->GlobalZoneHasQuestSub(event_id);
|
|
}
|
|
} else if (_global_zone_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_global_zone_quest_status);
|
|
return iter->second->GlobalZoneHasQuestSub(event_id);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QuestParserCollection::ZoneHasQuestSub(QuestEventID event_id)
|
|
{
|
|
return ZoneHasQuestSubLocal(event_id) || ZoneHasQuestSubGlobal(event_id);
|
|
}
|
|
|
|
int QuestParserCollection::EventNPC(
|
|
QuestEventID event_id,
|
|
NPC* npc,
|
|
Mob* init,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (npc->IsResumedFromZoneSuspend() && npc->IsQueuedForCorpse()) {
|
|
return 0;
|
|
}
|
|
|
|
const int local_return = EventNPCLocal(event_id, npc, init, data, extra_data, extra_pointers);
|
|
const int global_return = EventNPCGlobal(event_id, npc, init, data, extra_data, extra_pointers);
|
|
const int default_return = DispatchEventNPC(event_id, npc, init, data, extra_data, extra_pointers);
|
|
|
|
if (local_return != 0) {
|
|
return local_return;
|
|
} else if (global_return != 0) {
|
|
return global_return;
|
|
} else if (default_return != 0) {
|
|
return default_return;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventNPCLocal(
|
|
QuestEventID event_id,
|
|
NPC* npc,
|
|
Mob* init,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
auto iter = _npc_quest_status.find(npc->GetNPCTypeID());
|
|
if (iter != _npc_quest_status.end()) {
|
|
//loaded or failed to load
|
|
if (iter->second != QuestFailedToLoad) {
|
|
auto qiter = _interfaces.find(iter->second);
|
|
return qiter->second->EventNPC(event_id, npc, init, data, extra_data, extra_pointers);
|
|
}
|
|
} else if (_npc_quest_status[npc->GetNPCTypeID()] != QuestFailedToLoad) {
|
|
std::string filename;
|
|
auto qi = GetQIByNPCQuest(npc->GetNPCTypeID(), filename);
|
|
|
|
if (qi) {
|
|
_npc_quest_status[npc->GetNPCTypeID()] = qi->GetIdentifier();
|
|
qi->LoadNPCScript(filename, npc->GetNPCTypeID());
|
|
return qi->EventNPC(event_id, npc, init, data, extra_data, extra_pointers);
|
|
} else {
|
|
_npc_quest_status[npc->GetNPCTypeID()] = QuestFailedToLoad;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventNPCGlobal(
|
|
QuestEventID event_id,
|
|
NPC* npc,
|
|
Mob* init,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (_global_npc_quest_status != QuestUnloaded && _global_npc_quest_status != QuestFailedToLoad) {
|
|
auto qiter = _interfaces.find(_global_npc_quest_status);
|
|
return qiter->second->EventGlobalNPC(event_id, npc, init, data, extra_data, extra_pointers);
|
|
} else if (_global_npc_quest_status != QuestFailedToLoad) {
|
|
std::string filename;
|
|
auto qi = GetQIByGlobalNPCQuest(filename);
|
|
|
|
if (qi) {
|
|
_global_npc_quest_status = qi->GetIdentifier();
|
|
qi->LoadGlobalNPCScript(filename);
|
|
return qi->EventGlobalNPC(event_id, npc, init, data, extra_data, extra_pointers);
|
|
} else {
|
|
_global_npc_quest_status = QuestFailedToLoad;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventPlayer(
|
|
QuestEventID event_id,
|
|
Client* client,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
const int local_return = EventPlayerLocal(event_id, client, data, extra_data, extra_pointers);
|
|
const int global_return = EventPlayerGlobal(event_id, client, data, extra_data, extra_pointers);
|
|
const int default_return = DispatchEventPlayer(event_id, client, data, extra_data, extra_pointers);
|
|
|
|
if (local_return != 0) {
|
|
return local_return;
|
|
} else if (global_return != 0) {
|
|
return global_return;
|
|
} else if (default_return != 0) {
|
|
return default_return;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventPlayerLocal(
|
|
QuestEventID event_id,
|
|
Client* client,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (_player_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByPlayerQuest(filename);
|
|
|
|
if (qi) {
|
|
_player_quest_status = qi->GetIdentifier();
|
|
qi->LoadPlayerScript(filename);
|
|
return qi->EventPlayer(event_id, client, data, extra_data, extra_pointers);
|
|
}
|
|
} else {
|
|
if (_player_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_player_quest_status);
|
|
return iter->second->EventPlayer(event_id, client, data, extra_data, extra_pointers);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventPlayerGlobal(
|
|
QuestEventID event_id,
|
|
Client* client,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (_global_player_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByGlobalPlayerQuest(filename);
|
|
|
|
if (qi) {
|
|
_global_player_quest_status = qi->GetIdentifier();
|
|
qi->LoadGlobalPlayerScript(filename);
|
|
return qi->EventGlobalPlayer(event_id, client, data, extra_data, extra_pointers);
|
|
}
|
|
} else {
|
|
if (_global_player_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_global_player_quest_status);
|
|
return iter->second->EventGlobalPlayer(event_id, client, data, extra_data, extra_pointers);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventItem(
|
|
QuestEventID event_id,
|
|
Client* client,
|
|
EQ::ItemInstance* inst,
|
|
Mob* mob,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (!inst) {
|
|
return 0;
|
|
}
|
|
|
|
std::string item_script;
|
|
if (inst->GetItem()->ScriptFileID != 0) {
|
|
item_script = fmt::format(
|
|
"script_{}",
|
|
inst->GetItem()->ScriptFileID
|
|
);
|
|
} else if (strlen(inst->GetItem()->CharmFile) > 0) {
|
|
item_script = inst->GetItem()->CharmFile;
|
|
} else {
|
|
item_script = std::to_string(inst->GetID());
|
|
}
|
|
|
|
uint32 item_id = inst->GetID();
|
|
auto iter = _item_quest_status.find(item_id);
|
|
if (iter != _item_quest_status.end()) {
|
|
//loaded or failed to load
|
|
if (iter->second != QuestFailedToLoad) {
|
|
auto qiter = _interfaces.find(iter->second);
|
|
int ret = DispatchEventItem(event_id, client, inst, mob, data, extra_data, extra_pointers);
|
|
int i = qiter->second->EventItem(event_id, client, inst, mob, data, extra_data, extra_pointers);
|
|
if (i != 0) {
|
|
ret = i;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
return DispatchEventItem(event_id, client, inst, mob, data, extra_data, extra_pointers);
|
|
} else if (_item_quest_status[item_id] != QuestFailedToLoad) {
|
|
std::string filename;
|
|
auto qi = GetQIByItemQuest(item_script, filename);
|
|
|
|
if (qi) {
|
|
_item_quest_status[item_id] = qi->GetIdentifier();
|
|
|
|
qi->LoadItemScript(filename, inst);
|
|
|
|
int ret = DispatchEventItem(
|
|
event_id,
|
|
client,
|
|
inst,
|
|
mob,
|
|
data,
|
|
extra_data,
|
|
extra_pointers
|
|
);
|
|
|
|
int i = qi->EventItem(event_id, client, inst, mob, data, extra_data, extra_pointers);
|
|
if (i != 0) {
|
|
ret = i;
|
|
}
|
|
|
|
return ret;
|
|
} else {
|
|
_item_quest_status[item_id] = QuestFailedToLoad;
|
|
return DispatchEventItem(event_id, client, inst, mob, data, extra_data, extra_pointers);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventSpell(
|
|
QuestEventID event_id,
|
|
Mob* mob,
|
|
Client* client,
|
|
uint32 spell_id,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
auto iter = _spell_quest_status.find(spell_id);
|
|
if (iter != _spell_quest_status.end()) {
|
|
//loaded or failed to load
|
|
if (iter->second != QuestFailedToLoad) {
|
|
auto qi = _interfaces.find(iter->second);
|
|
int ret = DispatchEventSpell(event_id, mob, client, spell_id, data, extra_data, extra_pointers);
|
|
int i = qi->second->EventSpell(event_id, mob, client, spell_id, data, extra_data, extra_pointers);
|
|
if (i != 0) {
|
|
ret = i;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
return DispatchEventSpell(event_id, mob, client, spell_id, data, extra_data, extra_pointers);
|
|
} else if (_spell_quest_status[spell_id] != QuestFailedToLoad) {
|
|
std::string filename;
|
|
auto qi = GetQIBySpellQuest(spell_id, filename);
|
|
|
|
if (qi) {
|
|
_spell_quest_status[spell_id] = qi->GetIdentifier();
|
|
|
|
qi->LoadSpellScript(filename, spell_id);
|
|
|
|
int ret = DispatchEventSpell(
|
|
event_id,
|
|
mob,
|
|
client,
|
|
spell_id,
|
|
data,
|
|
extra_data,
|
|
extra_pointers
|
|
);
|
|
|
|
int i = qi->EventSpell(
|
|
event_id,
|
|
mob,
|
|
client,
|
|
spell_id,
|
|
data,
|
|
extra_data,
|
|
extra_pointers
|
|
);
|
|
if (i != 0) {
|
|
ret = i;
|
|
}
|
|
|
|
return ret;
|
|
} else {
|
|
_spell_quest_status[spell_id] = QuestFailedToLoad;
|
|
return DispatchEventSpell(event_id, mob, client, spell_id, data, extra_data, extra_pointers);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventEncounter(
|
|
QuestEventID event_id,
|
|
std::string encounter_name,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
auto iter = _encounter_quest_status.find(encounter_name);
|
|
if (iter != _encounter_quest_status.end()) {
|
|
if (iter->second != QuestFailedToLoad) { // Loaded or failed to load
|
|
auto qiter = _interfaces.find(iter->second);
|
|
return qiter->second->EventEncounter(event_id, encounter_name, data, extra_data, extra_pointers);
|
|
}
|
|
} else if (_encounter_quest_status[encounter_name] != QuestFailedToLoad) {
|
|
std::string filename;
|
|
auto qi = GetQIByEncounterQuest(encounter_name, filename);
|
|
|
|
if (qi) {
|
|
_encounter_quest_status[encounter_name] = qi->GetIdentifier();
|
|
qi->LoadEncounterScript(filename, encounter_name);
|
|
return qi->EventEncounter(event_id, encounter_name, data, extra_data, extra_pointers);
|
|
} else {
|
|
_encounter_quest_status[encounter_name] = QuestFailedToLoad;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventBot(
|
|
QuestEventID event_id,
|
|
Bot* bot,
|
|
Mob* init,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
const int local_return = EventBotLocal(event_id, bot, init, data, extra_data, extra_pointers);
|
|
const int global_return = EventBotGlobal(event_id, bot, init, data, extra_data, extra_pointers);
|
|
const int default_return = DispatchEventBot(event_id, bot, init, data, extra_data, extra_pointers);
|
|
|
|
if (local_return != 0) {
|
|
return local_return;
|
|
} else if (global_return != 0) {
|
|
return global_return;
|
|
} else if (default_return != 0) {
|
|
return default_return;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventBotLocal(
|
|
QuestEventID event_id,
|
|
Bot* bot,
|
|
Mob* init,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (_bot_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByBotQuest(filename);
|
|
|
|
if (qi) {
|
|
_bot_quest_status = qi->GetIdentifier();
|
|
qi->LoadBotScript(filename);
|
|
return qi->EventBot(event_id, bot, init, data, extra_data, extra_pointers);
|
|
}
|
|
} else {
|
|
if (_bot_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_bot_quest_status);
|
|
return iter->second->EventBot(event_id, bot, init, data, extra_data, extra_pointers);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventBotGlobal(
|
|
QuestEventID event_id,
|
|
Bot* bot,
|
|
Mob* init,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (_global_bot_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByGlobalBotQuest(filename);
|
|
|
|
if (qi) {
|
|
_global_bot_quest_status = qi->GetIdentifier();
|
|
qi->LoadGlobalBotScript(filename);
|
|
return qi->EventGlobalBot(event_id, bot, init, data, extra_data, extra_pointers);
|
|
}
|
|
} else {
|
|
if (_global_bot_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_global_bot_quest_status);
|
|
return iter->second->EventGlobalBot(event_id, bot, init, data, extra_data, extra_pointers);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventMerc(
|
|
QuestEventID event_id,
|
|
Merc* merc,
|
|
Mob* init,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
const int local_return = EventMercLocal(event_id, merc, init, data, extra_data, extra_pointers);
|
|
const int global_return = EventMercGlobal(event_id, merc, init, data, extra_data, extra_pointers);
|
|
const int default_return = DispatchEventMerc(event_id, merc, init, data, extra_data, extra_pointers);
|
|
|
|
if (local_return != 0) {
|
|
return local_return;
|
|
} else if (global_return != 0) {
|
|
return global_return;
|
|
} else if (default_return != 0) {
|
|
return default_return;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventMercLocal(
|
|
QuestEventID event_id,
|
|
Merc* merc,
|
|
Mob* init,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (_merc_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByMercQuest(filename);
|
|
|
|
if (qi) {
|
|
_merc_quest_status = qi->GetIdentifier();
|
|
qi->LoadMercScript(filename);
|
|
return qi->EventMerc(event_id, merc, init, data, extra_data, extra_pointers);
|
|
}
|
|
} else {
|
|
if (_merc_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_merc_quest_status);
|
|
return iter->second->EventMerc(event_id, merc, init, data, extra_data, extra_pointers);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventMercGlobal(
|
|
QuestEventID event_id,
|
|
Merc* merc,
|
|
Mob* init,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (_global_merc_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByGlobalMercQuest(filename);
|
|
|
|
if (qi) {
|
|
_global_merc_quest_status = qi->GetIdentifier();
|
|
qi->LoadGlobalMercScript(filename);
|
|
return qi->EventGlobalMerc(event_id, merc, init, data, extra_data, extra_pointers);
|
|
}
|
|
} else {
|
|
if (_global_merc_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_global_merc_quest_status);
|
|
return iter->second->EventGlobalMerc(event_id, merc, init, data, extra_data, extra_pointers);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventZone(
|
|
QuestEventID event_id,
|
|
Zone* zone,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
const int local_return = EventZoneLocal(event_id, zone, data, extra_data, extra_pointers);
|
|
const int global_return = EventZoneGlobal(event_id, zone, data, extra_data, extra_pointers);
|
|
const int default_return = DispatchEventZone(event_id, zone, data, extra_data, extra_pointers);
|
|
|
|
if (local_return != 0) {
|
|
return local_return;
|
|
} else if (global_return != 0) {
|
|
return global_return;
|
|
} else if (default_return != 0) {
|
|
return default_return;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventZoneLocal(
|
|
QuestEventID event_id,
|
|
Zone* zone,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (_zone_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByZoneQuest(filename);
|
|
|
|
if (qi) {
|
|
_zone_quest_status = qi->GetIdentifier();
|
|
qi->LoadZoneScript(filename);
|
|
return qi->EventZone(event_id, zone, data, extra_data, extra_pointers);
|
|
}
|
|
} else {
|
|
if (_zone_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_zone_quest_status);
|
|
return iter->second->EventZone(event_id, zone, data, extra_data, extra_pointers);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QuestParserCollection::EventZoneGlobal(
|
|
QuestEventID event_id,
|
|
Zone* zone,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (_global_zone_quest_status == QuestUnloaded) {
|
|
std::string filename;
|
|
auto qi = GetQIByGlobalZoneQuest(filename);
|
|
|
|
if (qi) {
|
|
_global_zone_quest_status = qi->GetIdentifier();
|
|
qi->LoadGlobalZoneScript(filename);
|
|
return qi->EventGlobalZone(event_id, zone, data, extra_data, extra_pointers);
|
|
}
|
|
} else {
|
|
if (_global_zone_quest_status != QuestFailedToLoad) {
|
|
auto iter = _interfaces.find(_global_zone_quest_status);
|
|
return iter->second->EventGlobalZone(event_id, zone, data, extra_data, extra_pointers);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
QuestInterface* QuestParserCollection::GetQIByNPCQuest(uint32 npc_id, std::string& filename)
|
|
{
|
|
if (!zone) {
|
|
return nullptr;
|
|
}
|
|
|
|
const auto npc_type = content_db.LoadNPCTypesData(npc_id);
|
|
if (!npc_type && npc_id != ZONE_CONTROLLER_NPC_ID) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::string npc_name = npc_id == ZONE_CONTROLLER_NPC_ID ? "zone_controller" : npc_type->name;
|
|
|
|
Strings::FindReplace(npc_name, "`", "-");
|
|
|
|
for (auto & dir : PathManager::Instance()->GetQuestPaths()) {
|
|
const std::string& npc_id_and_name = fmt::format(
|
|
"{}_{}",
|
|
npc_name,
|
|
npc_id
|
|
);
|
|
|
|
const std::string& global_path = fmt::format(
|
|
"{}/{}",
|
|
dir,
|
|
QUEST_GLOBAL_DIRECTORY
|
|
);
|
|
|
|
const std::string& zone_path = fmt::format(
|
|
"{}/{}",
|
|
dir,
|
|
zone->GetShortName()
|
|
);
|
|
|
|
const std::string& zone_versioned_path = fmt::format(
|
|
"{}/{}/v{}",
|
|
dir,
|
|
zone->GetShortName(),
|
|
zone->GetInstanceVersion()
|
|
);
|
|
|
|
std::vector<std::string> file_names = {
|
|
fmt::format("{}/{}", zone_versioned_path, npc_id), // Local versioned by NPC ID (./quests/zone/v0/10.ext)
|
|
fmt::format("{}/{}", zone_versioned_path, npc_name), // Local versioned by NPC Name (./quests/zone/v0/name.ext)
|
|
fmt::format("{}/{}", zone_versioned_path, npc_id_and_name), // Local versioned by NPC ID and NPC Name (./quests/zone/v0/10_name.ext)
|
|
fmt::format("{}/{}", zone_path, npc_id), // Local by NPC ID
|
|
fmt::format("{}/{}", zone_path, npc_name), // Local by NPC Name
|
|
fmt::format("{}/{}", zone_path, npc_id_and_name), // Local by NPC ID and NPC Name
|
|
fmt::format("{}/{}", global_path, npc_id), // Global by NPC ID
|
|
fmt::format("{}/{}", global_path, npc_name), // Global by NPC ID
|
|
fmt::format("{}/{}", global_path, npc_id_and_name), // Global by NPC ID and NPC Name
|
|
fmt::format("{}/default", zone_versioned_path), // Zone Versioned Default (./quests/zone/v0/default.ext)
|
|
fmt::format("{}/default", zone_path), // Zone Default
|
|
fmt::format("{}/default", global_path), // Global Default
|
|
};
|
|
|
|
std::string file_name;
|
|
|
|
for (auto & file : file_names) {
|
|
for (auto* e: _load_precedence) {
|
|
file_name = fmt::format(
|
|
"{}.{}",
|
|
file,
|
|
_extensions.find(e->GetIdentifier())->second
|
|
);
|
|
|
|
if (File::Exists(file_name)) {
|
|
filename = file_name;
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QuestInterface* QuestParserCollection::GetQIByPlayerQuest(std::string& filename)
|
|
{
|
|
if (!zone || !zone->IsLoaded()) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (auto & dir : PathManager::Instance()->GetQuestPaths()) {
|
|
const std::string& global_path = fmt::format(
|
|
"{}/{}",
|
|
dir,
|
|
QUEST_GLOBAL_DIRECTORY
|
|
);
|
|
|
|
const std::string& zone_path = fmt::format(
|
|
"{}/{}",
|
|
dir,
|
|
zone->GetShortName()
|
|
);
|
|
|
|
const std::string& zone_versioned_path = fmt::format(
|
|
"{}/{}/v{}",
|
|
dir,
|
|
zone->GetShortName(),
|
|
zone->GetInstanceVersion()
|
|
);
|
|
|
|
std::vector<std::string> file_names = {
|
|
fmt::format("{}/player", zone_versioned_path), // Local by Instance Version ./quests/zone/v0/player.ext
|
|
fmt::format("{}/player_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version
|
|
fmt::format("{}/player", zone_path), // Local
|
|
fmt::format("{}/player", global_path) // Global
|
|
};
|
|
|
|
std::string file_name;
|
|
for (auto & file : file_names) {
|
|
for (auto* e: _load_precedence) {
|
|
file_name = fmt::format(
|
|
"{}.{}",
|
|
file,
|
|
_extensions.find(e->GetIdentifier())->second
|
|
);
|
|
|
|
if (File::Exists(file_name)) {
|
|
filename = file_name;
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QuestInterface* QuestParserCollection::GetQIByGlobalNPCQuest(std::string& filename)
|
|
{
|
|
if (!zone) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::string file_name;
|
|
|
|
for (auto & dir : PathManager::Instance()->GetQuestPaths()) {
|
|
for (auto* e: _load_precedence) {
|
|
file_name = fmt::format(
|
|
"{}/{}/global_npc.{}",
|
|
dir,
|
|
QUEST_GLOBAL_DIRECTORY,
|
|
_extensions.find(e->GetIdentifier())->second
|
|
);
|
|
|
|
if (File::Exists(file_name)) {
|
|
filename = file_name;
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QuestInterface* QuestParserCollection::GetQIByGlobalPlayerQuest(std::string& filename)
|
|
{
|
|
if (!zone) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::string file_name;
|
|
for (auto & dir : PathManager::Instance()->GetQuestPaths()) {
|
|
for (auto* e: _load_precedence) {
|
|
file_name = fmt::format(
|
|
"{}/{}/global_player.{}",
|
|
dir,
|
|
QUEST_GLOBAL_DIRECTORY,
|
|
_extensions.find(e->GetIdentifier())->second
|
|
);
|
|
|
|
if (File::Exists(file_name)) {
|
|
filename = file_name;
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QuestInterface* QuestParserCollection::GetQIBySpellQuest(uint32 spell_id, std::string& filename)
|
|
{
|
|
if (!zone) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (auto & dir : PathManager::Instance()->GetQuestPaths()) {
|
|
const std::string& global_path = fmt::format(
|
|
"{}/{}/spells",
|
|
dir,
|
|
QUEST_GLOBAL_DIRECTORY
|
|
);
|
|
|
|
const std::string& zone_path = fmt::format(
|
|
"{}/{}/spells",
|
|
dir,
|
|
zone->GetShortName()
|
|
);
|
|
|
|
const std::string& zone_versioned_path = fmt::format(
|
|
"{}/{}/v{}/spells",
|
|
dir,
|
|
zone->GetShortName(),
|
|
zone->GetInstanceVersion()
|
|
);
|
|
|
|
std::vector<std::string> file_names = {
|
|
fmt::format("{}/{}", zone_versioned_path, spell_id), // Local versioned by Spell ID ./quests/zone/v0/spells/10.ext
|
|
fmt::format("{}/{}", zone_path, spell_id), // Local
|
|
fmt::format("{}/{}", global_path, spell_id), // Global
|
|
fmt::format("{}/default", zone_path), // Local Default
|
|
fmt::format("{}/default", global_path) // Global Default
|
|
};
|
|
|
|
std::string file_name;
|
|
for (auto & file : file_names) {
|
|
for (auto* e: _load_precedence) {
|
|
file_name = fmt::format(
|
|
"{}.{}",
|
|
file,
|
|
_extensions.find(e->GetIdentifier())->second
|
|
);
|
|
|
|
if (File::Exists(file_name)) {
|
|
filename = file_name;
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QuestInterface* QuestParserCollection::GetQIByItemQuest(std::string item_script, std::string& filename)
|
|
{
|
|
if (!zone) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (auto & dir : PathManager::Instance()->GetQuestPaths()) {
|
|
const std::string& global_path = fmt::format(
|
|
"{}/{}/items",
|
|
dir,
|
|
QUEST_GLOBAL_DIRECTORY
|
|
);
|
|
|
|
const std::string& zone_path = fmt::format(
|
|
"{}/{}/items",
|
|
dir,
|
|
zone->GetShortName()
|
|
);
|
|
|
|
const std::string& zone_versioned_path = fmt::format(
|
|
"{}/{}/v{}/items",
|
|
dir,
|
|
zone->GetShortName(),
|
|
zone->GetInstanceVersion()
|
|
);
|
|
|
|
std::vector<std::string> file_names = {
|
|
fmt::format("{}/{}", zone_versioned_path, item_script), // Local versioned by Item Script ./quests/zone/v0/items/10.ext
|
|
fmt::format("{}/{}", zone_path, item_script), // Local
|
|
fmt::format("{}/{}", global_path, item_script), // Global
|
|
fmt::format("{}/default", zone_path), // Local Default
|
|
fmt::format("{}/default", global_path) // Global Default
|
|
};
|
|
|
|
std::string file_name;
|
|
for (auto & file : file_names) {
|
|
for (auto* e: _load_precedence) {
|
|
file_name = fmt::format(
|
|
"{}.{}",
|
|
file,
|
|
_extensions.find(e->GetIdentifier())->second
|
|
);
|
|
|
|
if (File::Exists(file_name)) {
|
|
filename = file_name;
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QuestInterface* QuestParserCollection::GetQIByEncounterQuest(std::string encounter_name, std::string& filename)
|
|
{
|
|
if (!zone) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (auto & dir : PathManager::Instance()->GetQuestPaths()) {
|
|
const std::string& global_path = fmt::format(
|
|
"{}/{}/encounters",
|
|
dir,
|
|
QUEST_GLOBAL_DIRECTORY
|
|
);
|
|
|
|
const std::string& zone_path = fmt::format(
|
|
"{}/{}/encounters",
|
|
dir,
|
|
zone->GetShortName()
|
|
);
|
|
|
|
const std::string& zone_versioned_path = fmt::format(
|
|
"{}/{}/v{}/encounters",
|
|
dir,
|
|
zone->GetShortName(),
|
|
zone->GetInstanceVersion()
|
|
);
|
|
|
|
std::vector<std::string> file_names = {
|
|
fmt::format("{}/{}", zone_versioned_path, encounter_name), // Local versioned ./quests/zone/v0/encounters/name.ext
|
|
fmt::format("{}/{}", zone_path, encounter_name), // Local
|
|
fmt::format("{}/{}", global_path, encounter_name) // Global
|
|
};
|
|
|
|
std::string file_name;
|
|
for (auto & file : file_names) {
|
|
for (auto* e: _load_precedence) {
|
|
file_name = fmt::format(
|
|
"{}.{}",
|
|
file,
|
|
_extensions.find(e->GetIdentifier())->second
|
|
);
|
|
|
|
if (File::Exists(file_name)) {
|
|
filename = file_name;
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QuestInterface* QuestParserCollection::GetQIByBotQuest(std::string& filename)
|
|
{
|
|
if (!zone || !zone->IsLoaded()) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (auto & dir : PathManager::Instance()->GetQuestPaths()) {
|
|
const std::string& global_path = fmt::format(
|
|
"{}/{}",
|
|
dir,
|
|
QUEST_GLOBAL_DIRECTORY
|
|
);
|
|
|
|
const std::string& zone_path = fmt::format(
|
|
"{}/{}",
|
|
dir,
|
|
zone->GetShortName()
|
|
);
|
|
|
|
const std::string& zone_versioned_path = fmt::format(
|
|
"{}/{}/v{}",
|
|
dir,
|
|
zone->GetShortName(),
|
|
zone->GetInstanceVersion()
|
|
);
|
|
|
|
std::vector<std::string> file_names = {
|
|
fmt::format("{}/bot", zone_versioned_path), // Local versioned by Instance Version ./quests/zone/v0/bot.ext
|
|
fmt::format("{}/bot_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version
|
|
fmt::format("{}/bot", zone_path), // Local
|
|
fmt::format("{}/bot", global_path) // Global
|
|
};
|
|
|
|
std::string file_name;
|
|
for (auto & file : file_names) {
|
|
for (auto* e: _load_precedence) {
|
|
file_name = fmt::format(
|
|
"{}.{}",
|
|
file,
|
|
_extensions.find(e->GetIdentifier())->second
|
|
);
|
|
|
|
if (File::Exists(file_name)) {
|
|
filename = file_name;
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QuestInterface* QuestParserCollection::GetQIByGlobalBotQuest(std::string& filename)
|
|
{
|
|
if (!zone) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::string file_name;
|
|
for (auto & dir : PathManager::Instance()->GetQuestPaths()) {
|
|
for (auto* e: _load_precedence) {
|
|
file_name = fmt::format(
|
|
"{}/{}/global_bot.{}",
|
|
dir,
|
|
QUEST_GLOBAL_DIRECTORY,
|
|
_extensions.find(e->GetIdentifier())->second
|
|
);
|
|
|
|
if (File::Exists(file_name)) {
|
|
filename = file_name;
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QuestInterface* QuestParserCollection::GetQIByMercQuest(std::string& filename)
|
|
{
|
|
if (!zone || !zone->IsLoaded()) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (auto & dir : PathManager::Instance()->GetQuestPaths()) {
|
|
const std::string& global_path = fmt::format(
|
|
"{}/{}",
|
|
dir,
|
|
QUEST_GLOBAL_DIRECTORY
|
|
);
|
|
|
|
const std::string& zone_path = fmt::format(
|
|
"{}/{}",
|
|
dir,
|
|
zone->GetShortName()
|
|
);
|
|
|
|
const std::string& zone_versioned_path = fmt::format(
|
|
"{}/{}/v{}",
|
|
dir,
|
|
zone->GetShortName(),
|
|
zone->GetInstanceVersion()
|
|
);
|
|
|
|
std::vector<std::string> file_names = {
|
|
fmt::format("{}/merc", zone_versioned_path), // Local versioned by Instance Version ./quests/zone/v0/merc.ext
|
|
fmt::format("{}/merc_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version
|
|
fmt::format("{}/merc", zone_path), // Local
|
|
fmt::format("{}/merc", global_path) // Global
|
|
};
|
|
|
|
std::string file_name;
|
|
for (auto & file : file_names) {
|
|
for (auto* e: _load_precedence) {
|
|
file_name = fmt::format(
|
|
"{}.{}",
|
|
file,
|
|
_extensions.find(e->GetIdentifier())->second
|
|
);
|
|
|
|
if (File::Exists(file_name)) {
|
|
filename = file_name;
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QuestInterface* QuestParserCollection::GetQIByGlobalMercQuest(std::string& filename)
|
|
{
|
|
if (!zone) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::string file_name;
|
|
for (auto & dir : PathManager::Instance()->GetQuestPaths()) {
|
|
for (auto* e: _load_precedence) {
|
|
file_name = fmt::format(
|
|
"{}/{}/global_merc.{}",
|
|
dir,
|
|
QUEST_GLOBAL_DIRECTORY,
|
|
_extensions.find(e->GetIdentifier())->second
|
|
);
|
|
|
|
if (File::Exists(file_name)) {
|
|
filename = file_name;
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QuestInterface* QuestParserCollection::GetQIByZoneQuest(std::string& filename)
|
|
{
|
|
if (!zone || !zone->IsLoaded()) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::string file_name;
|
|
for (auto& dir: PathManager::Instance()->GetQuestPaths()) {
|
|
const std::string& global_path = fmt::format(
|
|
"{}/{}",
|
|
dir,
|
|
QUEST_GLOBAL_DIRECTORY
|
|
);
|
|
|
|
const std::string& zone_path = fmt::format(
|
|
"{}/{}",
|
|
dir,
|
|
zone->GetShortName()
|
|
);
|
|
|
|
const std::string& zone_versioned_path = fmt::format(
|
|
"{}/{}/v{}",
|
|
dir,
|
|
zone->GetShortName(),
|
|
zone->GetInstanceVersion()
|
|
);
|
|
|
|
std::vector<std::string> file_names = {
|
|
fmt::format("{}/zone", zone_versioned_path), // Local versioned by Instance Version ./quests/zone/v0/zone.ext
|
|
fmt::format("{}/zone_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version
|
|
fmt::format("{}/zone", zone_path), // Local
|
|
fmt::format("{}/zone", global_path) // Global
|
|
};
|
|
|
|
for (auto& file: file_names) {
|
|
for (auto* e: _load_precedence) {
|
|
file_name = fmt::format(
|
|
"{}.{}",
|
|
file,
|
|
_extensions.find(e->GetIdentifier())->second
|
|
);
|
|
|
|
if (File::Exists(file_name)) {
|
|
filename = file_name;
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QuestInterface* QuestParserCollection::GetQIByGlobalZoneQuest(std::string& filename)
|
|
{
|
|
if (!zone) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::string file_name;
|
|
|
|
for (auto& dir: PathManager::Instance()->GetQuestPaths()) {
|
|
for (auto* e: _load_precedence) {
|
|
file_name = fmt::format(
|
|
"{}/{}/global_zone.{}",
|
|
dir,
|
|
QUEST_GLOBAL_DIRECTORY,
|
|
_extensions.find(e->GetIdentifier())->second
|
|
);
|
|
|
|
if (File::Exists(file_name)) {
|
|
filename = file_name;
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void QuestParserCollection::GetErrors(std::list<std::string>& quest_errors)
|
|
{
|
|
quest_errors.clear();
|
|
|
|
for (const auto& e: _load_precedence) {
|
|
e->GetErrors(quest_errors);
|
|
}
|
|
}
|
|
|
|
int QuestParserCollection::DispatchEventNPC(
|
|
QuestEventID event_id,
|
|
NPC* npc,
|
|
Mob* init,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
int ret = 0;
|
|
|
|
for (const auto& e: _load_precedence) {
|
|
const int i = e->DispatchEventNPC(event_id, npc, init, data, extra_data, extra_pointers);
|
|
if (i != 0) {
|
|
ret = i;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int QuestParserCollection::DispatchEventPlayer(
|
|
QuestEventID event_id,
|
|
Client* client,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
int ret = 0;
|
|
|
|
for (const auto& e: _load_precedence) {
|
|
const int i = e->DispatchEventPlayer(event_id, client, data, extra_data, extra_pointers);
|
|
if (i != 0) {
|
|
ret = i;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int QuestParserCollection::DispatchEventItem(
|
|
QuestEventID event_id,
|
|
Client* client,
|
|
EQ::ItemInstance* inst,
|
|
Mob* mob,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
int ret = 0;
|
|
|
|
for (const auto& e: _load_precedence) {
|
|
const int i = e->DispatchEventItem(event_id, client, inst, mob, data, extra_data, extra_pointers);
|
|
if (i != 0) {
|
|
ret = i;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int QuestParserCollection::DispatchEventSpell(
|
|
QuestEventID event_id,
|
|
Mob* mob,
|
|
Client* client,
|
|
uint32 spell_id,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
int ret = 0;
|
|
|
|
for (const auto& e: _load_precedence) {
|
|
const int i = e->DispatchEventSpell(event_id, mob, client, spell_id, data, extra_data, extra_pointers);
|
|
if (i != 0) {
|
|
ret = i;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int QuestParserCollection::DispatchEventBot(
|
|
QuestEventID event_id,
|
|
Bot* bot,
|
|
Mob* init,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
int ret = 0;
|
|
|
|
for (const auto& e: _load_precedence) {
|
|
int i = e->DispatchEventBot(event_id, bot, init, data, extra_data, extra_pointers);
|
|
if (i != 0) {
|
|
ret = i;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int QuestParserCollection::DispatchEventMerc(
|
|
QuestEventID event_id,
|
|
Merc* merc,
|
|
Mob* init,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
int ret = 0;
|
|
|
|
for (const auto& e: _load_precedence) {
|
|
int i = e->DispatchEventMerc(event_id, merc, init, data, extra_data, extra_pointers);
|
|
if (i != 0) {
|
|
ret = i;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int QuestParserCollection::DispatchEventZone(
|
|
QuestEventID event_id,
|
|
Zone* zone,
|
|
std::string data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
int ret = 0;
|
|
|
|
for (const auto& e: _load_precedence) {
|
|
int i = e->DispatchEventZone(event_id, zone, data, extra_data, extra_pointers);
|
|
if (i != 0) {
|
|
ret = i;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void QuestParserCollection::LoadPerlEventExportSettings(PerlEventExportSettings* s)
|
|
{
|
|
for (int i = 0; i < _LargestEventID; i++) {
|
|
s[i].qglobals = 1;
|
|
s[i].mob = 1;
|
|
s[i].zone = 1;
|
|
s[i].item = 1;
|
|
s[i].event_variables = 1;
|
|
}
|
|
|
|
const auto& l = PerlEventExportSettingsRepository::All(database);
|
|
|
|
for (const auto& e: l) {
|
|
s[e.event_id].qglobals = e.export_qglobals;
|
|
s[e.event_id].mob = e.export_mob;
|
|
s[e.event_id].zone = e.export_zone;
|
|
s[e.event_id].item = e.export_item;
|
|
s[e.event_id].event_variables = e.export_event;
|
|
}
|
|
|
|
LogInfo("Loaded [{}] Perl Event Export Settings", l.size());
|
|
}
|
|
|
|
int QuestParserCollection::EventBotMerc(
|
|
QuestEventID event_id,
|
|
Mob* e,
|
|
Mob* init,
|
|
std::function<std::string()> lazy_data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (e->IsBot() && BotHasQuestSub(event_id)) {
|
|
return EventBot(event_id, e->CastToBot(), init, lazy_data(), extra_data, extra_pointers);
|
|
} else if (e->IsMerc() && MercHasQuestSub(event_id)) {
|
|
return EventMerc(event_id, e->CastToMerc(), init, lazy_data(), extra_data, extra_pointers);
|
|
}
|
|
|
|
return false; // No quest subscription found
|
|
}
|
|
|
|
int QuestParserCollection::EventMercNPC(
|
|
QuestEventID event_id,
|
|
Mob* e,
|
|
Mob* init,
|
|
std::function<std::string()> lazy_data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (e->IsMerc() && MercHasQuestSub(event_id)) {
|
|
return EventMerc(event_id, e->CastToMerc(), init, lazy_data(), extra_data, extra_pointers);
|
|
} else if (e->IsNPC() && HasQuestSub(e->GetNPCTypeID(), event_id)) {
|
|
return EventNPC(event_id, e->CastToNPC(), init, lazy_data(), extra_data, extra_pointers);
|
|
}
|
|
|
|
return false; // No quest subscription found
|
|
}
|
|
|
|
int QuestParserCollection::EventBotMercNPC(
|
|
QuestEventID event_id,
|
|
Mob* e,
|
|
Mob* init,
|
|
std::function<std::string()> lazy_data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (e->IsBot() && BotHasQuestSub(event_id)) {
|
|
return EventBot(event_id, e->CastToBot(), init, lazy_data(), extra_data, extra_pointers);
|
|
} else if (e->IsMerc() && MercHasQuestSub(event_id)) {
|
|
return EventMerc(event_id, e->CastToMerc(), init, lazy_data(), extra_data, extra_pointers);
|
|
} else if (e->IsNPC() && HasQuestSub(e->GetNPCTypeID(), event_id)) {
|
|
return EventNPC(event_id, e->CastToNPC(), init, lazy_data(), extra_data, extra_pointers);
|
|
}
|
|
|
|
return false; // No quest subscription found
|
|
}
|
|
|
|
int QuestParserCollection::EventMob(
|
|
QuestEventID event_id,
|
|
Mob* e,
|
|
Mob* init,
|
|
std::function<std::string()> lazy_data,
|
|
uint32 extra_data,
|
|
std::vector<std::any>* extra_pointers
|
|
)
|
|
{
|
|
if (e->IsClient() && PlayerHasQuestSub(event_id)) {
|
|
return EventPlayer(event_id, e->CastToClient(), lazy_data(), extra_data, extra_pointers);
|
|
} else if (e->IsBot() && BotHasQuestSub(event_id)) {
|
|
return EventBot(event_id, e->CastToBot(), init, lazy_data(), extra_data, extra_pointers);
|
|
} else if (e->IsMerc() && MercHasQuestSub(event_id)) {
|
|
return EventMerc(event_id, e->CastToMerc(), init, lazy_data(), extra_data, extra_pointers);
|
|
} else if (e->IsNPC() && HasQuestSub(e->GetNPCTypeID(), event_id)) {
|
|
return EventNPC(event_id, e->CastToNPC(), init, lazy_data(), extra_data, extra_pointers);
|
|
}
|
|
|
|
return false; // No quest subscription found
|
|
}
|