diff --git a/zone/embparser.cpp b/zone/embparser.cpp index 5a7f58136..1b86ef3e4 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -222,6 +222,8 @@ PerlembParser::PerlembParser() : perl(nullptr) global_bot_quest_status_ = questUnloaded; merc_quest_status_ = questUnloaded; global_merc_quest_status_ = questUnloaded; + zone_quest_status_ = questUnloaded; + global_zone_quest_status_ = questUnloaded; } PerlembParser::~PerlembParser() @@ -265,6 +267,8 @@ void PerlembParser::ReloadQuests() global_bot_quest_status_ = questUnloaded; merc_quest_status_ = questUnloaded; global_merc_quest_status_ = questUnloaded; + zone_quest_status_ = questUnloaded; + global_zone_quest_status_ = questUnloaded; item_quest_status_.clear(); spell_quest_status_.clear(); @@ -353,21 +357,21 @@ int PerlembParser::EventCommon( } if (quest_type == QuestType::Player || quest_type == QuestType::PlayerGlobal) { - return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, nullptr, nullptr); + return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, nullptr, nullptr, nullptr); } else if ( quest_type == QuestType::Bot || quest_type == QuestType::BotGlobal || quest_type == QuestType::Merc || quest_type == QuestType::MercGlobal ) { - return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, npc_mob, mob, nullptr, nullptr); + return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, npc_mob, mob, nullptr, nullptr, nullptr); } else if (quest_type == QuestType::Item || quest_type == QuestType::ItemGlobal) { - return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, inst, nullptr); + return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, inst, nullptr, nullptr); } else if (quest_type == QuestType::Spell || quest_type == QuestType::SpellGlobal) { if (mob) { - return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, nullptr, spell); + return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, nullptr, spell, nullptr); } else { - return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, npc_mob, mob, nullptr, spell); + return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, npc_mob, mob, nullptr, spell, nullptr); } } else if (quest_type == QuestType::NPC || quest_type == QuestType::NPCGlobal) { return SendCommands( @@ -377,8 +381,20 @@ int PerlembParser::EventCommon( npc_mob, mob, nullptr, + nullptr, nullptr ); + } else if (quest_type == QuestType::Zone || quest_type == QuestType::ZoneGlobal) { + return SendCommands( + package_name.c_str(), + QuestEventSubroutines[event_id], + 0, + nullptr, + nullptr, + nullptr, + nullptr, + zone + ); } } @@ -972,7 +988,8 @@ int PerlembParser::SendCommands( Mob* other, Mob* mob, EQ::ItemInstance* inst, - const SPDat_Spell_Struct* spell + const SPDat_Spell_Struct* spell, + Zone* zone ) { if (!perl) { @@ -980,12 +997,20 @@ int PerlembParser::SendCommands( } int ret_value = 0; + QuestManager::RunningQuest q; if (mob && mob->IsClient()) { - quest_manager.StartQuest(other, mob->CastToClient(), inst, spell); - } else { - quest_manager.StartQuest(other); + q.owner = other; + q.initiator = mob->CastToClient(); + q.questitem = inst; + q.questspell = spell; } + if (zone) { + q.zone = zone; + } + + quest_manager.StartQuest(q); + try { perl->eval(fmt::format("package {};", prefix).c_str()); @@ -1024,21 +1049,23 @@ int PerlembParser::SendCommands( sv_setsv(client, _empty_sv); } - if (other->IsBot()) { - Bot* b = quest_manager.GetBot(); - buf = fmt::format("{}::bot", prefix); - SV* bot = get_sv(buf.c_str(), true); - sv_setref_pv(bot, "Bot", b); - } else if (other->IsMerc()) { - Merc* m = quest_manager.GetMerc(); - buf = fmt::format("{}::merc", prefix); - SV* merc = get_sv(buf.c_str(), true); - sv_setref_pv(merc, "Merc", m); - } else if (other->IsNPC()) { - NPC* n = quest_manager.GetNPC(); - buf = fmt::format("{}::npc", prefix); - SV* npc = get_sv(buf.c_str(), true); - sv_setref_pv(npc, "NPC", n); + if (other) { + if (other->IsBot()) { + Bot* b = quest_manager.GetBot(); + buf = fmt::format("{}::bot", prefix); + SV* bot = get_sv(buf.c_str(), true); + sv_setref_pv(bot, "Bot", b); + } else if (other->IsMerc()) { + Merc* m = quest_manager.GetMerc(); + buf = fmt::format("{}::merc", prefix); + SV* merc = get_sv(buf.c_str(), true); + sv_setref_pv(merc, "Merc", m); + } else if (other->IsNPC()) { + NPC* n = quest_manager.GetNPC(); + buf = fmt::format("{}::npc", prefix); + SV* npc = get_sv(buf.c_str(), true); + sv_setref_pv(npc, "NPC", n); + } } //only export QuestItem if it's an inst quest @@ -2724,7 +2751,7 @@ void PerlembParser::LoadGlobalZoneScript(std::string filename) } catch (std::string e) { AddError( fmt::format( - "Error Compiling Global Zone uest File [{}] Error [{}]", + "Error Compiling Global Zone Quest File [{}] Error [{}]", filename, e ) diff --git a/zone/embparser.h b/zone/embparser.h index 769828d58..5817ce15b 100644 --- a/zone/embparser.h +++ b/zone/embparser.h @@ -232,7 +232,8 @@ private: Mob* other, Mob* mob, EQ::ItemInstance* inst, - const SPDat_Spell_Struct* spell + const SPDat_Spell_Struct* spell, + Zone* zone ); void MapFunctions(); diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index d44fb2bfa..5063833b5 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -489,7 +489,13 @@ int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, M arg_function(this, L, npc, init, data, extra_data, extra_pointers); Client *c = (init && init->IsClient()) ? init->CastToClient() : nullptr; - quest_manager.StartQuest(npc, c); + QuestManager::RunningQuest q; + + q.owner = npc; + q.initiator = c; + + quest_manager.StartQuest(q); + if(lua_pcall(L, 1, 1, start + 1)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -582,7 +588,13 @@ int LuaParser::_EventPlayer(std::string package_name, QuestEventID evt, Client * auto arg_function = PlayerArgumentDispatch[evt]; arg_function(this, L, client, data, extra_data, extra_pointers); - quest_manager.StartQuest(client, client); + QuestManager::RunningQuest q; + + q.owner = client; + q.initiator = client; + + quest_manager.StartQuest(q); + if(lua_pcall(L, 1, 1, start + 1)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -666,7 +678,14 @@ int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *cl auto arg_function = ItemArgumentDispatch[evt]; arg_function(this, L, client, item, mob, data, extra_data, extra_pointers); - quest_manager.StartQuest(client, client, item); + QuestManager::RunningQuest q; + + q.owner = client; + q.initiator = client; + q.questitem = item; + + quest_manager.StartQuest(q); + if(lua_pcall(L, 1, 1, start + 1)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -748,7 +767,14 @@ int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, Mob* mob, auto arg_function = SpellArgumentDispatch[evt]; arg_function(this, L, mob, client, spell_id, data, extra_data, extra_pointers); - quest_manager.StartQuest(mob, client, nullptr, const_cast(&spells[spell_id])); + QuestManager::RunningQuest q; + + q.owner = client; + q.initiator = client; + q.questspell = const_cast(&spells[spell_id]); + + quest_manager.StartQuest(q); + if(lua_pcall(L, 1, 1, start + 1)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -814,7 +840,13 @@ int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std:: auto arg_function = EncounterArgumentDispatch[evt]; arg_function(this, L, enc, data, extra_data, extra_pointers); - quest_manager.StartQuest(enc, nullptr, nullptr, nullptr, encounter_name); + QuestManager::RunningQuest q; + + q.owner = enc; + q.encounter = encounter_name; + + quest_manager.StartQuest(q); + if(lua_pcall(L, 1, 1, start + 1)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -1757,7 +1789,13 @@ int LuaParser::_EventBot( arg_function(this, L, bot, init, data, extra_data, extra_pointers); auto* c = (init && init->IsClient()) ? init->CastToClient() : nullptr; - quest_manager.StartQuest(bot, c); + QuestManager::RunningQuest q; + + q.owner = bot; + q.initiator = c; + + quest_manager.StartQuest(q); + if(lua_pcall(L, 1, 1, start + 1)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -1936,7 +1974,13 @@ int LuaParser::_EventMerc( arg_function(this, L, merc, init, data, extra_data, extra_pointers); auto* c = (init && init->IsClient()) ? init->CastToClient() : nullptr; - quest_manager.StartQuest(merc, c); + QuestManager::RunningQuest q; + + q.owner = merc; + q.initiator = c; + + quest_manager.StartQuest(q); + if(lua_pcall(L, 1, 1, start + 1)) { std::string error = lua_tostring(L, -1); AddError(error); diff --git a/zone/quest_parser_collection.cpp b/zone/quest_parser_collection.cpp index 540f5f54e..0c668a037 100644 --- a/zone/quest_parser_collection.cpp +++ b/zone/quest_parser_collection.cpp @@ -87,6 +87,7 @@ void QuestParserCollection::ReloadQuests(bool reset_timers) { if (reset_timers) { quest_manager.ClearAllTimers(); + zone->StopAllTimers(); } MapOpcodes(); diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index ac17e68d3..8f95a93cf 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -64,10 +64,10 @@ QuestManager quest_manager; EQ::ItemInstance* questitem = nullptr; \ const SPDat_Spell_Struct* questspell = nullptr; \ bool depop_npc = false; \ - std::string encounter; \ + std::string encounter = ""; \ do { \ - if(!quests_running_.empty()) { \ - running_quest e = quests_running_.top(); \ + if(!m_running_quests.empty()) { \ + RunningQuest e = m_running_quests.top(); \ owner = e.owner; \ initiator = e.initiator; \ questitem = e.questitem; \ @@ -124,33 +124,34 @@ void QuestManager::Process() { } } -void QuestManager::StartQuest(Mob *_owner, Client *_initiator, EQ::ItemInstance* _questitem, const SPDat_Spell_Struct* _questspell, std::string encounter) { - running_quest run; - run.owner = _owner; - run.initiator = _initiator; - run.questitem = _questitem; - run.questspell = _questspell; - run.depop_npc = false; - run.encounter = encounter; - quests_running_.push(run); +void QuestManager::StartQuest(RunningQuest q) +{ + m_running_quests.push(q); } void QuestManager::EndQuest() { - running_quest run = quests_running_.top(); - if(run.depop_npc && run.owner->IsNPC()) { + RunningQuest run = m_running_quests.top(); + + if (run.depop_npc && run.owner->IsNPC()) { //clear out any timers for them... std::list::iterator cur = QTimerList.begin(), end; end = QTimerList.end(); while (cur != end) { - if (cur->mob == run.owner) + if (cur->mob == run.owner) { cur = QTimerList.erase(cur); - else + } else { ++cur; + } } run.owner->Depop(); } - quests_running_.pop(); + + if (run.zone && run.zone == zone) { + zone->StopAllTimers(); + } + + m_running_quests.pop(); } void QuestManager::ClearAllTimers() { @@ -1098,18 +1099,18 @@ void QuestManager::depop(int npc_type) { tmp->CastToNPC()->Depop(); } else { - running_quest e = quests_running_.top(); + RunningQuest e = m_running_quests.top(); e.depop_npc = true; - quests_running_.pop(); - quests_running_.push(e); + m_running_quests.pop(); + m_running_quests.push(e); } } } else { //depop self - running_quest e = quests_running_.top(); + RunningQuest e = m_running_quests.top(); e.depop_npc = true; - quests_running_.pop(); - quests_running_.push(e); + m_running_quests.pop(); + m_running_quests.push(e); } } } @@ -1606,7 +1607,7 @@ void QuestManager::save() { void QuestManager::faction(int faction_id, int faction_value, int temp) { QuestManagerCurrentQuestVars(); - running_quest run = quests_running_.top(); + RunningQuest run = m_running_quests.top(); if(run.owner->IsCharmed() == false && initiator) { if(faction_id != 0 && faction_value != 0) { initiator->SetFactionLevel2( @@ -2077,10 +2078,10 @@ void QuestManager::respawn(int npcTypeID, int grid) { if (!owner || !owner->IsNPC()) return; - running_quest e = quests_running_.top(); + RunningQuest e = m_running_quests.top(); e.depop_npc = true; - quests_running_.pop(); - quests_running_.push(e); + m_running_quests.pop(); + m_running_quests.push(e); const NPCType* npcType = nullptr; if ((npcType = content_db.LoadNPCTypesData(npcTypeID))) @@ -3980,81 +3981,90 @@ void QuestManager::ReloadZoneStaticData() } } -Client *QuestManager::GetInitiator() const { - if(!quests_running_.empty()) { - running_quest e = quests_running_.top(); +Client* QuestManager::GetInitiator() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return e.initiator; } return nullptr; } -NPC *QuestManager::GetNPC() const { - if(!quests_running_.empty()) { - running_quest e = quests_running_.top(); +NPC* QuestManager::GetNPC() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return (e.owner && e.owner->IsNPC()) ? e.owner->CastToNPC() : nullptr; } return nullptr; } -Bot *QuestManager::GetBot() const { - if (!quests_running_.empty()) { - running_quest e = quests_running_.top(); +Bot* QuestManager::GetBot() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return (e.owner && e.owner->IsBot()) ? e.owner->CastToBot() : nullptr; } return nullptr; } -Merc *QuestManager::GetMerc() const { - if (!quests_running_.empty()) { - running_quest e = quests_running_.top(); +Merc* QuestManager::GetMerc() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return (e.owner && e.owner->IsMerc()) ? e.owner->CastToMerc() : nullptr; } return nullptr; } -Mob *QuestManager::GetOwner() const { - if(!quests_running_.empty()) { - running_quest e = quests_running_.top(); +Mob* QuestManager::GetOwner() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return e.owner; } return nullptr; } -EQ::InventoryProfile *QuestManager::GetInventory() const { - if(!quests_running_.empty()) { - running_quest e = quests_running_.top(); +EQ::InventoryProfile* QuestManager::GetInventory() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return &e.initiator->GetInv(); } return nullptr; } -EQ::ItemInstance *QuestManager::GetQuestItem() const { - if(!quests_running_.empty()) { - running_quest e = quests_running_.top(); +EQ::ItemInstance* QuestManager::GetQuestItem() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return e.questitem; } return nullptr; } -const SPDat_Spell_Struct *QuestManager::GetQuestSpell() { - if(!quests_running_.empty()) { - running_quest e = quests_running_.top(); +const SPDat_Spell_Struct* QuestManager::GetQuestSpell() +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return e.questspell; } return nullptr; } -std::string QuestManager::GetEncounter() const { - if(!quests_running_.empty()) { - running_quest e = quests_running_.top(); +std::string QuestManager::GetEncounter() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return e.encounter; } diff --git a/zone/questmgr.h b/zone/questmgr.h index 0e3cd4a4f..53efe4c2a 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -34,14 +34,6 @@ namespace EQ } class QuestManager { - struct running_quest { - Mob *owner; - Client *initiator; - EQ::ItemInstance* questitem; - const SPDat_Spell_Struct* questspell; - bool depop_npc; - std::string encounter; - }; struct PausedTimer { Mob* owner; @@ -49,12 +41,23 @@ class QuestManager { uint32 time; }; public: + + struct RunningQuest { + Mob *owner = nullptr; + Client *initiator = nullptr; + EQ::ItemInstance* questitem = nullptr; + const SPDat_Spell_Struct* questspell = nullptr; + bool depop_npc = false; + std::string encounter = ""; + Zone* zone = nullptr; + }; + QuestManager(); virtual ~QuestManager(); - void StartQuest(Mob *_owner, Client *_initiator = nullptr, EQ::ItemInstance* _questitem = nullptr, const SPDat_Spell_Struct* _questspell = nullptr, std::string encounter = ""); + void StartQuest(RunningQuest q); void EndQuest(); - bool QuestsRunning() { return !quests_running_.empty(); } + bool QuestsRunning() { return !m_running_quests.empty(); } void Process(); @@ -381,7 +384,7 @@ public: bool handin(std::map required); private: - std::stack quests_running_; + std::stack m_running_quests; bool HaveProximitySays; diff --git a/zone/zone.cpp b/zone/zone.cpp index ac43e766b..056f7b088 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1696,7 +1696,6 @@ bool Zone::Process() { const bool has_timer_event = parse->ZoneHasQuestSub(EVENT_TIMER); for (auto e : zone_timers) { - LogError("has_timer_event [{}]", has_timer_event ? "y" : "n"); if (e.timer_.Enabled() && e.timer_.Check()) { if (has_timer_event) { parse->EventZone(EVENT_TIMER, this, e.name); @@ -1946,6 +1945,8 @@ void Zone::Repop(bool is_forced) quest_manager.ClearAllTimers(); + StopAllTimers(); + LogInfo("Loading spawn groups"); if (!content_db.LoadSpawnGroups(short_name, GetInstanceVersion(), &spawn_group_list)) { LogError("Loading spawn groups failed"); @@ -3457,7 +3458,8 @@ void Zone::SetTimer(std::string name, uint32 duration) zone_timers.emplace_back(ZoneTimer(name, duration)); if (parse->ZoneHasQuestSub(EVENT_TIMER_START)) { - parse->EventZone(EVENT_TIMER_START, this, name); + const std::string& export_string = fmt::format("{} {}", name, duration); + parse->EventZone(EVENT_TIMER_START, this, export_string); } } @@ -3483,6 +3485,10 @@ void Zone::StopTimer(std::string name) void Zone::StopAllTimers() { + if (!IsLoaded()) { + return; + } + if (zone_timers.empty()) { return; } @@ -3493,8 +3499,6 @@ void Zone::StopAllTimers() if (has_stop_event) { parse->EventZone(EVENT_TIMER_STOP, this, e->name); } - - e = zone_timers.erase(e); } }