/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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.
EQ2Emulator 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 EQ2Emulator. If not, see .
*/
#ifndef __EQ2_SPELL_PROCESS__
#define __EQ2_SPELL_PROCESS__
#include
#include
#include "client.h"
#include "Spells.h"
#include "zoneserver.h"
#include "LuaInterface.h"
#include "MutexMap.h"
#include "MutexList.h"
#include "World.h"
#include "HeroicOp/HeroicOp.h"
#define MODIFY_HEALTH 1
#define MODIFY_FOCUS 2
#define MODIFY_DEFENSE 3
#define MODIFY_POWER 4
#define MODIFY_SPEED 5
#define MODIFY_INT 6
#define MODIFY_WIS 7
#define MODIFY_STR 8
#define MODIFY_AGI 9
#define MODIFY_STA 10
#define MODIFY_COLD_RESIST 11
#define MODIFY_HEAT_RESIST 12
#define MODIFY_DISEASE_RESIST 13
#define MODIFY_POISON_RESIST 14
#define MODIFY_MAGIC_RESIST 15
#define MODIFY_MENTAL_RESIST 16
#define MODIFY_DIVINE_RESIST 17
#define MODIFY_ATTACK 18
#define MODIFY_MITIGATION 19
#define MODIFY_AVOIDANCE 20
#define MODIFY_CONCENTRATION 21
#define MODIFY_EXP 22
#define MODIFY_FACTION 23
#define CHANGE_SIZE 24
#define CHANGE_RACE 25
#define CHANGE_LOCATION 26
#define CHANGE_ZONE 27
#define CHANGE_PREFIX_TITLE 28
#define CHANGE_DEITY 29
#define CHANGE_LAST_NAME 30
#define MODIFY_HASTE 31
#define MODIFY_SKILL 32
#define CHANGE_TARGET 33
#define CHANGE_LEVEL 34
#define MODIFY_SPELL_CAST_TIME 35
#define MODIFY_SPELL_POWER_REQ 36
#define MODIFY_SPELL_HEALTH_REQ 37
#define MODIFY_SPELL_RECOVERY 38
#define MODIFY_SPELL_RECAST_TIME 39
#define MODIFY_SPELL_RADIUS 40
#define MODIFY_SPELL_AOE_TARGETS 41
#define MODIFY_SPELL_RANGE 42
#define MODIFY_SPELL_DURATION 43
#define MODIFY_SPELL_RESISTIBILITY 44
#define MODIFY_DAMAGE 45
#define MODIFY_DELAY 46
#define MODIFY_TRADESKILL_EXP 47
#define ADD_MOUNT 48
#define REMOVE_MOUNT 49
#define MODIFY_SPELL_CRIT_CHANCE 50
#define MODIFY_CRIT_CHANCE 51
#define SUMMON_ITEM 52
#define MODIFY_JUMP 53
#define MODIFY_FALL_SPEED 54
#define INFLICT_DAMAGE 55
#define ADD_DOT 56
#define REMOVE_DOT 57
#define HEAL_TARGET 58
#define HEAL_AOE 59
#define INFLICT_AOE_DAMAGE 60
#define HEAL_GROUP_AOE 61
#define ADD_AOE_DOT 62
#define REMOVE_AOE_DOT 63
#define ADD_HOT 64
#define REMOVE_HOT 65
#define MODIFY_AGGRO_RANGE 66
#define BLIND_TARGET 67
#define UNBLIND_TARGET 68
#define KILL_TARGET 69
#define RESURRECT_TARGET 70
#define CHANGE_SUFFIX_TITLE 71
#define SUMMON_PET 72
#define MODIFY_HATE 73
#define ADD_REACTIVE_HEAL 74
#define MODIFY_POWER_REGEN 75
#define MODIFY_HP_REGEN 76
#define FEIGN_DEATH 77
#define MODIFY_VISION 78
#define INVISIBILITY 79
#define CHARM_TARGET 80
#define MODIFY_TRADESKILL_DURABILITY 81
#define MODIFY_TRADESKILL_PROGRESS 82
#define ACTIVE_SPELL_NORMAL 0
#define ACTIVE_SPELL_ADD 1
#define ACTIVE_SPELL_REMOVE 2
#define GET_VALUE_BAD_VALUE 0xFFFFFFFF
struct InterruptStruct{
Spawn* interrupted;
LuaSpell* spell;
int16 error_code;
};
struct CastTimer{
Client* caster;
int32 target_id;
EntityCommand* entity_command;
LuaSpell* spell;
Timer* timer;
ZoneServer* zone;
bool delete_timer;
bool in_heroic_opp;
};
struct CastSpell{
Entity* caster;
Spawn* target;
int32 spell_id;
ZoneServer* zone;
};
struct RecastTimer{
Entity* caster;
Client* client;
Spell* spell;
Timer* timer;
int32 spell_id;
int32 linked_timer;
int32 type_group_spell_id;
};
/// Handles all spell casts for a zone, only 1 SpellProcess per zone
class SpellProcess{
public:
SpellProcess();
~SpellProcess();
/// Remove dead pointers for casters when the Spawn is deconstructed
void RemoveCaster(Spawn* caster);
/// Remove all spells from the SpellProcess
void RemoveAllSpells(bool reload_spells = false);
/// Main loop, handles everything (interupts, cast time, recast, ...)
void Process();
/// Interrupts the caster (creates the InterruptStruct and adds it to a list)
/// Entity being interrupted
/// Spawn that interrupted the caster
/// The error code
/// Bool if the spell was cancelled not interrupted
void Interrupted(Entity* caster, Spawn* interruptor, int16 error_code, bool cancel = false, bool from_movement = false);
/// Does all the checks and actually casts the spell
/// The current ZoneServer
/// The Spell to cast
/// The Entity casting the spell
/// The target(Spawn) of the spell
/// ??? not currently used
/// Is this a harvest spell?
void ProcessSpell(ZoneServer* zone, Spell* spell, Entity* caster, Spawn* target = 0, bool lock = true, bool harvest_spell = false, LuaSpell* customSpell = 0, int16 custom_cast_time = 0, bool in_heroic_opp = false);
/// Cast an EntityCommand (right click menu)
/// The current ZoneServer
/// the EntityCommand to cast
/// The Entity casting the EntityCommand
/// The target(Spawn*) of the EntityCommand
/// ??? not currently used
void ProcessEntityCommand(ZoneServer* zone, EntityCommand* entity_command, Entity* caster, Spawn* target, bool lock = true, bool in_heroic_opp = false);
/// Checks to see if the caster has enough power and takes it
/// LuaSpell to check and take power for (LuaSpell contains the caster)
/// True if caster had enough power
bool TakePower(LuaSpell* spell, int32 custom_power_req = 0);
/// Check to see if the caster has enough power to cast the spell
/// LuaSpell to check (LuaSpell contains the caster)
/// True if the caster has enough power
bool CheckPower(LuaSpell* spell);
/// Check to see if the caster has enough hp and take it
/// LuaSpell to check and take hp for (LuaSpell contains the caster)
/// True if the caster had enough hp
bool TakeHP(LuaSpell* spell, int32 custom_hp_req = 0);
/// Check to see if the caster has enough hp to cast the spell
/// LuaSpell to check (LuaSpell contains the caster)
/// True if the caster had enough hp
bool CheckHP(LuaSpell* spell);
/// Check to see if the caster has enough concentration available to cast the spell
/// LuaSpell to check (LuaSpell contains the caster)
/// True if the caster has enough concentration
bool CheckConcentration(LuaSpell* spell);
bool CheckSavagery(LuaSpell* spell);
bool TakeSavagery(LuaSpell* spell);
bool CheckDissonance(LuaSpell* spell);
bool AddDissonance(LuaSpell* spell);
/// Check to see if the caster has enough concentration available and add to the casters concentration
/// LuaSpell to check (LuaSpell contains the caster)
/// True of the caster had enough concentration
bool AddConcentration(LuaSpell* spell);
/// Cast the spell, calls ProcessSpell for the given LuaSpell, as well as sends the messages for the spells and calls the casted on function in the targets spawn script
/// LuaSpell to cast
/// Is this a passive spell being cast?
/// True if the spell was casted
bool CastProcessedSpell(LuaSpell* spell, bool passive = false, bool in_heroic_opp = false);
/// Cast the EntityCommand, calls ProcessEntityCommand for the given EntityCommand, as well as sends the messages for the command and calls the casted on function in the targets spawn script
/// EntityCommand to cast
/// Client casting the entity command
/// True if the spell was casted
bool CastProcessedEntityCommand(EntityCommand* entity_command, Client* client, Spawn* target, bool in_heroic_opp = false);
/// Sends the start cast packet for the given client
/// LuaSpell being cast
/// The client casting the spell
void SendStartCast(LuaSpell* spell, Client* client);
/// Send finish cast packet and take power/hp or add conc, also checks for quest updates
/// LuaSpell that just finished casting
/// Client that just finished casting, null if not a player
void SendFinishedCast(LuaSpell* spell, Client* client);
/// Locks all the spells for the given client (shades them all gray)
/// Client to lock the spells for
void LockAllSpells(Client* client);
/// Unlock all the spells for the given client
/// Client to unlock the spells for
void UnlockAllSpells(Client* client, Spell* exception = 0);
/// Unlock a single spell for the given client
/// The client to unlock the spell for
/// The spell to unlock
void UnlockSpell(Client* client, Spell* spell);
/// Remove the given spell for the given caster from the SpellProcess
/// The spawn to remove the spell for
/// The spell to remove
bool DeleteCasterSpell(Spawn* caster, Spell* spell, string reason = "");
/// Remove the given spell from the ZpellProcess
/// LuaSpell to remove
bool DeleteCasterSpell(LuaSpell* spell, string reason="", bool removing_all_spells = false, Spawn* remove_target = nullptr, bool zone_shutting_down = false, bool shared_lock_spell = true);
/// Interrupt the spell
/// InterruptStruct that contains all the info
void CheckInterrupt(InterruptStruct* interrupt);
/// Removes the timers for the given spawn
/// Spawn to remove the timers for
/// Remove all timers (cast, recast, active, queue, interrupted)? If false only cast timers are removed
void RemoveSpellTimersFromSpawn(Spawn* spawn, bool remove_all = false, bool delete_recast = false, bool call_expire_function = true, bool lock_spell_process = false);
/// Sets the recast timer for the spell
/// The spell to set the recast for
/// The entity to set the recast for
/// Change the recast timer of the spell
/// Set the recast on all other spells the player has with the same timer
void CheckRecast(Spell* spell, Entity* caster, float timer_override = 0, bool check_linked_timers = true);
/// Add a spell to the queue for the player
/// Spell to add
/// Entity's queue to add the spell to, if not a player function does nothing
void AddSpellToQueue(Spell* spell, Entity* caster);
/// Removes a spell from the queue for the player
/// Spell to remove from the queue
/// Entity's queue to remove the spell from, if not a player function does nothing
void RemoveSpellFromQueue(Spell* spell, Entity* caster, bool send_update = true);
/// Clear the queue, or clear only hostile spells from the queue
/// Entity to clear the queue for, if not player function does nothing
/// Set to true to only remove hostile spells, default is false
void RemoveSpellFromQueue(Entity* caster, bool hostile_only = false);
/// Check the given enities queue for the spell, if found remove, if not found add
/// Spell to check for
/// Entity's queue to check, if not player function does nothing
bool CheckSpellQueue(Spell* spell, Entity* caster);
/// Checks to see if the entity can cast the spell
/// The spell being cast
/// The entity casting the spell
bool IsReady(Spell* spell, Entity* caster);
/// Send the spell book update packet to the given client
/// Client to send the packet to
void SendSpellBookUpdate(Client* client);
/// Gets the target of the currently casting spell for the given entity
/// Entity whos spell we are checking
/// Spawn* - the spells target
Spawn* GetSpellTarget(Entity* caster);
/// Gets the currently casting spell for the given entity
/// Entity to get the spell for
/// Spell* for the currently casting spell
Spell* GetSpell(Entity* caster);
/// Gets the currently casting LuaSpell for the given entity
/// Entity to get the LuaSpell for
/// LuaSpell* for the currently casting spell
LuaSpell* GetLuaSpell(Entity* caster);
/// Gets the targets for the spell and adds them to the LuaSpell targets array
/// LuaSpell to get the targets for
static void GetSpellTargets(LuaSpell* luaspell);
static bool GetPlayerGroupTargets(Player* target, Spawn* caster, LuaSpell* luaspell, bool bypassSpellChecks=false, bool bypassRangeChecks=false);
/// Gets targets for a true aoe spell (not an encounter ae) and adds them to the LuaSpell targets array
/// LuaSpell to get the targets for
static void GetSpellTargetsTrueAOE(LuaSpell* luaspell);
/// Applies or removes passive spells, bypasses the spell queue and treats the spell as an insta cast spell
/// The passive spell to apply or remove
/// The Entity to apply or remove the passive spell to
/// Tells the function to remove the spell effects of this passive, default is false
bool CastPassives(Spell* spell, Entity* caster, bool remove = false);
bool CastInstant(Spell* spell, Entity* caster, Entity* target, bool remove = false, bool passive=false);
/// Adds a spell script timer to the list
/// Timer to add
void AddSpellScriptTimer(SpellScriptTimer* timer);
/// Removes a spell script timer from the list
/// Timer to remove
void RemoveSpellScriptTimer(SpellScriptTimer* timer, bool locked=false);
void RemoveSpellScriptTimerBySpell(LuaSpell* spell, bool clearPendingDeletes=true);
/// Checks the spell script timers
void CheckSpellScriptTimers();
/// Checks to see if the list has the spell
bool SpellScriptTimersHasSpell(LuaSpell* spell);
std::string SpellScriptTimerCustomFunction(LuaSpell* spell);
void ClearSpellScriptTimerList();
MutexList* GetActiveSpells() { return &active_spells; }
void RemoveTargetFromSpell(LuaSpell* spell, Spawn* target, bool remove_caster = false);
void CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete = true, bool removing_all_spells = false);
void RemoveTargetList(LuaSpell* spell);
/// Adds a solo HO to the SpellProcess
/// The client who is starting the HO
/// The HO that is being started
bool AddHO(Client* client, HeroicOP* ho);
/// Adds a group HO to the SpellProcess
/// ID of the group that is starting the HO
/// The HO that is being started
bool AddHO(int32 group_id, HeroicOP* ho);
/// Stops the HO that targets the given spawn
/// ID of the spawn targeted by the HO we want to stop
void KillHOBySpawnID(int32 spawn_id);
void AddSpellCancel(LuaSpell* spell);
void DeleteSpell(LuaSpell* spell);
void SpellCannotStack(ZoneServer* zone, Client* client, Entity* caster, LuaSpell* lua_spell, LuaSpell* conflictSpell);
bool ProcessSpell(LuaSpell* spell, bool first_cast = true, const char* function = 0, SpellScriptTimer* timer = 0, bool all_targets = false);
std::string ApplyLuaFunction(LuaSpell* spell, bool first_cast, const char* function, SpellScriptTimer* timer, Spawn* altTarget = 0);
void AddActiveSpell(LuaSpell* spell);
static void AddSelfAndPet(LuaSpell* spell, Spawn* self, bool onlyPet=false);
static void AddSelfAndPetToCharTargets(LuaSpell* spell, Spawn* caster, bool onlyPet=false);
void DeleteActiveSpell(LuaSpell* spell, bool skipRemoveCurrent = false);
static bool AddLuaSpellTarget(LuaSpell* lua_spell, int32 id, bool lock_spell_targets = true);
mutable std::shared_mutex MSpellProcess;
private:
MutexMap spell_que;
MutexList active_spells;
MutexList cast_timers;
MutexListinterrupt_list;
MutexList recast_timers;
int32 last_checked_time;
vector m_spellScriptList;
Mutex MSpellScriptTimers;
map*> remove_target_list;
Mutex MRemoveTargetList;
vector SpellCancelList;
Mutex MSpellCancelList;
Mutex MSoloHO;
Mutex MGroupHO;
map m_soloHO;
map m_groupHO;
};
#endif