/* 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 . */ #pragma once #include "common/timer.h" #include "zone/npc.h" #define SC_AlwaysEnabled 0 class SpawnCondition; class NPC; class Spawn2 { public: Spawn2(uint32 spawn2_id, uint32 spawngroup_id, float x, float y, float z, float heading, uint32 respawn, uint32 variance, uint32 timeleft = 0, uint32 grid = 0, bool in_path_when_zone_idle=false, uint16 cond_id = SC_AlwaysEnabled, int16 min_value = 0, bool in_enabled = true, EmuAppearance anim = eaStanding); ~Spawn2(); void LoadGrid(int start_wp = 0); void Enable() { enabled = true; } void Disable(); bool Enabled() { return enabled; } bool Process(); void Reset(); void Depop(); void Repop(uint32 delay = 0); void ForceDespawn(); void DeathReset(bool realdeath = 0); //resets the spawn in the case the npc dies, also updates db if needed void SpawnConditionChanged(const SpawnCondition &c, int16 old_value); uint32 GetID() { return spawn2_id; } float GetX() { return x; } float GetY() { return y; } float GetZ() { return z; } float GetHeading() { return heading; } bool PathWhenZoneIdle() { return path_when_zone_idle; } void SetRespawnTimer(uint32 newrespawntime) { m_respawn_time = newrespawntime; }; void SetVariance(uint32 newvariance) { variance_ = newvariance; } const uint32 GetVariance() const { return variance_; } uint32 RespawnTimer() { return m_respawn_time; } uint32 SpawnGroupID() { return spawngroup_id_; } uint32 CurrentNPCID() { return currentnpcid; } void SetCurrentNPCID(uint32 nid) { currentnpcid = nid; } uint32 GetSpawnCondition() { return condition_id; } bool NPCPointerValid() { return (npcthis!=nullptr); } void SetNPCPointer(NPC* n) { npcthis = n; } void SetNPCPointerNull() { npcthis = nullptr; } Timer GetTimer() { return timer; } void SetTimer(uint32 duration) { timer.Start(duration); } uint32 GetKillCount() { return killcount; } uint32 GetGrid() const { return grid_; } bool GetPathWhenZoneIdle() const { return path_when_zone_idle; } int16 GetConditionMinValue() const { return condition_min_value; } int16 GetAnimation () { return anim; } inline NPC *GetNPC() const { return npcthis; } inline bool IsResumedFromZoneSuspend() const { return m_resumed_from_zone_suspend; } inline void SetResumedFromZoneSuspend(bool resumed) { m_resumed_from_zone_suspend = resumed; } inline void SetEntityVariables(std::map vars) { m_entity_variables = vars; } inline void SetResumedNPCID(uint32 npc_id) { m_resumed_npc_id = npc_id; } inline void SetStoredLocation(const glm::vec4& loc) { m_stored_location = loc; } protected: friend class Zone; Timer timer; private: uint32 spawn2_id; uint32 m_respawn_time; uint32 resetTimer(); uint32 despawnTimer(uint32 despawn_timer); uint32 spawngroup_id_; uint32 currentnpcid; NPC* npcthis; float x; float y; float z; float heading; uint32 variance_; uint32 grid_; bool path_when_zone_idle; uint16 condition_id; int16 condition_min_value; bool enabled; EmuAppearance anim; bool IsDespawned; uint32 killcount; bool m_resumed_from_zone_suspend = false; uint32 m_resumed_npc_id = 0; std::map m_entity_variables = {}; glm::vec4 m_stored_location = {0, 0, -1000, 0}; // use -1000 to indicate unset/zero-state }; class SpawnCondition { public: typedef enum { DoNothing = 0, DoDepop = 1, DoRepop = 2, DoRepopIfReady = 3, //... 4...9 reserved for future use DoSignalMin = 10 //any number above this value is used as //a base for the signal ID sent. e.g. // value 12 sends signal id 2 } OnChange; SpawnCondition(); uint16 condition_id; int16 value; OnChange on_change; }; class SpawnEvent { public: typedef enum { ActionSet = 0, ActionAdd = 1, ActionSubtract = 2, ActionMultiply = 3, ActionDivide = 4 } Action; SpawnEvent(); uint32 id; uint16 condition_id; std::string zone_name; bool enabled; Action action; int16 argument; bool strict; uint32 period; //eq minutes (3 seconds) between events TimeOfDay_Struct next; //next time this event triggers }; class SpawnConditionManager { public: SpawnConditionManager(); void Process(); bool LoadSpawnConditions(const std::string& zone_short_name, uint32 instance_id); int16 GetCondition(const std::string& zone_short_name, uint32 instance_id, uint16 condition); void SetCondition(const char *zone_short, uint32 instance_id, uint16 condition_id, int16 new_value, bool world_update = false); void ToggleEvent(uint32 event_id, bool enabled, bool strict, bool reset_base); bool Check(uint16 condition, int16 min_value); void ReloadEvent(uint32 event_id); protected: std::map spawn_conditions; std::vector spawn_events; void ExecEvent(SpawnEvent &e, bool send_update); void UpdateSpawnEvent(SpawnEvent &e); bool LoadSpawnEvent(uint32 event_id, SpawnEvent& event, std::string& zone_short_name); void UpdateSpawnCondition(const std::string& zone_short_name, uint32 instance_id, uint16 condition, int16 condition_value); void FindNearestEvent(); Timer minute_timer; TimeOfDay_Struct next_event; }; constexpr int format_as(SpawnCondition::OnChange val) { return static_cast(val); } constexpr int format_as(SpawnEvent::Action val) { return static_cast(val); }