From 1bc87d6617da7904117933c00c6502cb3c0071b1 Mon Sep 17 00:00:00 2001 From: Emagi Date: Mon, 25 Aug 2025 09:18:34 -0400 Subject: [PATCH] LUA RemoveSpell(Spawn, spell_id, ..) added, Illusion is a control effect, Redesign of control effects, immunities, effect flags away from mutex lists RemoveSpell(Spawn, SpellID, MaintainedSpell, ReasonString) - maintainedspell is a boolean, default false it will remove an effect (per target) otherwise setting to true will remove the entire spell, maintained, if that is the caster. Reason String is "canceled" by default unless overwritten Illusions made to a control effect so we can enforce an existing illusion --- source/WorldServer/EffectFlags.h | 442 +++++++++++++++++++ source/WorldServer/Entity.cpp | 612 +++++++++------------------ source/WorldServer/Entity.h | 40 +- source/WorldServer/LuaFunctions.cpp | 180 ++++---- source/WorldServer/LuaFunctions.h | 1 + source/WorldServer/LuaInterface.cpp | 3 +- source/WorldServer/LuaInterface.h | 3 +- source/WorldServer/Player.cpp | 8 +- source/WorldServer/WorldDatabase.cpp | 4 +- 9 files changed, 774 insertions(+), 519 deletions(-) create mode 100644 source/WorldServer/EffectFlags.h diff --git a/source/WorldServer/EffectFlags.h b/source/WorldServer/EffectFlags.h new file mode 100644 index 0000000..d890372 --- /dev/null +++ b/source/WorldServer/EffectFlags.h @@ -0,0 +1,442 @@ +/* + EQ2Emulator: Everquest II Server Emulator + Copyright (C) 2005 - 2026 EQ2EMulator Development Team (http://www.eq2emu.com formerly 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 . +*/ + +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class LuaSpell; + +// ----------------------------- Core bitflags -------------------------------- +template +class BitFlags { +public: + static constexpr std::size_t kWordBits = 64; + static constexpr std::size_t kWords = (NBits + kWordBits - 1) / kWordBits; + + constexpr BitFlags() noexcept : words_{} {} + + // Single-bit ops + inline void set(std::size_t bit) noexcept { words_[word_index(bit)] |= word_mask(bit); } + inline void reset(std::size_t bit) noexcept { words_[word_index(bit)] &= ~word_mask(bit); } + inline void toggle(std::size_t bit) noexcept { words_[word_index(bit)] ^= word_mask(bit); } + inline bool test(std::size_t bit) const noexcept { return (words_[word_index(bit)] & word_mask(bit)) != 0ULL; } + + // Bulk ops + inline void clear() noexcept { + for (std::size_t i = 0; i < kWords; ++i) words_[i] = 0ULL; + } + inline bool any() const noexcept { + for (std::size_t i = 0; i < kWords; ++i) if (words_[i]) return true; + return false; + } + inline bool none() const noexcept { return !any(); } + + inline void import_u32(std::uint32_t legacy) noexcept { + if (!legacy) return; + const std::size_t lim = (NBits < 32 ? NBits : 32); + for (std::size_t i = 0; i < lim; ++i) + if ((legacy >> i) & 1u) set(i); + } + inline std::uint32_t export_u32() const noexcept { + std::uint32_t out = 0; + const std::size_t lim = (NBits < 32 ? NBits : 32); + for (std::size_t i = 0; i < lim; ++i) + if (test(i)) out |= (1u << i); + return out; + } + + // Import a 64-bit legacy mask (low 64 bits only) +inline void import_u64(std::uint64_t legacy) noexcept { + if (!legacy) return; + const std::size_t lim = (NBits < 64 ? NBits : 64); + for (std::size_t i = 0; i < lim; ++i) + if ((legacy >> i) & 1ULL) set(i); +} + +// Export low 64 bits into a uint64_t +inline std::uint64_t export_u64() const noexcept { + std::uint64_t out = 0; + const std::size_t lim = (NBits < 64 ? NBits : 64); + for (std::size_t i = 0; i < lim; ++i) + if (test(i)) out |= (1ULL << i); + return out; +} + + + // Set by legacy power-of-two value (find index of the single set bit) + inline void set_legacy_flag_value(std::uint64_t pow2) noexcept { + if (!pow2) return; +#if defined(__GNUC__) || defined(__clang__) + std::size_t bit = static_cast(__builtin_ctzll(pow2)); +#else + std::size_t bit = 0; while (bit < 64 && ((pow2 >> bit) & 1ULL) == 0ULL) ++bit; +#endif + if (bit < NBits) set(bit); + } + + // Direct word access (used by TS wrapper) + static constexpr std::size_t words_count() noexcept { return kWords; } + inline std::uint64_t& word_ref(std::size_t i) noexcept { return words_[i]; } + inline const std::uint64_t& word_ref(std::size_t i) const noexcept { return words_[i]; } + +private: + static constexpr std::size_t word_index(std::size_t bit) noexcept { return bit / kWordBits; } + static constexpr std::uint64_t word_mask (std::size_t bit) noexcept { return 1ULL << (bit % kWordBits); } + + std::array words_; +}; + +// --------------------------- Thread-safe wrapper ---------------------------- +template +class TSBitFlags { +public: + using Snapshot = BitFlags; + + // Single-bit ops + inline void set(std::size_t bit) { std::unique_lock lk(m_); bits_.set(bit); } + inline void reset(std::size_t bit) { std::unique_lock lk(m_); bits_.reset(bit); } + inline void toggle(std::size_t bit) { std::unique_lock lk(m_); bits_.toggle(bit); } + inline bool test(std::size_t bit) const { std::shared_lock lk(m_); return bits_.test(bit); } + + // Convenience + inline void add(std::size_t bit) { set(bit); } + inline void remove(std::size_t bit) { reset(bit); } + inline bool has(std::size_t bit) const { return test(bit); } + + // Batch ops + inline void set_many(std::initializer_list bits) { + std::unique_lock lk(m_); for (auto b : bits) bits_.set(b); + } + inline void reset_many(std::initializer_list bits) { + std::unique_lock lk(m_); for (auto b : bits) bits_.reset(b); + } + + // Clear / any / none + inline void clear() { std::unique_lock lk(m_); bits_.clear(); } + inline bool any() const { std::shared_lock lk(m_); return bits_.any(); } + inline bool none() const { std::shared_lock lk(m_); return bits_.none(); } + + // Legacy helpers + inline void import_u32(std::uint32_t legacy) { std::unique_lock lk(m_); bits_.import_u32(legacy); } + inline std::uint32_t export_u32() const { std::shared_lock lk(m_); return bits_.export_u32(); } + inline void import_u64(std::uint64_t legacy) { std::unique_lock lk(m_); bits_.import_u64(legacy); } + inline std::uint64_t export_u64() const { std::shared_lock lk(m_); return bits_.export_u64(); } + inline void set_legacy_flag_value(std::uint64_t v){ std::unique_lock lk(m_); bits_.set_legacy_flag_value(v); } + + // Snapshots (copy out/in without exposing lock) + inline Snapshot snapshot() const { std::shared_lock lk(m_); return bits_; } + inline void assign_from(const Snapshot& snap) { + std::unique_lock lk(m_); + for (std::size_t i = 0; i < Snapshot::words_count(); ++i) + bits_.word_ref(i) = snap.word_ref(i); + } + +private: + mutable std::shared_mutex m_; + Snapshot bits_{}; +}; + +// ------------------------- Project-specific typedefs ------------------------ +inline constexpr std::size_t kEffectBits = 64; // limited due to DB restrictions at this time +using EffectFlags = TSBitFlags; + +enum : std::size_t { + EFFECT_IDX_STUN = 0, + EFFECT_IDX_ROOT = 1, + EFFECT_IDX_MEZ = 2, + EFFECT_IDX_STIFLE = 3, + EFFECT_IDX_DAZE = 4, + EFFECT_IDX_FEAR = 5, + EFFECT_IDX_SPELLBONUS = 6, + EFFECT_IDX_SKILLBONUS = 7, + EFFECT_IDX_STEALTH = 8, + EFFECT_IDX_INVIS = 9, + EFFECT_IDX_SNARE = 10, + EFFECT_IDX_WATERWALK = 11, + EFFECT_IDX_WATERJUMP = 12, + EFFECT_IDX_FLIGHT = 13, + EFFECT_IDX_GLIDE = 14, + EFFECT_IDX_AOE_IMMUNE = 15, + EFFECT_IDX_STUN_IMMUNE = 16, + EFFECT_IDX_MEZ_IMMUNE = 17, + EFFECT_IDX_DAZE_IMMUNE = 18, + EFFECT_IDX_ROOT_IMMUNE = 19, + EFFECT_IDX_STIFLE_IMMUNE = 20, + EFFECT_IDX_FEAR_IMMUNE = 21, + EFFECT_IDX_SAFEFALL = 22, + EFFECT_IDX_ILLUSION = 23, +}; + + + +class EffectRegistryPerSpell { +public: + using Code = uint8_t; // your int8 codes + using Value = std::variant; + + explicit EffectRegistryPerSpell(Code max_code_inclusive) + : max_code_(max_code_inclusive), + slots_(static_cast(max_code_inclusive) + 1) {} + + // --- Membership (writers) ------------------------------------------------- + + // Add a spell to a type. Returns true if inserted (false if already present). + bool Add(Code code, LuaSpell* spell) { + if (!in_range(code) || !spell) return false; + auto& s = slots_[code]; + std::unique_lock lk(s.mtx); + return s.members.emplace(spell, Entry{spell, std::monostate{}}).second; + } + + // Add or update (set/replace the per-spell value atomically). + // Returns true if inserted new, false if updated existing. + template + bool AddOrUpdate(Code code, LuaSpell* spell, T v) { + if (!in_range(code) || !spell) return false; + auto& s = slots_[code]; + std::unique_lock lk(s.mtx); + auto [it, inserted] = s.members.emplace(spell, Entry{spell, std::monostate{}}); + it->second.val = to_variant(std::move(v)); + return inserted; + } + + // Remove a spell from a type. Returns true if erased. + bool Remove(Code code, LuaSpell* spell) { + if (!in_range(code) || !spell) return false; + auto& s = slots_[code]; + std::unique_lock lk(s.mtx); + return s.members.erase(spell) > 0; + } + + // Clear all spells at a type + void Clear(Code code) { + if (!in_range(code)) return; + auto& s = slots_[code]; + std::unique_lock lk(s.mtx); + s.members.clear(); + } + + // --- Queries (readers) ---------------------------------------------------- + + // Is there any spell registered at this type? + bool Has(Code code) const { + if (!in_range(code)) return false; + auto& s = slots_[code]; + std::shared_lock lk(s.mtx); + return !s.members.empty(); + } + + // Is this specific spell present under this type? + bool Contains(Code code, const LuaSpell* spell) const { + if (!in_range(code) || !spell) return false; + auto& s = slots_[code]; + std::shared_lock lk(s.mtx); + return s.members.find(const_cast(spell)) != s.members.end(); + } + + // How many spells are registered at this type? + size_t Count(Code code) const { + if (!in_range(code)) return 0; + auto& s = slots_[code]; + std::shared_lock lk(s.mtx); + return s.members.size(); + } + + // Snapshot list of spells under a type (copy out while holding a shared lock). + std::vector Snapshot(Code code) const { + std::vector out; + if (!in_range(code)) return out; + auto& s = slots_[code]; + std::shared_lock lk(s.mtx); + out.reserve(s.members.size()); + for (auto& kv : s.members) out.push_back(kv.first); + return out; + } + + // Snapshot of (spell, value) pairs under a type. + struct SpellWithValue { + LuaSpell* spell{}; + Value value{}; + }; + std::vector SnapshotWithValues(Code code) const { + std::vector out; + if (!in_range(code)) return out; + auto& s = slots_[code]; + std::shared_lock lk(s.mtx); + out.reserve(s.members.size()); + for (auto& kv : s.members) out.push_back({kv.second.ptr, kv.second.val}); + return out; + } + + // --- Per-spell value API -------------------------------------------------- + + // Set/replace the value for a specific spell under a type. + template + bool SetValue(Code code, LuaSpell* spell, T v) { + if (!in_range(code) || !spell) return false; + auto& s = slots_[code]; + std::unique_lock lk(s.mtx); + auto it = s.members.find(spell); + if (it == s.members.end()) return false; + it->second.val = to_variant(std::move(v)); + return true; + } + + // Clear value for a specific spell under a type (keeps membership). + bool ClearValue(Code code, LuaSpell* spell) { + if (!in_range(code) || !spell) return false; + auto& s = slots_[code]; + std::unique_lock lk(s.mtx); + auto it = s.members.find(spell); + if (it == s.members.end()) return false; + it->second.val = std::monostate{}; + return true; + } + + // Read value as requested type. nullopt if not set or wrong type. + template + std::optional GetValue(Code code, const LuaSpell* spell) const { + if (!in_range(code) || !spell) return std::nullopt; + auto& s = slots_[code]; + std::shared_lock lk(s.mtx); + auto it = s.members.find(const_cast(spell)); + if (it == s.members.end()) return std::nullopt; + if (auto p = std::get_if(&it->second.val)) return *p; + return std::nullopt; + } + + // Convenience typed getters + std::optional GetInt (Code code, const LuaSpell* s) const { return GetValue(code, s); } + std::optional GetFloat (Code code, const LuaSpell* s) const { return GetValue (code, s); } + std::optional GetString(Code code, const LuaSpell* s) const { return GetValue(code, s); } + + Code MaxCode() const { return max_code_; } + +private: + struct Entry { + LuaSpell* ptr{}; + Value val{}; + }; + struct Slot { + mutable std::shared_mutex mtx; + std::unordered_map members; // key = spell*, value = (spell*, variant) + }; + + bool in_range(Code code) const { return code <= max_code_; } + + // normalize to variant + static Value to_variant(int64_t v) { return Value{v}; } + static Value to_variant(int v) { return Value{static_cast(v)}; } + static Value to_variant(uint32_t v) { return Value{static_cast(v)}; } + static Value to_variant(float v) { return Value{static_cast(v)}; } + static Value to_variant(double v) { return Value{v}; } + static Value to_variant(const char* s) { return Value{std::string(s ? s : "")}; } + static Value to_variant(std::string s) { return Value{std::move(s)}; } + + Code max_code_; + std::vector slots_; +}; + +#define CONTROL_EFFECT_TYPE_MEZ 1 +#define CONTROL_EFFECT_TYPE_STIFLE 2 +#define CONTROL_EFFECT_TYPE_DAZE 3 +#define CONTROL_EFFECT_TYPE_STUN 4 +#define CONTROL_EFFECT_TYPE_ROOT 5 +#define CONTROL_EFFECT_TYPE_FEAR 6 +#define CONTROL_EFFECT_TYPE_WALKUNDERWATER 7 +#define CONTROL_EFFECT_TYPE_JUMPUNDERWATER 8 +#define CONTROL_EFFECT_TYPE_INVIS 9 +#define CONTROL_EFFECT_TYPE_STEALTH 10 +#define CONTROL_EFFECT_TYPE_SNARE 11 +#define CONTROL_EFFECT_TYPE_FLIGHT 12 +#define CONTROL_EFFECT_TYPE_GLIDE 13 +#define CONTROL_EFFECT_TYPE_SAFEFALL 14 +#define CONTROL_EFFECT_TYPE_ILLUSION 15 +#define CONTROL_MAX_EFFECTS 16 + +#define IMMUNITY_TYPE_MEZ 1 +#define IMMUNITY_TYPE_STIFLE 2 +#define IMMUNITY_TYPE_DAZE 3 +#define IMMUNITY_TYPE_STUN 4 +#define IMMUNITY_TYPE_ROOT 5 +#define IMMUNITY_TYPE_FEAR 6 +#define IMMUNITY_TYPE_AOE 7 +#define IMMUNITY_TYPE_TAUNT 8 +#define IMMUNITY_TYPE_RIPOSTE 9 +#define IMMUNITY_TYPE_STRIKETHROUGH 10 +#define IMMUNITY_MAX_TYPES 11 + +class ControlEffects { +public: + ControlEffects() : reg_(CONTROL_MAX_EFFECTS - 1) {} // max code = 14 + + bool Add(uint8_t type, LuaSpell* s) { return reg_.Add(type, s); } + template bool AddOrUpdate(uint8_t t, LuaSpell* s, T v){ return reg_.AddOrUpdate(t, s, std::move(v)); } + bool Remove(uint8_t type, LuaSpell* s) { return reg_.Remove(type, s); } + void Clear(uint8_t type) { reg_.Clear(type); } + + bool Has(uint8_t type) const { return reg_.Has(type); } + bool Contains(uint8_t type, const LuaSpell* s) const { return reg_.Contains(type, s); } + size_t Count(uint8_t type) const { return reg_.Count(type); } + std::vector Snapshot(uint8_t type) const { return reg_.Snapshot(type); } + auto SnapshotWithValues(uint8_t type) const { return reg_.SnapshotWithValues(type); } + + template bool SetValue(uint8_t t, LuaSpell* s, T v) { return reg_.SetValue(t, s, std::move(v)); } + bool ClearValue(uint8_t t, LuaSpell* s) { return reg_.ClearValue(t, s); } + + template std::optional GetValue(uint8_t t, const LuaSpell* s) const { return reg_.GetValue(t, s); } + +private: + EffectRegistryPerSpell reg_; +}; + +class Immunities { +public: + Immunities() : reg_(IMMUNITY_MAX_TYPES) {} // max code = 10 + + bool Add(uint8_t type, LuaSpell* s) { return reg_.Add(type, s); } + template bool AddOrUpdate(uint8_t t, LuaSpell* s, T v){ return reg_.AddOrUpdate(t, s, std::move(v)); } + bool Remove(uint8_t type, LuaSpell* s) { return reg_.Remove(type, s); } + void Clear(uint8_t type) { reg_.Clear(type); } + + bool Has(uint8_t type) const { return reg_.Has(type); } + bool Contains(uint8_t type, const LuaSpell* s) const { return reg_.Contains(type, s); } + size_t Count(uint8_t type) const { return reg_.Count(type); } + std::vector Snapshot(uint8_t type) const { return reg_.Snapshot(type); } + auto SnapshotWithValues(uint8_t type) const { return reg_.SnapshotWithValues(type); } + + template bool SetValue(uint8_t t, LuaSpell* s, T v) { return reg_.SetValue(t, s, std::move(v)); } + bool ClearValue(uint8_t t, LuaSpell* s) { return reg_.ClearValue(t, s); } + + template std::optional GetValue(uint8_t t, const LuaSpell* s) const { return reg_.GetValue(t, s); } + +private: + EffectRegistryPerSpell reg_; +}; \ No newline at end of file diff --git a/source/WorldServer/Entity.cpp b/source/WorldServer/Entity.cpp index 6838ee1..0fc3799 100644 --- a/source/WorldServer/Entity.cpp +++ b/source/WorldServer/Entity.cpp @@ -73,11 +73,6 @@ Entity::Entity(){ MMaintainedSpells.SetName("Entity::MMaintainedSpells"); MSpellEffects.SetName("Entity::MSpellEffects"); m_procList.clear(); - control_effects.clear(); - for (int i = 0; i < CONTROL_MAX_EFFECTS; i++) - control_effects[i] = NULL; - - immunities.clear(); info_struct.ResetEffects(this); @@ -101,15 +96,6 @@ Entity::~Entity(){ safe_delete(itr2.value); ClearProcs(); safe_delete(m_threatTransfer); - map*>::iterator itr3; - for (itr3 = control_effects.begin(); itr3 != control_effects.end(); itr3++) - safe_delete(itr3->second); - control_effects.clear(); - map*>::iterator itr4; - for (itr4 = immunities.begin(); itr4 != immunities.end(); itr4++) - safe_delete(itr4->second); - immunities.clear(); - safe_delete(m_threatTransfer); } void Entity::DeleteSpellEffects(bool removeClient) @@ -2067,15 +2053,10 @@ void Entity::CalculateSpellBonuses(ItemStatsValues* stats){ } void Entity::AddMezSpell(LuaSpell* spell) { - if (!spell) + if (!spell || IsMezImmune()) return; - - if (!control_effects[CONTROL_EFFECT_TYPE_MEZ]) - control_effects[CONTROL_EFFECT_TYPE_MEZ] = new MutexList; - - MutexList* mez_spells = control_effects[CONTROL_EFFECT_TYPE_MEZ]; - - if (IsPlayer() && !IsStunned() && !IsMezImmune() && mez_spells->size(true) == 0){ + + if (IsPlayer() && !IsStunned() && !control_effects.Has(CONTROL_EFFECT_TYPE_MEZ)){ ((Player*)this)->SetPlayerControlFlag(1, 16, true); if (!IsRooted()) ((Player*)this)->SetPlayerControlFlag(1, 8, true); @@ -2083,22 +2064,18 @@ void Entity::AddMezSpell(LuaSpell* spell) { GetZone()->LockAllSpells((Player*)this); } - if (IsNPC() && !IsMezImmune()) + if (IsNPC()) { HaltMovement(); } - mez_spells->Add(spell); + control_effects.Add(CONTROL_EFFECT_TYPE_MEZ, spell); } void Entity::RemoveMezSpell(LuaSpell* spell) { - MutexList* mez_spells = control_effects[CONTROL_EFFECT_TYPE_MEZ]; - if (!mez_spells || mez_spells->size(true) == 0) - return; - - mez_spells->Remove(spell); - if (mez_spells->size(true) == 0){ - if (IsPlayer() && !IsMezImmune() && !IsStunned()){ + control_effects.Remove(CONTROL_EFFECT_TYPE_MEZ, spell); + if (!control_effects.Has(CONTROL_EFFECT_TYPE_MEZ)){ + if (IsPlayer() && !IsStunned()){ if (!IsStifled() && !IsFeared()) GetZone()->UnlockAllSpells((Player*)this); ((Player*)this)->SetPlayerControlFlag(1, 16, false); @@ -2114,13 +2091,7 @@ void Entity::RemoveMezSpell(LuaSpell* spell) { } void Entity::RemoveAllMezSpells() { - MutexList* mez_spells = control_effects[CONTROL_EFFECT_TYPE_MEZ]; - if (!mez_spells) - return; - - MutexList::iterator itr = mez_spells->begin(); - while (itr.Next()){ - LuaSpell* spell = itr.value; + for (LuaSpell* spell : control_effects.Snapshot(CONTROL_EFFECT_TYPE_MEZ)) { if (!spell) continue; GetZone()->RemoveTargetFromSpell(spell, this); @@ -2129,9 +2100,8 @@ void Entity::RemoveAllMezSpells() { if (IsPlayer()) ((Player*)this)->RemoveSkillBonus(spell->spell->GetSpellID()); } - - mez_spells->clear(); - if (IsPlayer() && !IsMezImmune() && !IsStunned()){ + control_effects.Clear(CONTROL_EFFECT_TYPE_MEZ); + if (IsPlayer() && !IsStunned()){ if (!IsStifled() && !IsFeared()) GetZone()->UnlockAllSpells((Player*)this); ((Player*)this)->SetPlayerControlFlag(1, 16, false); @@ -2141,55 +2111,37 @@ void Entity::RemoveAllMezSpells() { } void Entity::AddStifleSpell(LuaSpell* spell) { - if (!spell) + if (!spell || IsStifleImmune() || IsMezzedOrStunned()) return; - if (!control_effects[CONTROL_EFFECT_TYPE_STIFLE]) - control_effects[CONTROL_EFFECT_TYPE_STIFLE] = new MutexList; - - if (IsPlayer() && control_effects[CONTROL_EFFECT_TYPE_STIFLE]->size(true) == 0 && !IsStifleImmune() && !IsMezzedOrStunned()) + if (IsPlayer() && !control_effects.Has(CONTROL_EFFECT_TYPE_STIFLE)) GetZone()->LockAllSpells((Player*)this); - control_effects[CONTROL_EFFECT_TYPE_STIFLE]->Add(spell); + control_effects.Add(CONTROL_EFFECT_TYPE_STIFLE, spell); } void Entity::RemoveStifleSpell(LuaSpell* spell) { - MutexList* stifle_list = control_effects[CONTROL_EFFECT_TYPE_STIFLE]; - if (!stifle_list || stifle_list->size(true) == 0) - return; - - stifle_list->Remove(spell); - - if (IsPlayer() && stifle_list->size(true) == 0 && !IsStifleImmune() && !IsMezzedOrStunned()) + control_effects.Remove(CONTROL_EFFECT_TYPE_STIFLE, spell); + if (IsPlayer() && !control_effects.Has(CONTROL_EFFECT_TYPE_STIFLE)) GetZone()->UnlockAllSpells((Player*)this); } void Entity::AddDazeSpell(LuaSpell* spell) { if (!spell) return; - - if (!control_effects[CONTROL_EFFECT_TYPE_DAZE]) - control_effects[CONTROL_EFFECT_TYPE_DAZE] = new MutexList; - - control_effects[CONTROL_EFFECT_TYPE_DAZE]->Add(spell); + + control_effects.Add(CONTROL_EFFECT_TYPE_DAZE, spell); } void Entity::RemoveDazeSpell(LuaSpell* spell) { - MutexList* daze_list = control_effects[CONTROL_EFFECT_TYPE_DAZE]; - if (!daze_list || daze_list->size(true) == 0) - return; - - daze_list->Remove(spell); + control_effects.Remove(CONTROL_EFFECT_TYPE_DAZE, spell); } void Entity::AddStunSpell(LuaSpell* spell) { - if (!spell) + if (!spell || IsStunImmune()) return; - if (!control_effects[CONTROL_EFFECT_TYPE_STUN]) - control_effects[CONTROL_EFFECT_TYPE_STUN] = new MutexList; - - if (IsPlayer() && control_effects[CONTROL_EFFECT_TYPE_STUN]->size(true) == 0 && !IsStunImmune()){ + if (IsPlayer() && !control_effects.Has(CONTROL_EFFECT_TYPE_STUN)){ if (!IsMezzed()){ ((Player*)this)->SetPlayerControlFlag(1, 16, true); if (!IsRooted()) @@ -2199,17 +2151,13 @@ void Entity::AddStunSpell(LuaSpell* spell) { } } - control_effects[CONTROL_EFFECT_TYPE_STUN]->Add(spell); + control_effects.Add(CONTROL_EFFECT_TYPE_STUN, spell); } void Entity::RemoveStunSpell(LuaSpell* spell) { - MutexList* stun_list = control_effects[CONTROL_EFFECT_TYPE_STUN]; - if (!stun_list || stun_list->size(true) == 0) - return; - - stun_list->Remove(spell); - if (stun_list->size(true) == 0){ - if (IsPlayer() && !IsMezzed() && !IsStunImmune()){ + control_effects.Remove(CONTROL_EFFECT_TYPE_STUN, spell); + if (!control_effects.Has(CONTROL_EFFECT_TYPE_STUN)){ + if (IsPlayer() && !IsMezzed()){ ((Player*)this)->SetPlayerControlFlag(1, 16, false); if (!IsRooted()) ((Player*)this)->SetPlayerControlFlag(1, 8, false); @@ -2555,6 +2503,8 @@ int32 Entity::CheckWards(Entity* attacker, int32 damage, int8 damage_type) { for (auto it = tmp_deletes.begin(); it != tmp_deletes.end(); ++it) { GetZone()->GetSpellProcess()->DeleteCasterSpell(*it, "purged"); + // maybe this instead: + //GetZone()->GetSpellProcess()->DeleteCasterSpell(*it, "purged", false, this); } return damage; } @@ -2881,34 +2831,35 @@ DetrimentalEffects* Entity::GetDetrimentalEffect(int32 spell_id, Entity* caster) void Entity::CancelAllStealth() { bool did_change = false; - MutexList* stealth_list = control_effects[CONTROL_EFFECT_TYPE_STEALTH]; - if (stealth_list){ - MutexList::iterator itr = stealth_list->begin(); - while (itr.Next()){ - if (itr.value->caster == this) - GetZone()->GetSpellProcess()->AddSpellCancel(itr.value); - else{ - GetZone()->RemoveTargetFromSpell(itr.value, this); - RemoveSpellEffect(itr.value); - } - did_change = true; + + for (LuaSpell* spell : control_effects.Snapshot(CONTROL_EFFECT_TYPE_STEALTH)) { + if (!spell) + continue; + + if (spell->caster == this) + GetZone()->GetSpellProcess()->AddSpellCancel(spell); + else{ + GetZone()->RemoveTargetFromSpell(spell, this); + RemoveSpellEffect(spell); } - stealth_list->clear(); + did_change = true; } - MutexList* invis_list = control_effects[CONTROL_EFFECT_TYPE_INVIS]; - if (invis_list){ - MutexList::iterator invis_itr = invis_list->begin(); - while (invis_itr.Next()){ - if (invis_itr.value->caster == this) - GetZone()->GetSpellProcess()->AddSpellCancel(invis_itr.value); - else{ - GetZone()->RemoveTargetFromSpell(invis_itr.value, this); - RemoveSpellEffect(invis_itr.value); - } - did_change = true; + control_effects.Clear(CONTROL_EFFECT_TYPE_STEALTH); + + + for (LuaSpell* spell : control_effects.Snapshot(CONTROL_EFFECT_TYPE_INVIS)) { + if (!spell) + continue; + + if (spell->caster == this) + GetZone()->GetSpellProcess()->AddSpellCancel(spell); + else{ + GetZone()->RemoveTargetFromSpell(spell, this); + RemoveSpellEffect(spell); } - invis_list->clear(); + did_change = true; } + control_effects.Clear(CONTROL_EFFECT_TYPE_INVIS); if (did_change){ info_changed = true; @@ -2922,8 +2873,7 @@ void Entity::CancelAllStealth() { } bool Entity::IsStealthed(){ - MutexList* stealth_list = control_effects[CONTROL_EFFECT_TYPE_STEALTH]; - return (!stealth_list || stealth_list->size(true) == 0) == false; + return control_effects.Has(CONTROL_EFFECT_TYPE_STEALTH); } bool Entity::CanSeeInvis(Entity* target) { @@ -2941,19 +2891,14 @@ bool Entity::CanSeeInvis(Entity* target) { } bool Entity::IsInvis(){ - MutexList* invis_list = control_effects[CONTROL_EFFECT_TYPE_INVIS]; - return (!invis_list || invis_list->size(true) == 0) == false; + return control_effects.Has(CONTROL_EFFECT_TYPE_INVIS); } void Entity::AddStealthSpell(LuaSpell* spell) { if (!spell) return; - - if (!control_effects[CONTROL_EFFECT_TYPE_STEALTH]) - control_effects[CONTROL_EFFECT_TYPE_STEALTH] = new MutexList; - - control_effects[CONTROL_EFFECT_TYPE_STEALTH]->Add(spell); - if (control_effects[CONTROL_EFFECT_TYPE_STEALTH]->size(true) == 1){ + control_effects.Add(CONTROL_EFFECT_TYPE_STEALTH, spell); + if (control_effects.Has(CONTROL_EFFECT_TYPE_STEALTH)){ info_changed = true; changed = true; AddChangedZoneSpawn(); @@ -2969,11 +2914,8 @@ void Entity::AddInvisSpell(LuaSpell* spell) { if (!spell) return; - if (!control_effects[CONTROL_EFFECT_TYPE_INVIS]) - control_effects[CONTROL_EFFECT_TYPE_INVIS] = new MutexList; - - control_effects[CONTROL_EFFECT_TYPE_INVIS]->Add(spell); - if (control_effects[CONTROL_EFFECT_TYPE_INVIS]->size(true) == 1){ + control_effects.Add(CONTROL_EFFECT_TYPE_INVIS, spell); + if (control_effects.Has(CONTROL_EFFECT_TYPE_INVIS)){ info_changed = true; changed = true; AddChangedZoneSpawn(); @@ -2986,13 +2928,9 @@ void Entity::AddInvisSpell(LuaSpell* spell) { } void Entity::RemoveInvisSpell(LuaSpell* spell) { - MutexList* invis_list = control_effects[CONTROL_EFFECT_TYPE_INVIS]; - if (!invis_list || invis_list->size(true) == 0) - return; - - invis_list->Remove(spell); + control_effects.Remove(CONTROL_EFFECT_TYPE_INVIS, spell); RemoveSpellEffect(spell); - if (invis_list->size(true) == 0){ + if (!control_effects.Has(CONTROL_EFFECT_TYPE_INVIS)){ info_changed = true; changed = true; AddChangedZoneSpawn(); @@ -3005,13 +2943,9 @@ void Entity::RemoveInvisSpell(LuaSpell* spell) { } void Entity::RemoveStealthSpell(LuaSpell* spell) { - MutexList* stealth_list = control_effects[CONTROL_EFFECT_TYPE_STEALTH]; - if (!stealth_list || stealth_list->size(true) == 0) - return; - - stealth_list->Remove(spell); + control_effects.Remove(CONTROL_EFFECT_TYPE_STEALTH, spell); RemoveSpellEffect(spell); - if (stealth_list->size() == 0){ + if (!control_effects.Has(CONTROL_EFFECT_TYPE_STEALTH)){ info_changed = true; changed = true; AddChangedZoneSpawn(); @@ -3024,13 +2958,10 @@ void Entity::RemoveStealthSpell(LuaSpell* spell) { } void Entity::AddRootSpell(LuaSpell* spell) { - if (!spell) + if (!spell || IsRootImmune()) return; - - if (!control_effects[CONTROL_EFFECT_TYPE_ROOT]) - control_effects[CONTROL_EFFECT_TYPE_ROOT] = new MutexList; - - if (control_effects[CONTROL_EFFECT_TYPE_ROOT]->size(true) == 0 && !IsRootImmune()) { + + if (!control_effects.Has(CONTROL_EFFECT_TYPE_ROOT)) { if (IsPlayer()){ if (!IsMezzedOrStunned()) ((Player*)this)->SetPlayerControlFlag(1, 8, true); // heading movement only @@ -3039,16 +2970,12 @@ void Entity::AddRootSpell(LuaSpell* spell) { SetSpeedMultiplier(0.0f); } - control_effects[CONTROL_EFFECT_TYPE_ROOT]->Add(spell); + control_effects.Add(CONTROL_EFFECT_TYPE_ROOT, spell); } void Entity::RemoveRootSpell(LuaSpell* spell) { - MutexList* root_list = control_effects[CONTROL_EFFECT_TYPE_ROOT]; - if (!root_list || root_list->size(true) == 0) - return; - - root_list->Remove(spell); - if (root_list->size(true) == 0 && !IsRootImmune()) { + control_effects.Remove(CONTROL_EFFECT_TYPE_ROOT, spell); + if (!control_effects.Has(CONTROL_EFFECT_TYPE_ROOT)) { if (IsPlayer()){ if (!IsMezzedOrStunned()) ((Player*)this)->SetPlayerControlFlag(1, 8, false); // heading movement only @@ -3066,34 +2993,26 @@ void Entity::RemoveRootSpell(LuaSpell* spell) { } void Entity::AddFearSpell(LuaSpell* spell){ - if (!spell) + if (!spell || IsFearImmune()) return; - if (!control_effects[CONTROL_EFFECT_TYPE_FEAR]) - control_effects[CONTROL_EFFECT_TYPE_FEAR] = new MutexList; - - if (IsPlayer() && control_effects[CONTROL_EFFECT_TYPE_FEAR]->size(true) == 0 && !IsFearImmune()){ + if (IsPlayer() && control_effects.Has(CONTROL_EFFECT_TYPE_FEAR)){ ((Player*)this)->SetPlayerControlFlag(4, 4, true); // feared if (!IsMezzedOrStunned() && !IsStifled()) GetZone()->LockAllSpells((Player*)this); } - if (!IsFearImmune() && IsNPC()) + if (IsNPC()) { HaltMovement(); } - control_effects[CONTROL_EFFECT_TYPE_FEAR]->Add(spell); + control_effects.Add(CONTROL_EFFECT_TYPE_FEAR, spell); } void Entity::RemoveFearSpell(LuaSpell* spell){ - MutexList* fear_list = control_effects[CONTROL_EFFECT_TYPE_FEAR]; - if (!fear_list || fear_list->size(true) == 0) - return; - - fear_list->Remove(spell); - - if (IsPlayer() && fear_list->size(true) == 0 && !IsFearImmune()){ + control_effects.Remove(CONTROL_EFFECT_TYPE_FEAR, spell); + if (IsPlayer() && !control_effects.Has(CONTROL_EFFECT_TYPE_FEAR)){ ((Player*)this)->SetPlayerControlFlag(4, 4, false); // feared disabled if (!IsMezzedOrStunned() && !IsStifled()) GetZone()->LockAllSpells((Player*)this); @@ -3106,35 +3025,23 @@ void Entity::RemoveFearSpell(LuaSpell* spell){ } void Entity::AddSnareSpell(LuaSpell* spell) { - if (!spell) - return; + control_effects.Add(CONTROL_EFFECT_TYPE_SNARE, spell); - if (!control_effects[CONTROL_EFFECT_TYPE_SNARE]) - control_effects[CONTROL_EFFECT_TYPE_SNARE] = new MutexList; - - control_effects[CONTROL_EFFECT_TYPE_SNARE]->Add(spell); - - // Don't set speed multiplier if there is a root or no snare values - MutexList* roots = control_effects[CONTROL_EFFECT_TYPE_ROOT]; - if ((!roots || roots->size(true) == 0) && snare_values.size() > 0) + if (!control_effects.Has(CONTROL_EFFECT_TYPE_ROOT) && control_effects.Has(CONTROL_EFFECT_TYPE_SNARE)) SetSpeedMultiplier(GetHighestSnare()); } void Entity::RemoveSnareSpell(LuaSpell* spell) { - MutexList* snare_list = control_effects[CONTROL_EFFECT_TYPE_SNARE]; - if (!snare_list || snare_list->size(true) == 0) - return; - - snare_list->Remove(spell); - snare_values.erase(spell); - - //LogWrite(PLAYER__ERROR, 0, "Debug", "snare_values.size() = %u", snare_values.size()); - - // only change speeds if there are no roots - MutexList* roots = control_effects[CONTROL_EFFECT_TYPE_ROOT]; - if (!roots || roots->size(true) == 0) { + control_effects.Remove(CONTROL_EFFECT_TYPE_SNARE, spell); + { + std::unique_lock lock(MSnareValues); + snare_values.erase(spell); + } + if (control_effects.Has(CONTROL_EFFECT_TYPE_SNARE)) { + SetSpeedMultiplier(GetHighestSnare()); + } + else if (!control_effects.Has(CONTROL_EFFECT_TYPE_ROOT)) { float multiplier = GetHighestSnare(); - //LogWrite(PLAYER__ERROR, 0, "Debug", "GetHighestSnare() = %f", multiplier); SetSpeedMultiplier(multiplier); } } @@ -3143,7 +3050,10 @@ void Entity::SetSnareValue(LuaSpell* spell, float snare_val) { if (!spell) return; - snare_values[spell] = snare_val; + { + std::unique_lock lock(MSnareValues); + snare_values[spell] = snare_val; + } } float Entity::GetHighestSnare() { @@ -3168,115 +3078,75 @@ float Entity::GetHighestSnare() { weight_diff = weight_pct_cap; // cap weight impact rule } } - if (snare_values.size() == 0) - return ((ret - weight_diff) < 0.0f ) ? 0.0f : (ret - weight_diff); + + { + std::shared_lock rlock(MSnareValues); + if (snare_values.size() == 0) + return ((ret - weight_diff) < 0.0f ) ? 0.0f : (ret - weight_diff); - map::iterator itr; - for (itr = snare_values.begin(); itr != snare_values.end(); itr++) { - if (itr->second < ret) - ret = itr->second; + map::iterator itr; + for (itr = snare_values.begin(); itr != snare_values.end(); itr++) { + if (itr->second < ret) + ret = itr->second; + } } return ((ret - weight_diff) < 0.0f ) ? 0.0f : (ret - weight_diff); } bool Entity::IsSnared() { - if (control_effects.size() < 1 || !control_effects[CONTROL_EFFECT_TYPE_SNARE]) - return false; - - MutexList* snare_list = control_effects[CONTROL_EFFECT_TYPE_SNARE]; - return (!snare_list || snare_list->size(true) == 0) == false; + return control_effects.Has(CONTROL_EFFECT_TYPE_SNARE); } bool Entity::IsMezzed(){ - if (control_effects.size() < 1 || !control_effects[CONTROL_EFFECT_TYPE_MEZ]) - return false; - - MutexList* mez_spells = control_effects[CONTROL_EFFECT_TYPE_MEZ]; - return (!mez_spells || mez_spells->size(true) == 0 || IsMezImmune()) == false; + return control_effects.Has(CONTROL_EFFECT_TYPE_MEZ); } bool Entity::IsStifled(){ - if (!control_effects[CONTROL_EFFECT_TYPE_STIFLE]) - return false; - - MutexList* stifle_list = control_effects[CONTROL_EFFECT_TYPE_STIFLE]; - return (!stifle_list || stifle_list->size(true) == 0 || IsStifleImmune()) == false; + return control_effects.Has(CONTROL_EFFECT_TYPE_STIFLE); } bool Entity::IsDazed(){ - if (control_effects.size() < 1 || !control_effects[CONTROL_EFFECT_TYPE_DAZE]) - return false; - - MutexList* daze_list = control_effects[CONTROL_EFFECT_TYPE_DAZE]; - return (!daze_list || daze_list->size(true) == 0 || IsDazeImmune()) == false; + return control_effects.Has(CONTROL_EFFECT_TYPE_DAZE); } bool Entity::IsStunned(){ - if (!control_effects[CONTROL_EFFECT_TYPE_STUN]) - return false; - - MutexList* stun_list = control_effects[CONTROL_EFFECT_TYPE_STUN]; - return (!stun_list || stun_list->size(true) == 0 || IsStunImmune()) == false; + return control_effects.Has(CONTROL_EFFECT_TYPE_STUN); } bool Entity::IsRooted(){ - if (control_effects.size() < 1 || !control_effects[CONTROL_EFFECT_TYPE_ROOT]) - return false; - - MutexList* root_list = control_effects[CONTROL_EFFECT_TYPE_ROOT]; - return (!root_list || root_list->size(true) == 0 || IsRootImmune()) == false; + return control_effects.Has(CONTROL_EFFECT_TYPE_ROOT); } bool Entity::IsFeared(){ - if (control_effects.size() < 1 || !control_effects[CONTROL_EFFECT_TYPE_FEAR]) - return false; - - MutexList* fear_list = control_effects[CONTROL_EFFECT_TYPE_FEAR]; - return (!fear_list || fear_list->size(true) == 0 || IsFearImmune()) == false; + return control_effects.Has(CONTROL_EFFECT_TYPE_FEAR); } void Entity::AddWaterwalkSpell(LuaSpell* spell){ if (!spell) return; - if (!control_effects[CONTROL_EFFECT_TYPE_WALKUNDERWATER]) - control_effects[CONTROL_EFFECT_TYPE_WALKUNDERWATER] = new MutexList; - - control_effects[CONTROL_EFFECT_TYPE_WALKUNDERWATER]->Add(spell); - if (control_effects[CONTROL_EFFECT_TYPE_WALKUNDERWATER]->size(true) == 1 && IsPlayer()) + control_effects.Add(CONTROL_EFFECT_TYPE_WALKUNDERWATER, spell); + if (control_effects.Has(CONTROL_EFFECT_TYPE_WALKUNDERWATER) && IsPlayer()) ((Player*)this)->SetPlayerControlFlag(3, 128, true); // enable walking underwater } void Entity::RemoveWaterwalkSpell(LuaSpell* spell){ - MutexList* waterwalk_list = control_effects[CONTROL_EFFECT_TYPE_WALKUNDERWATER]; - if (!waterwalk_list || waterwalk_list->size(true) == 0) - return; - - waterwalk_list->Remove(spell); - if (waterwalk_list->size(true) == 0 && IsPlayer()) + control_effects.Remove(CONTROL_EFFECT_TYPE_WALKUNDERWATER, spell); + if (!control_effects.Has(CONTROL_EFFECT_TYPE_WALKUNDERWATER) && IsPlayer()){ ((Player*)this)->SetPlayerControlFlag(3, 128, false); // disable walking underwater + } } void Entity::AddWaterjumpSpell(LuaSpell* spell){ - if (!spell) - return; - - if (!control_effects[CONTROL_EFFECT_TYPE_JUMPUNDERWATER]) - control_effects[CONTROL_EFFECT_TYPE_JUMPUNDERWATER] = new MutexList; - - control_effects[CONTROL_EFFECT_TYPE_JUMPUNDERWATER]->Add(spell); - if (control_effects[CONTROL_EFFECT_TYPE_JUMPUNDERWATER]->size(true) == 1 && IsPlayer()) + control_effects.Add(CONTROL_EFFECT_TYPE_JUMPUNDERWATER, spell); + if (control_effects.Has(CONTROL_EFFECT_TYPE_JUMPUNDERWATER) && IsPlayer()) ((Player*)this)->SetPlayerControlFlag(4, 1, true); // enable moonjumps underwater } void Entity::RemoveWaterjumpSpell(LuaSpell* spell){ - MutexList* waterjump_list = control_effects[CONTROL_EFFECT_TYPE_JUMPUNDERWATER]; - if (!waterjump_list || waterjump_list->size(true) == 0) - return; - - waterjump_list->Remove(spell); - if (waterjump_list->size(true) == 0 && IsPlayer()) + control_effects.Remove(CONTROL_EFFECT_TYPE_JUMPUNDERWATER, spell); + if (!control_effects.Has(CONTROL_EFFECT_TYPE_JUMPUNDERWATER) && IsPlayer()) ((Player*)this)->SetPlayerControlFlag(4, 1, false); // disable moonjumps underwater } @@ -3284,45 +3154,32 @@ void Entity::AddAOEImmunity(LuaSpell* spell){ if (!spell) return; - if (!immunities[IMMUNITY_TYPE_AOE]) - immunities[IMMUNITY_TYPE_AOE] = new MutexList; - - immunities[IMMUNITY_TYPE_AOE]->Add(spell); + immunities.Add(IMMUNITY_TYPE_AOE, spell); } void Entity::RemoveAOEImmunity(LuaSpell* spell){ - MutexList* aoe_list = immunities[IMMUNITY_TYPE_AOE]; - if (!aoe_list || aoe_list->size(true) == 0) - return; - aoe_list->Remove(spell); + immunities.Remove(IMMUNITY_TYPE_AOE, spell); } bool Entity::IsAOEImmune(){ - return (immunities[IMMUNITY_TYPE_AOE] && immunities[IMMUNITY_TYPE_AOE]->size(true)); + return immunities.Has(IMMUNITY_TYPE_AOE); } void Entity::AddStunImmunity(LuaSpell* spell){ if (!spell) return; - - if (!immunities[IMMUNITY_TYPE_STUN]) - immunities[IMMUNITY_TYPE_STUN] = new MutexList; - + if (IsPlayer() && IsStunned() && !IsMezzed()){ ((Player*)this)->SetPlayerControlFlag(4, 64, false); if (!IsFeared() && !IsStifled()) ((Player*)this)->UnlockAllSpells(); } - immunities[IMMUNITY_TYPE_STUN]->Add(spell); + immunities.Add(IMMUNITY_TYPE_STUN, spell); } void Entity::RemoveStunImmunity(LuaSpell* spell){ - MutexList* stun_list = immunities[IMMUNITY_TYPE_STUN]; - if (!stun_list || stun_list->size(true) == 0) - return; - - stun_list->Remove(spell); + immunities.Remove(IMMUNITY_TYPE_STUN, spell); if (IsPlayer() && IsStunned() && !IsMezzed()){ ((Player*)this)->SetPlayerControlFlag(4, 64, true); @@ -3332,61 +3189,47 @@ void Entity::RemoveStunImmunity(LuaSpell* spell){ } bool Entity::IsStunImmune(){ - return (immunities[IMMUNITY_TYPE_STUN] && immunities[IMMUNITY_TYPE_STUN]->size(true) > 0); + return immunities.Has(IMMUNITY_TYPE_STUN); } void Entity::AddStifleImmunity(LuaSpell* spell){ if (!spell) return; - - if (!immunities[IMMUNITY_TYPE_STIFLE]) - immunities[IMMUNITY_TYPE_STIFLE] = new MutexList; - - if (IsPlayer() && immunities[IMMUNITY_TYPE_STIFLE]->size(true) == 0){ + + if (IsPlayer() && !immunities.Has(IMMUNITY_TYPE_STIFLE)){ if (IsStifled() && !IsMezzedOrStunned() && !IsFeared()) ((Player*)this)->UnlockAllSpells(); } - immunities[IMMUNITY_TYPE_STIFLE]->Add(spell); + immunities.Add(IMMUNITY_TYPE_STIFLE, spell); } void Entity::RemoveStifleImmunity(LuaSpell* spell){ - MutexList* stifle_list = immunities[IMMUNITY_TYPE_STIFLE]; - if (!stifle_list || stifle_list->size(true) == 0) - return; - - stifle_list->Remove(spell); + immunities.Remove(IMMUNITY_TYPE_STIFLE, spell); if (IsPlayer() && IsStifled() && !IsMezzedOrStunned() && !IsFeared()) ((Player*)this)->UnlockAllSpells(); } bool Entity::IsStifleImmune(){ - return (immunities[IMMUNITY_TYPE_STIFLE] && immunities[IMMUNITY_TYPE_STIFLE]->size(true) > 0); + return immunities.Has(IMMUNITY_TYPE_STIFLE); } void Entity::AddMezImmunity(LuaSpell* spell){ if (!spell) return; - - if (!immunities[IMMUNITY_TYPE_MEZ]) - immunities[IMMUNITY_TYPE_MEZ] = new MutexList; - + if (IsPlayer() && IsMezzed() && !IsStunned()){ ((Player*)this)->SetPlayerControlFlag(4, 64, false); if (!IsFeared() && !IsStifled()) ((Player*)this)->UnlockAllSpells(); } - immunities[IMMUNITY_TYPE_MEZ]->Add(spell); + immunities.Add(IMMUNITY_TYPE_MEZ, spell); } void Entity::RemoveMezImmunity(LuaSpell* spell){ - MutexList* mez_list = immunities[IMMUNITY_TYPE_MEZ]; - if (!mez_list || mez_list->size(true) == 0) - return; - - mez_list->Remove(spell); + immunities.Remove(IMMUNITY_TYPE_MEZ, spell); if (IsPlayer() && IsMezzed() && !IsStunned()){ ((Player*)this)->SetPlayerControlFlag(4, 64, true); @@ -3396,59 +3239,45 @@ void Entity::RemoveMezImmunity(LuaSpell* spell){ } bool Entity::IsMezImmune(){ - return (immunities[IMMUNITY_TYPE_MEZ] && immunities[IMMUNITY_TYPE_MEZ]->size(true) > 0); + return immunities.Has(IMMUNITY_TYPE_MEZ); } void Entity::AddRootImmunity(LuaSpell* spell){ if (!spell) return; - - if (!immunities[IMMUNITY_TYPE_ROOT]) - immunities[IMMUNITY_TYPE_ROOT] = new MutexList; - + if (IsPlayer() && IsRooted()) ((Player*)this)->SetPlayerControlFlag(1, 8, false); - immunities[IMMUNITY_TYPE_ROOT]->Add(spell); + immunities.Add(IMMUNITY_TYPE_ROOT, spell); } void Entity::RemoveRootImmunity(LuaSpell* spell){ - MutexList* root_list = immunities[IMMUNITY_TYPE_ROOT]; - if (!root_list || root_list->size(true) == 0) - return; - - root_list->Remove(spell); - + immunities.Remove(IMMUNITY_TYPE_ROOT, spell); + if (IsPlayer() && IsRooted()) ((Player*)this)->SetPlayerControlFlag(1, 8, true); } bool Entity::IsRootImmune(){ - return (immunities[IMMUNITY_TYPE_ROOT] && immunities[IMMUNITY_TYPE_ROOT]->size(true) > 0); + return immunities.Has(IMMUNITY_TYPE_ROOT); } void Entity::AddFearImmunity(LuaSpell* spell){ if (!spell) return; - if (!immunities[IMMUNITY_TYPE_FEAR]) - immunities[IMMUNITY_TYPE_FEAR] = new MutexList; - if (IsPlayer() && IsFeared()){ if (!IsMezzedOrStunned() && !IsStifled()) ((Player*)this)->UnlockAllSpells(); ((Player*)this)->SetPlayerControlFlag(4, 4, false); } - immunities[IMMUNITY_TYPE_FEAR]->Add(spell); + immunities.Add(IMMUNITY_TYPE_FEAR, spell); } void Entity::RemoveFearImmunity(LuaSpell* spell){ - MutexList* fear_list = immunities[IMMUNITY_TYPE_FEAR]; - if (!fear_list || fear_list->size(true) == 0) - return; - - fear_list->Remove(spell); + immunities.Remove(IMMUNITY_TYPE_FEAR, spell); if (IsPlayer() && IsFeared()){ if (!IsMezzedOrStunned() && !IsStifled()) @@ -3458,108 +3287,94 @@ void Entity::RemoveFearImmunity(LuaSpell* spell){ } bool Entity::IsFearImmune(){ - return (immunities[IMMUNITY_TYPE_FEAR] && immunities[IMMUNITY_TYPE_FEAR]->size(true) > 0); + return immunities.Has(IMMUNITY_TYPE_FEAR); } void Entity::AddDazeImmunity(LuaSpell* spell){ if (!spell) return; - if (!immunities[IMMUNITY_TYPE_DAZE]) - immunities[IMMUNITY_TYPE_DAZE] = new MutexList; - - immunities[IMMUNITY_TYPE_DAZE]->Add(spell); + immunities.Add(IMMUNITY_TYPE_DAZE, spell); } void Entity::RemoveDazeImmunity(LuaSpell* spell){ - MutexList* daze_list = immunities[IMMUNITY_TYPE_DAZE]; - if (!daze_list || daze_list->size(true) == 0) - return; - - daze_list->Remove(spell); + immunities.Remove(IMMUNITY_TYPE_DAZE, spell); } bool Entity::IsDazeImmune(){ - return (immunities[IMMUNITY_TYPE_DAZE] && immunities[IMMUNITY_TYPE_DAZE]->size(true) > 0); + return immunities.Has(IMMUNITY_TYPE_DAZE); } void Entity::AddImmunity(LuaSpell* spell, int8 type){ if (!spell) return; - - if (!immunities[type]) - immunities[type] = new MutexList; - - immunities[type]->Add(spell); + + immunities.Add(type, spell); } void Entity::RemoveImmunity(LuaSpell* spell, int8 type){ - MutexList* list = immunities[type]; - if (!list || list->size(true) == 0) - return; - - list->Remove(spell); + immunities.Remove(type, spell); } bool Entity::IsImmune(int8 type){ - return (immunities[type] && immunities[type]->size(true) > 0); + return immunities.Has(type); } void Entity::RemoveEffectsFromLuaSpell(LuaSpell* spell){ if (!spell) return; - //Attempt to remove all applied effects from this spell when spell has been removed from just this target. Should improve performance/easier maitenance - int32 effect_bitmask = spell->effect_bitmask; - if (effect_bitmask == 0) + if (spell->effect_flags.none()) return; - if (effect_bitmask & EFFECT_FLAG_STUN) + if (spell->effect_flags.has(EFFECT_IDX_STUN)) RemoveStunSpell(spell); - if (effect_bitmask & EFFECT_FLAG_ROOT) + if (spell->effect_flags.has(EFFECT_IDX_ROOT)) RemoveRootSpell(spell); - if (effect_bitmask & EFFECT_FLAG_MEZ) + if (spell->effect_flags.has(EFFECT_IDX_MEZ)) RemoveMezSpell(spell); - if (effect_bitmask & EFFECT_FLAG_STIFLE) + if (spell->effect_flags.has(EFFECT_IDX_STIFLE)) RemoveStifleSpell(spell); - if (effect_bitmask & EFFECT_FLAG_DAZE) + if (spell->effect_flags.has(EFFECT_IDX_DAZE)) RemoveDazeSpell(spell); - if (effect_bitmask & EFFECT_FLAG_FEAR) + if (spell->effect_flags.has(EFFECT_IDX_FEAR)) RemoveFearSpell(spell); - if (effect_bitmask & EFFECT_FLAG_SPELLBONUS) + if (spell->effect_flags.has(EFFECT_IDX_SPELLBONUS)) RemoveSpellBonus(spell); - if (effect_bitmask & EFFECT_FLAG_SKILLBONUS) + if (spell->effect_flags.has(EFFECT_IDX_SKILLBONUS)) RemoveSkillBonus(spell->spell->GetSpellID()); - if (effect_bitmask & EFFECT_FLAG_STEALTH) + if (spell->effect_flags.has(EFFECT_IDX_STEALTH)) RemoveStealthSpell(spell); - if (effect_bitmask & EFFECT_FLAG_INVIS) + if (spell->effect_flags.has(EFFECT_IDX_INVIS)) RemoveInvisSpell(spell); - if (effect_bitmask & EFFECT_FLAG_SNARE) + if (spell->effect_flags.has(EFFECT_IDX_SNARE)) RemoveSnareSpell(spell); - if (effect_bitmask & EFFECT_FLAG_WATERWALK) + if (spell->effect_flags.has(EFFECT_IDX_WATERWALK)) RemoveWaterwalkSpell(spell); - if (effect_bitmask & EFFECT_FLAG_WATERJUMP) + if (spell->effect_flags.has(EFFECT_IDX_WATERJUMP)) RemoveWaterjumpSpell(spell); - if (effect_bitmask & EFFECT_FLAG_FLIGHT) + if (spell->effect_flags.has(EFFECT_IDX_FLIGHT)) RemoveFlightSpell(spell); - if (effect_bitmask & EFFECT_FLAG_GLIDE) + if (spell->effect_flags.has(EFFECT_IDX_GLIDE)) RemoveGlideSpell(spell); - if (effect_bitmask & EFFECT_FLAG_AOE_IMMUNE) + if (spell->effect_flags.has(EFFECT_IDX_AOE_IMMUNE)) RemoveAOEImmunity(spell); - if (effect_bitmask & EFFECT_FLAG_STUN_IMMUNE) + if (spell->effect_flags.has(EFFECT_IDX_STUN_IMMUNE)) RemoveStunImmunity(spell); - if (effect_bitmask & EFFECT_FLAG_MEZ_IMMUNE) + if (spell->effect_flags.has(EFFECT_IDX_MEZ_IMMUNE)) RemoveMezImmunity(spell); - if (effect_bitmask & EFFECT_FLAG_DAZE_IMMUNE) + if (spell->effect_flags.has(EFFECT_IDX_DAZE_IMMUNE)) RemoveDazeImmunity(spell); - if (effect_bitmask & EFFECT_FLAG_ROOT_IMMUNE) + if (spell->effect_flags.has(EFFECT_IDX_ROOT_IMMUNE)) RemoveRootImmunity(spell); - if (effect_bitmask & EFFECT_FLAG_STIFLE_IMMUNE) + if (spell->effect_flags.has(EFFECT_IDX_STIFLE_IMMUNE)) RemoveStifleImmunity(spell); - if (effect_bitmask & EFFECT_FLAG_FEAR_IMMUNE) + if (spell->effect_flags.has(EFFECT_IDX_FEAR_IMMUNE)) RemoveFearImmunity(spell); - if (effect_bitmask & EFFECT_FLAG_SAFEFALL) + if (spell->effect_flags.has(EFFECT_IDX_SAFEFALL)) RemoveSafefallSpell(spell); + if (spell->effect_flags.has(EFFECT_IDX_ILLUSION)) + RemoveIllusionSpell(spell); } void Entity::RemoveSkillBonus(int32 spell_id){ @@ -3570,23 +3385,16 @@ void Entity::RemoveSkillBonus(int32 spell_id){ void Entity::AddFlightSpell(LuaSpell* spell){ if (!spell) return; - - if (!control_effects[CONTROL_EFFECT_TYPE_FLIGHT]) - control_effects[CONTROL_EFFECT_TYPE_FLIGHT] = new MutexList; - - if (IsPlayer() && control_effects[CONTROL_EFFECT_TYPE_FLIGHT]->size(true) == 0) + + if (IsPlayer() && !control_effects.Has(CONTROL_EFFECT_TYPE_FLIGHT)) ((Player*)this)->SetPlayerControlFlag(5, 32, true); - control_effects[CONTROL_EFFECT_TYPE_FLIGHT]->Add(spell); + control_effects.Add(CONTROL_EFFECT_TYPE_FLIGHT, spell); } void Entity::RemoveFlightSpell(LuaSpell* spell){ - MutexList* flight_list = control_effects[CONTROL_EFFECT_TYPE_FLIGHT]; - if (!flight_list || flight_list->size(true) == 0) - return; - - flight_list->Remove(spell); - if (IsPlayer() && flight_list->size(true) == 0) + control_effects.Remove(CONTROL_EFFECT_TYPE_FLIGHT, spell); + if (IsPlayer() && !control_effects.Has(CONTROL_EFFECT_TYPE_FLIGHT)) ((Player*)this)->SetPlayerControlFlag(5, 32, false); } @@ -3594,22 +3402,15 @@ void Entity::AddGlideSpell(LuaSpell* spell){ if (!spell) return; - if (!control_effects[CONTROL_EFFECT_TYPE_GLIDE]) - control_effects[CONTROL_EFFECT_TYPE_GLIDE] = new MutexList; - - if (IsPlayer() && control_effects[CONTROL_EFFECT_TYPE_GLIDE]->size(true) == 0) + if (IsPlayer() && !control_effects.Has(CONTROL_EFFECT_TYPE_GLIDE)) ((Player*)this)->SetPlayerControlFlag(4, 16, true); - control_effects[CONTROL_EFFECT_TYPE_GLIDE]->Add(spell); + control_effects.Add(CONTROL_EFFECT_TYPE_GLIDE, spell); } void Entity::RemoveGlideSpell(LuaSpell* spell){ - MutexList* glide_list = control_effects[CONTROL_EFFECT_TYPE_GLIDE]; - if (!glide_list || glide_list->size(true) == 0) - return; - - glide_list->Remove(spell); - if (IsPlayer() && glide_list->size(true) == 0) + control_effects.Remove(CONTROL_EFFECT_TYPE_GLIDE, spell); + if (IsPlayer() && !control_effects.Has(CONTROL_EFFECT_TYPE_GLIDE)) ((Player*)this)->SetPlayerControlFlag(4, 16, false); } @@ -3617,25 +3418,32 @@ void Entity::AddSafefallSpell(LuaSpell* spell){ if (!spell) return; - if (!control_effects[CONTROL_EFFECT_TYPE_SAFEFALL]) - control_effects[CONTROL_EFFECT_TYPE_SAFEFALL] = new MutexList; - - if (IsPlayer() && control_effects[CONTROL_EFFECT_TYPE_SAFEFALL]->size(true) == 0) + if (IsPlayer() && !control_effects.Has(CONTROL_EFFECT_TYPE_SAFEFALL)) ((Player*)this)->SetPlayerControlFlag(4, 32, true); - control_effects[CONTROL_EFFECT_TYPE_SAFEFALL]->Add(spell); + control_effects.Add(CONTROL_EFFECT_TYPE_SAFEFALL, spell); } void Entity::RemoveSafefallSpell(LuaSpell* spell){ - MutexList* safe_list = control_effects[CONTROL_EFFECT_TYPE_SAFEFALL]; - if (!safe_list || safe_list->size(true) == 0) - return; - - safe_list->Remove(spell); - if (IsPlayer() && safe_list->size(true) == 0) + control_effects.Remove(CONTROL_EFFECT_TYPE_SAFEFALL, spell); + if (IsPlayer() && !control_effects.Has(CONTROL_EFFECT_TYPE_SAFEFALL)) ((Player*)this)->SetPlayerControlFlag(4, 32, false); } +void Entity::AddIllusionSpell(LuaSpell* spell, int16 model_id){ + if(!control_effects.Has(CONTROL_EFFECT_TYPE_ILLUSION)) { + control_effects.AddOrUpdate(CONTROL_EFFECT_TYPE_ILLUSION, spell, model_id); + SetIllusionModel(model_id, true); + } +} + +void Entity::RemoveIllusionSpell(LuaSpell* spell) { + if(control_effects.Contains(CONTROL_EFFECT_TYPE_ILLUSION, spell)) { + SetIllusionModel(0, true); + } + control_effects.Remove(CONTROL_EFFECT_TYPE_ILLUSION, spell); +} + void Entity::UpdateGroupMemberInfo(bool inGroupMgrLock, bool groupMembersLocked) { if (!group_member_info || group_id == 0) return; @@ -3819,14 +3627,7 @@ void Entity::AddSkillBonus(int32 spell_id, int32 skill_id, float value) { bool Entity::HasControlEffect(int8 type) { - if (type >= CONTROL_MAX_EFFECTS) - return false; - - MutexList* spell_list = control_effects[type]; - if (!spell_list || spell_list->size(true) == 0) - return false; - - return true; + return control_effects.Has(type); } void Entity::HaltMovement() @@ -4174,16 +3975,9 @@ void Entity::SendControlEffectDetailsToClient(Client* client) { client->Message(CHANNEL_COLOR_YELLOW, "Current control effects on %s", GetName()); client->Message(CHANNEL_COLOR_YELLOW, "-------------------------------"); for (int i = 0; i < CONTROL_MAX_EFFECTS; i++) { - if(control_effects[i]) { - MutexList* spells = control_effects[i]; - if(spells->size() > 0) { - MutexList::iterator itr = spells->begin(); - while(itr.Next()){ - LuaSpell* spell = itr->value; - if(spell && spell->spell && spell->spell->GetSpellData()) { - client->Message(CHANNEL_COLOR_YELLOW, "Spell %s (%u) control effect %s", spell->spell->GetName(), spell->spell->GetSpellData()->id, GetControlEffectName(i).c_str()); - } - } + for (LuaSpell* spell : control_effects.Snapshot(i)) { + if(spell && spell->spell && spell->spell->GetSpellData()) { + client->Message(CHANNEL_COLOR_YELLOW, "Spell %s (%u) control effect %s", spell->spell->GetName(), spell->spell->GetSpellData()->id, GetControlEffectName(i).c_str()); } } } diff --git a/source/WorldServer/Entity.h b/source/WorldServer/Entity.h index c0dccf9..e6cb2af 100644 --- a/source/WorldServer/Entity.h +++ b/source/WorldServer/Entity.h @@ -25,6 +25,7 @@ #include "MutexList.h" #include "MutexVector.h" #include "Trade.h" +#include "EffectFlags.h" #include #include #include @@ -1115,6 +1116,7 @@ struct InfoStruct{ // when PacketStruct is fixed for C++17 this should become a shared_mutex and handle read/write lock std::mutex classMutex; std::unordered_map props; + EffectFlags spell_flags; private: std::string name_; int8 class1_; @@ -1413,33 +1415,6 @@ struct ThreatTransfer { #define DISPELL_TYPE_CURE 0 #define DISPELL_TYPE_DISPELL 1 -#define CONTROL_EFFECT_TYPE_MEZ 1 -#define CONTROL_EFFECT_TYPE_STIFLE 2 -#define CONTROL_EFFECT_TYPE_DAZE 3 -#define CONTROL_EFFECT_TYPE_STUN 4 -#define CONTROL_EFFECT_TYPE_ROOT 5 -#define CONTROL_EFFECT_TYPE_FEAR 6 -#define CONTROL_EFFECT_TYPE_WALKUNDERWATER 7 -#define CONTROL_EFFECT_TYPE_JUMPUNDERWATER 8 -#define CONTROL_EFFECT_TYPE_INVIS 9 -#define CONTROL_EFFECT_TYPE_STEALTH 10 -#define CONTROL_EFFECT_TYPE_SNARE 11 -#define CONTROL_EFFECT_TYPE_FLIGHT 12 -#define CONTROL_EFFECT_TYPE_GLIDE 13 -#define CONTROL_EFFECT_TYPE_SAFEFALL 14 -#define CONTROL_MAX_EFFECTS 15 // always +1 to highest control effect - -#define IMMUNITY_TYPE_MEZ 1 -#define IMMUNITY_TYPE_STIFLE 2 -#define IMMUNITY_TYPE_DAZE 3 -#define IMMUNITY_TYPE_STUN 4 -#define IMMUNITY_TYPE_ROOT 5 -#define IMMUNITY_TYPE_FEAR 6 -#define IMMUNITY_TYPE_AOE 7 -#define IMMUNITY_TYPE_TAUNT 8 -#define IMMUNITY_TYPE_RIPOSTE 9 -#define IMMUNITY_TYPE_STRIKETHROUGH 10 - //class Spell; //class ZoneServer; @@ -1985,6 +1960,8 @@ public: void RemoveSafefallSpell(LuaSpell* spell); void AddGlideSpell(LuaSpell* spell); void RemoveGlideSpell(LuaSpell* spell); + void AddIllusionSpell(LuaSpell* spell, int16 model_id); + void RemoveIllusionSpell(LuaSpell* spell); GroupMemberInfo* GetGroupMemberInfo() { return group_member_info; } void SetGroupMemberInfo(GroupMemberInfo* info) { group_member_info = info; } @@ -2110,6 +2087,10 @@ public: return "SafeFall"; break; } + case CONTROL_EFFECT_TYPE_ILLUSION:{ + return "Illusion"; + break; + } default: { return "Undefined"; break; @@ -2136,8 +2117,8 @@ protected: bool m_petDismissing; private: MutexList bonus_list; - map*> control_effects; - map*> immunities; + ControlEffects control_effects; + Immunities immunities; float max_speed; int8 deity; sint16 regen_hp_rate; @@ -2176,6 +2157,7 @@ private: float speed_multiplier; map snare_values; + mutable std::shared_mutex MSnareValues; ThreatTransfer* m_threatTransfer; diff --git a/source/WorldServer/LuaFunctions.cpp b/source/WorldServer/LuaFunctions.cpp index abf38f6..9530a33 100644 --- a/source/WorldServer/LuaFunctions.cpp +++ b/source/WorldServer/LuaFunctions.cpp @@ -2465,8 +2465,7 @@ int EQ2Emu_lua_AddSpellBonus(lua_State* state) { lua_interface->LogError("%s: Error applying spell bonus on non entity.", lua_interface->GetScriptName(state)); } } - if (!(luaspell->effect_bitmask & EFFECT_FLAG_SPELLBONUS)) - luaspell->effect_bitmask += EFFECT_FLAG_SPELLBONUS; + luaspell->effect_flags.add(EFFECT_IDX_SPELLBONUS); } else if (spawn && spawn->IsEntity()) { ((Entity*)spawn)->AddSpellBonus(luaspell, type, value, class_req, race_req, faction_req); @@ -2540,8 +2539,7 @@ int EQ2Emu_lua_AddSpawnSpellBonus(lua_State* state) { ((Entity*)spawn)->AddSpellBonus(luaspell, type, value, class_req, race_req, faction_req); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_SPELLBONUS)) - luaspell->effect_bitmask += EFFECT_FLAG_SPELLBONUS; + luaspell->effect_flags.add(EFFECT_IDX_SPELLBONUS); if (spawn->IsPlayer()) ((Player*)spawn)->SetCharSheetChanged(true); @@ -2640,13 +2638,11 @@ int EQ2Emu_lua_AddSkillBonus(lua_State* state) { if (packet) client->QueuePacket(packet); } - if (!(luaspell->effect_bitmask & EFFECT_FLAG_SKILLBONUS)) - luaspell->effect_bitmask += EFFECT_FLAG_SKILLBONUS; + luaspell->effect_flags.add(EFFECT_IDX_SKILLBONUS); } else if (target->IsNPC()) { ((NPC*)target)->AddSkillBonus(spell_id, skill_id, value); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_SKILLBONUS)) - luaspell->effect_bitmask += EFFECT_FLAG_SKILLBONUS; + luaspell->effect_flags.add(EFFECT_IDX_SKILLBONUS); } else LogWrite(LUA__ERROR, 0, "LUA", "Error applying bonus buff on '%s'. Not a NPC or player.", target->GetName()); @@ -2746,77 +2742,65 @@ int EQ2Emu_lua_AddControlEffect(lua_State* state) { if (target && target->IsEntity()) { if (type == CONTROL_EFFECT_TYPE_MEZ) { ((Entity*)target)->AddMezSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_MEZ)) - luaspell->effect_bitmask += EFFECT_FLAG_MEZ; + luaspell->effect_flags.add(EFFECT_IDX_MEZ); if (target->IsNPC()) ((NPC*)target)->Brain()->AddHate(luaspell->caster, 5); } else if (type == CONTROL_EFFECT_TYPE_STIFLE) { ((Entity*)target)->AddStifleSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_STIFLE)) - luaspell->effect_bitmask += EFFECT_FLAG_STIFLE; + luaspell->effect_flags.add(EFFECT_IDX_STIFLE); if (target->IsNPC()) ((NPC*)target)->Brain()->AddHate(luaspell->caster, 5); } else if (type == CONTROL_EFFECT_TYPE_DAZE) { ((Entity*)target)->AddDazeSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_DAZE)) - luaspell->effect_bitmask += EFFECT_FLAG_DAZE; + luaspell->effect_flags.add(EFFECT_IDX_DAZE); if (target->IsNPC()) ((NPC*)target)->Brain()->AddHate(luaspell->caster, 5); } else if (type == CONTROL_EFFECT_TYPE_STUN) { - if (!(luaspell->effect_bitmask & EFFECT_FLAG_STUN)) - luaspell->effect_bitmask += EFFECT_FLAG_STUN; + luaspell->effect_flags.add(EFFECT_IDX_STUN); ((Entity*)target)->AddStunSpell(luaspell); if (target->IsNPC()) ((NPC*)target)->Brain()->AddHate(luaspell->caster, 5); } else if (type == CONTROL_EFFECT_TYPE_ROOT) { - if (!(luaspell->effect_bitmask & EFFECT_FLAG_ROOT)) - luaspell->effect_bitmask += EFFECT_FLAG_ROOT; ((Entity*)target)->AddRootSpell(luaspell); + luaspell->effect_flags.add(EFFECT_IDX_ROOT); if (target->IsNPC()) ((NPC*)target)->Brain()->AddHate(luaspell->caster, 5); } else if (type == CONTROL_EFFECT_TYPE_FEAR) { - if (!(luaspell->effect_bitmask & EFFECT_FLAG_FEAR)) - luaspell->effect_bitmask += EFFECT_FLAG_FEAR; ((Entity*)target)->AddFearSpell(luaspell); + luaspell->effect_flags.add(EFFECT_IDX_FEAR); if (target->IsNPC()) ((NPC*)target)->Brain()->AddHate(luaspell->caster, 5); } else if (type == CONTROL_EFFECT_TYPE_WALKUNDERWATER) { ((Entity*)target)->AddWaterwalkSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_WATERWALK)) - luaspell->effect_bitmask += EFFECT_FLAG_WATERWALK; + luaspell->effect_flags.add(EFFECT_IDX_WATERWALK); } else if (type == CONTROL_EFFECT_TYPE_JUMPUNDERWATER) { ((Entity*)target)->AddWaterjumpSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_WATERJUMP)) - luaspell->effect_bitmask += EFFECT_FLAG_WATERJUMP; + luaspell->effect_flags.add(EFFECT_IDX_WATERJUMP); } else if (type == CONTROL_EFFECT_TYPE_SNARE) { ((Entity*)target)->AddSnareSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_SNARE)) - luaspell->effect_bitmask += EFFECT_FLAG_SNARE; + luaspell->effect_flags.add(EFFECT_IDX_SNARE); if (target->IsNPC()) ((NPC*)target)->Brain()->AddHate(luaspell->caster, 5); } else if (type == CONTROL_EFFECT_TYPE_FLIGHT) { ((Entity*)target)->AddFlightSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_FLIGHT)) - luaspell->effect_bitmask += EFFECT_FLAG_FLIGHT; + luaspell->effect_flags.add(EFFECT_IDX_FLIGHT); } else if (type == CONTROL_EFFECT_TYPE_GLIDE) { ((Entity*)target)->AddGlideSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_GLIDE)) - luaspell->effect_bitmask += EFFECT_FLAG_GLIDE; + luaspell->effect_flags.add(EFFECT_IDX_GLIDE); } else if (type == CONTROL_EFFECT_TYPE_SAFEFALL) { ((Entity*)target)->AddSafefallSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_SAFEFALL)) - luaspell->effect_bitmask += EFFECT_FLAG_SAFEFALL; + luaspell->effect_flags.add(EFFECT_IDX_SAFEFALL); } else lua_interface->LogError("%s: Unhandled control effect type of %u.", lua_interface->GetScriptName(state), type); @@ -2828,63 +2812,51 @@ int EQ2Emu_lua_AddControlEffect(lua_State* state) { else if (only_add_spawn && spawn && spawn->IsEntity()) { if (type == CONTROL_EFFECT_TYPE_MEZ) { ((Entity*)spawn)->AddMezSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_MEZ)) - luaspell->effect_bitmask += EFFECT_FLAG_MEZ; + luaspell->effect_flags.add(EFFECT_IDX_MEZ); } else if (type == CONTROL_EFFECT_TYPE_STIFLE) { ((Entity*)spawn)->AddStifleSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_STIFLE)) - luaspell->effect_bitmask += EFFECT_FLAG_STIFLE; + luaspell->effect_flags.add(EFFECT_IDX_STIFLE); } else if (type == CONTROL_EFFECT_TYPE_DAZE) { ((Entity*)spawn)->AddDazeSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_DAZE)) - luaspell->effect_bitmask += EFFECT_FLAG_DAZE; + luaspell->effect_flags.add(EFFECT_IDX_DAZE); } else if (type == CONTROL_EFFECT_TYPE_STUN) { ((Entity*)spawn)->AddStunSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_STUN)) - luaspell->effect_bitmask += EFFECT_FLAG_STUN; + luaspell->effect_flags.add(EFFECT_IDX_STUN); } else if (type == CONTROL_EFFECT_TYPE_ROOT) { ((Entity*)spawn)->AddRootSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_ROOT)) - luaspell->effect_bitmask += EFFECT_FLAG_ROOT; + luaspell->effect_flags.add(EFFECT_IDX_ROOT); } else if (type == CONTROL_EFFECT_TYPE_FEAR) { ((Entity*)spawn)->AddFearSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_FEAR)) - luaspell->effect_bitmask += EFFECT_FLAG_FEAR; + luaspell->effect_flags.add(EFFECT_IDX_FEAR); } else if (type == CONTROL_EFFECT_TYPE_WALKUNDERWATER) { ((Entity*)spawn)->AddWaterwalkSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_WATERWALK)) - luaspell->effect_bitmask += EFFECT_FLAG_WATERWALK; + luaspell->effect_flags.add(EFFECT_IDX_WATERWALK); } else if (type == CONTROL_EFFECT_TYPE_JUMPUNDERWATER) { ((Entity*)spawn)->AddWaterjumpSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_WATERJUMP)) - luaspell->effect_bitmask += EFFECT_FLAG_WATERJUMP; + luaspell->effect_flags.add(EFFECT_IDX_WATERJUMP); } else if (type == CONTROL_EFFECT_TYPE_SNARE) { ((Entity*)spawn)->AddSnareSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_SNARE)) - luaspell->effect_bitmask += EFFECT_FLAG_SNARE; + luaspell->effect_flags.add(EFFECT_IDX_SNARE); } else if (type == CONTROL_EFFECT_TYPE_FLIGHT) { ((Entity*)spawn)->AddFlightSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_FLIGHT)) - luaspell->effect_bitmask += EFFECT_FLAG_FLIGHT; + luaspell->effect_flags.add(EFFECT_IDX_FLIGHT); } else if (type == CONTROL_EFFECT_TYPE_GLIDE) { ((Entity*)spawn)->AddGlideSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_GLIDE)) - luaspell->effect_bitmask += EFFECT_FLAG_GLIDE; + luaspell->effect_flags.add(EFFECT_IDX_GLIDE); } else if (type == CONTROL_EFFECT_TYPE_SAFEFALL) { ((Entity*)spawn)->AddSafefallSpell(luaspell); - if (!(luaspell->effect_bitmask & EFFECT_FLAG_SAFEFALL)) - luaspell->effect_bitmask += EFFECT_FLAG_SAFEFALL; + luaspell->effect_flags.add(EFFECT_IDX_SAFEFALL); } else lua_interface->LogError("%s: Unhandled control effect type of %u.", lua_interface->GetScriptName(state), type); @@ -2933,6 +2905,8 @@ int EQ2Emu_lua_RemoveControlEffect(lua_State* state) { ((Entity*)target)->RemoveGlideSpell(luaspell); else if (type == CONTROL_EFFECT_TYPE_SAFEFALL) ((Entity*)target)->RemoveGlideSpell(luaspell); + else if (type == CONTROL_EFFECT_TYPE_ILLUSION) + ((Entity*)target)->RemoveIllusionSpell(luaspell); else lua_interface->LogError("%s: Unhandled control effect type of %u.", lua_interface->GetScriptName(state), type); } @@ -2963,6 +2937,8 @@ int EQ2Emu_lua_RemoveControlEffect(lua_State* state) { ((Entity*)spawn)->RemoveGlideSpell(luaspell); else if (type == CONTROL_EFFECT_TYPE_SAFEFALL) ((Entity*)spawn)->RemoveSafefallSpell(luaspell); + else if (type == CONTROL_EFFECT_TYPE_ILLUSION) + ((Entity*)spawn)->RemoveIllusionSpell(luaspell); else lua_interface->LogError("%s: Unhandled control effect type of %u.", lua_interface->GetScriptName(state), type); } @@ -6836,13 +6812,11 @@ int EQ2Emu_lua_Stealth(lua_State* state) { if (spawn->IsEntity()) { if (type == 1) { ((Entity*)spawn)->AddStealthSpell(spell); - if (!(spell->effect_bitmask & EFFECT_FLAG_STEALTH)) - spell->effect_bitmask += EFFECT_FLAG_STEALTH; + spell->effect_flags.add(EFFECT_IDX_STEALTH); } else if (type == 2) { ((Entity*)spawn)->AddInvisSpell(spell); - if (!(spell->effect_bitmask & EFFECT_FLAG_INVIS)) - spell->effect_bitmask += EFFECT_FLAG_INVIS; + spell->effect_flags.add(EFFECT_IDX_INVIS); } return 0; } @@ -6859,13 +6833,11 @@ int EQ2Emu_lua_Stealth(lua_State* state) { if (type == 1) { ((Entity*)spawn)->AddStealthSpell(spell); - if (!(spell->effect_bitmask & EFFECT_FLAG_STEALTH)) - spell->effect_bitmask += EFFECT_FLAG_STEALTH; + spell->effect_flags.add(EFFECT_IDX_STEALTH); } else if (type == 2) { ((Entity*)spawn)->AddInvisSpell(spell); - if (!(spell->effect_bitmask & EFFECT_FLAG_INVIS)) - spell->effect_bitmask += EFFECT_FLAG_INVIS; + spell->effect_flags.add(EFFECT_IDX_INVIS); } else { lua_interface->LogError("%s: LUA Stealth command error: invalid stealth type given", lua_interface->GetScriptName(state)); @@ -9480,11 +9452,21 @@ int EQ2Emu_lua_SetIllusion(lua_State* state) { lua_interface->ResetFunctionStack(state); if (spell && spell->spell && spell->GetTargetCount() > 0) { + spell->effect_flags.add(EFFECT_IDX_ILLUSION); ZoneServer* zone = spell->zone; for (int32 id : spell->GetTargets()) { Spawn* target = zone->GetSpawnByID(id); - if (target) - target->SetIllusionModel(model); + if (target) { + if(!target->IsEntity()) { + target->SetIllusionModel(model); + } + else if(model) { + ((Entity*)target)->AddIllusionSpell(spell, model); + } + else { + ((Entity*)target)->RemoveIllusionSpell(spell); + } + } } } else { @@ -9492,8 +9474,15 @@ int EQ2Emu_lua_SetIllusion(lua_State* state) { lua_interface->LogError("%s: LUA SetIllusion command error: spawn is not valid", lua_interface->GetScriptName(state)); return 0; } - - spawn->SetIllusionModel(model); + if(!spawn->IsEntity()) { + spawn->SetIllusionModel(model); + } + else if(model) { + ((Entity*)spawn)->AddIllusionSpell(nullptr, model); + } + else { + ((Entity*)spawn)->RemoveIllusionSpell(spell); + } } return 0; @@ -9511,8 +9500,12 @@ int EQ2Emu_lua_ResetIllusion(lua_State* state) { ZoneServer* zone = spell->zone; for (int32 id : spell->GetTargets()) { Spawn* target = zone->GetSpawnByID(id); - if (target) - target->SetIllusionModel(0); + if (target) { + if(target->IsEntity()) + ((Entity*)target)->RemoveIllusionSpell(spell); + else + target->SetIllusionModel(0); + } } } else { @@ -9520,8 +9513,10 @@ int EQ2Emu_lua_ResetIllusion(lua_State* state) { lua_interface->LogError("%s: LUA ResetIllusion command error: spawn is not valid", lua_interface->GetScriptName(state)); return 0; } - - spawn->SetIllusionModel(0); + if(spawn->IsEntity()) + ((Entity*)spawn)->RemoveIllusionSpell(spell); + else + spawn->SetIllusionModel(0); } return 0; @@ -14913,4 +14908,45 @@ int EQ2Emu_lua_RemoveCharacterProperty(lua_State* state) { Query query; query.AddQueryAsync(((Player*)player)->GetCharacterID(), &database, Q_DELETE, "delete from character_properties where charid = %u and propname='%s'", ((Player*)player)->GetCharacterID(), propname.c_str()); return 0; +} + + +int EQ2Emu_lua_RemoveSpell(lua_State* state) { + Spawn* spawn = lua_interface->GetSpawn(state); + int32 spell_id = lua_interface->GetInt32Value(state, 2); + bool maintained_spell = lua_interface->GetBooleanValue(state, 3); + string reason = lua_interface->GetStringValue(state, 4); + lua_interface->ResetFunctionStack(state); + + if(!spawn || !spawn->IsEntity()) { + lua_interface->LogError("%s: LUA RemoveSpell command error: entity is not valid", lua_interface->GetScriptName(state)); + return 0; + } + if(!spawn->GetZone()) { + lua_interface->LogError("%s: LUA RemoveSpell command error: no valid zone", lua_interface->GetScriptName(state)); + return 0; + } + if(!spell_id) { + lua_interface->LogError("%s: LUA RemoveSpell command error: spell id is not valid", lua_interface->GetScriptName(state)); + return 0; + } + + Entity* ent = (Entity*)spawn; + + if(reason.length() < 1) + reason = "canceled"; + + if(maintained_spell) { + MaintainedEffects* effect = ent->GetMaintainedSpell(spell_id); + if(effect && effect->spell) { + ent->GetZone()->GetSpellProcess()->DeleteCasterSpell(effect->spell, reason, false); + } + } + else { + SpellEffects* effect = ent->GetSpellEffect(spell_id); + if(effect && effect->spell) { + ent->GetZone()->GetSpellProcess()->DeleteCasterSpell(effect->spell, reason, false, spawn); + } + } + return 0; } \ No newline at end of file diff --git a/source/WorldServer/LuaFunctions.h b/source/WorldServer/LuaFunctions.h index b66830b..71581c4 100644 --- a/source/WorldServer/LuaFunctions.h +++ b/source/WorldServer/LuaFunctions.h @@ -699,4 +699,5 @@ int EQ2Emu_lua_InSameRaid(lua_State* state); int EQ2Emu_lua_GetRaid(lua_State* state); int EQ2Emu_lua_AdjustHatePosition(lua_State* state); int EQ2Emu_lua_RemoveCharacterProperty(lua_State* state); +int EQ2Emu_lua_RemoveSpell(lua_State* state); #endif \ No newline at end of file diff --git a/source/WorldServer/LuaInterface.cpp b/source/WorldServer/LuaInterface.cpp index 857d5ce..dff85ba 100644 --- a/source/WorldServer/LuaInterface.cpp +++ b/source/WorldServer/LuaInterface.cpp @@ -1839,6 +1839,7 @@ void LuaInterface::RegisterFunctions(lua_State* state) { lua_register(state,"GetRaid", EQ2Emu_lua_GetRaid); lua_register(state,"AdjustHatePosition", EQ2Emu_lua_AdjustHatePosition); lua_register(state,"RemoveCharacterProperty", EQ2Emu_lua_RemoveCharacterProperty); + lua_register(state,"RemoveSpell", EQ2Emu_lua_RemoveSpell); } void LuaInterface::LogError(const char* error, ...) { @@ -2320,7 +2321,6 @@ LuaSpell* LuaInterface::LoadSpellScript(const char* name) { spell->had_dmg_remaining = false; spell->slot_pos = 0; spell->damage_remaining = 0; - spell->effect_bitmask = 0; spell->restored = false; spell->has_proc = false; spell->initial_caster_char_id = 0; @@ -2670,7 +2670,6 @@ LuaSpell* LuaInterface::CreateSpellScript(const char* name, lua_State* existStat new_spell->had_dmg_remaining = false; new_spell->slot_pos = 0; new_spell->damage_remaining = 0; - new_spell->effect_bitmask = 0; new_spell->caster = 0; new_spell->initial_target = 0; new_spell->spell = 0; diff --git a/source/WorldServer/LuaInterface.h b/source/WorldServer/LuaInterface.h index 7590319..80526b9 100644 --- a/source/WorldServer/LuaInterface.h +++ b/source/WorldServer/LuaInterface.h @@ -31,6 +31,7 @@ #include "Quests.h" #include "zoneserver.h" #include "client.h" +#include "EffectFlags.h" #include @@ -116,7 +117,7 @@ struct LuaSpell{ bool had_triggers; bool had_dmg_remaining; Mutex MScriptMutex; - int32 effect_bitmask; + EffectFlags effect_flags; bool restored; // restored spell cross zone std::atomic has_proc; ZoneServer* zone; diff --git a/source/WorldServer/Player.cpp b/source/WorldServer/Player.cpp index 30ea840..6043912 100644 --- a/source/WorldServer/Player.cpp +++ b/source/WorldServer/Player.cpp @@ -7509,12 +7509,12 @@ void Player::SaveSpellEffects() continue; savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, - "insert into character_spell_effects (name, caster_char_id, target_char_id, target_type, db_effect_type, spell_id, effect_slot, slot_pos, icon, icon_backdrop, conc_used, tier, total_time, expire_timestamp, lua_file, custom_spell, charid, damage_remaining, effect_bitmask, num_triggers, had_triggers, cancel_after_triggers, crit, last_spellattack_hit, interrupted, resisted, has_damaged, custom_function, caster_level) values ('%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %f, %u, '%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, '%s', %u)", + "insert into character_spell_effects (name, caster_char_id, target_char_id, target_type, db_effect_type, spell_id, effect_slot, slot_pos, icon, icon_backdrop, conc_used, tier, total_time, expire_timestamp, lua_file, custom_spell, charid, damage_remaining, effect_bitmask, num_triggers, had_triggers, cancel_after_triggers, crit, last_spellattack_hit, interrupted, resisted, has_damaged, custom_function, caster_level) values ('%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %f, %u, '%s', %u, %u, %u, %llu, %u, %u, %u, %u, %u, %u, %u, %u, '%s', %u)", database.getSafeEscapeString(info->spell_effects[i].spell->spell->GetName()).c_str(), caster_char_id, target_char_id, 0 /*no target_type for spell_effects*/, DB_TYPE_SPELLEFFECTS /* db_effect_type for spell_effects */, info->spell_effects[i].spell->spell->IsCopiedSpell() ? info->spell_effects[i].spell->spell->GetSpellData()->inherited_spell_id : info->spell_effects[i].spell_id, i, info->spell_effects[i].spell->slot_pos, info->spell_effects[i].icon, info->spell_effects[i].icon_backdrop, 0 /* no conc_used for spell_effects */, info->spell_effects[i].tier, info->spell_effects[i].total_time, timestamp, database.getSafeEscapeString(info->spell_effects[i].spell->file_name.c_str()).c_str(), info->spell_effects[i].spell->spell->IsCopiedSpell(), GetCharacterID(), - info->spell_effects[i].spell->damage_remaining, info->spell_effects[i].spell->effect_bitmask, info->spell_effects[i].spell->num_triggers, info->spell_effects[i].spell->had_triggers, info->spell_effects[i].spell->cancel_after_all_triggers, + info->spell_effects[i].spell->damage_remaining, info->spell_effects[i].spell->effect_flags.export_u64(), info->spell_effects[i].spell->num_triggers, info->spell_effects[i].spell->had_triggers, info->spell_effects[i].spell->cancel_after_all_triggers, info->spell_effects[i].spell->crit, info->spell_effects[i].spell->last_spellattack_hit, info->spell_effects[i].spell->interrupted, info->spell_effects[i].spell->resisted, info->spell_effects[i].spell->has_damaged, (info->maintained_effects[i].expire_timestamp) == 0xFFFFFFFF ? "" : database.getSafeEscapeString(spellProcess->SpellScriptTimerCustomFunction(info->spell_effects[i].spell).c_str()).c_str(), info->spell_effects[i].spell->initial_caster_level); SaveCustomSpellFields(info->spell_effects[i].spell); @@ -7542,11 +7542,11 @@ void Player::SaveSpellEffects() if(info->maintained_effects[i].spell->spell->GetSpellData() && !info->maintained_effects[i].spell->spell->GetSpellData()->duration_until_cancel) timestamp = info->maintained_effects[i].expire_timestamp - Timer::GetCurrentTime2(); savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, - "insert into character_spell_effects (name, caster_char_id, target_char_id, target_type, db_effect_type, spell_id, effect_slot, slot_pos, icon, icon_backdrop, conc_used, tier, total_time, expire_timestamp, lua_file, custom_spell, charid, damage_remaining, effect_bitmask, num_triggers, had_triggers, cancel_after_triggers, crit, last_spellattack_hit, interrupted, resisted, has_damaged, custom_function, caster_level) values ('%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %f, %u, '%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, '%s', %u)", + "insert into character_spell_effects (name, caster_char_id, target_char_id, target_type, db_effect_type, spell_id, effect_slot, slot_pos, icon, icon_backdrop, conc_used, tier, total_time, expire_timestamp, lua_file, custom_spell, charid, damage_remaining, effect_bitmask, num_triggers, had_triggers, cancel_after_triggers, crit, last_spellattack_hit, interrupted, resisted, has_damaged, custom_function, caster_level) values ('%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %f, %u, '%s', %u, %u, %u, %llu, %u, %u, %u, %u, %u, %u, %u, %u, '%s', %u)", database.getSafeEscapeString(info->maintained_effects[i].name).c_str(), caster_char_id, target_char_id, info->maintained_effects[i].target_type, DB_TYPE_MAINTAINEDEFFECTS /* db_effect_type for maintained_effects */, info->maintained_effects[i].spell->spell->IsCopiedSpell() ? info->maintained_effects[i].spell->spell->GetSpellData()->inherited_spell_id : info->maintained_effects[i].spell_id, i, info->maintained_effects[i].slot_pos, info->maintained_effects[i].icon, info->maintained_effects[i].icon_backdrop, info->maintained_effects[i].conc_used, info->maintained_effects[i].tier, info->maintained_effects[i].total_time, timestamp, database.getSafeEscapeString(info->maintained_effects[i].spell->file_name.c_str()).c_str(), info->maintained_effects[i].spell->spell->IsCopiedSpell(), GetCharacterID(), - info->maintained_effects[i].spell->damage_remaining, info->maintained_effects[i].spell->effect_bitmask, info->maintained_effects[i].spell->num_triggers, info->maintained_effects[i].spell->had_triggers, info->maintained_effects[i].spell->cancel_after_all_triggers, + info->maintained_effects[i].spell->damage_remaining, info->maintained_effects[i].spell->effect_flags.export_u64(), info->maintained_effects[i].spell->num_triggers, info->maintained_effects[i].spell->had_triggers, info->maintained_effects[i].spell->cancel_after_all_triggers, info->maintained_effects[i].spell->crit, info->maintained_effects[i].spell->last_spellattack_hit, info->maintained_effects[i].spell->interrupted, info->maintained_effects[i].spell->resisted, info->maintained_effects[i].spell->has_damaged, (info->maintained_effects[i].expire_timestamp) == 0xFFFFFFFF ? "" : database.getSafeEscapeString(spellProcess->SpellScriptTimerCustomFunction(info->maintained_effects[i].spell).c_str()).c_str(), info->maintained_effects[i].spell->initial_caster_level); SaveCustomSpellFields(info->maintained_effects[i].spell); diff --git a/source/WorldServer/WorldDatabase.cpp b/source/WorldServer/WorldDatabase.cpp index 7061bc2..84f7c08 100644 --- a/source/WorldServer/WorldDatabase.cpp +++ b/source/WorldServer/WorldDatabase.cpp @@ -8270,7 +8270,7 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int int8 custom_spell = result.GetInt32Str("custom_spell"); int32 damage_remaining = result.GetInt32Str("damage_remaining"); - int32 effect_bitmask = result.GetInt32Str("effect_bitmask"); + int64 effect_bitmask = result.GetInt64Str("effect_bitmask"); int16 num_triggers = result.GetInt32Str("num_triggers"); int8 had_triggers = result.GetInt32Str("had_triggers"); int8 cancel_after_triggers = result.GetInt32Str("cancel_after_triggers"); @@ -8394,7 +8394,7 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int { lua_spell->crit = crit; lua_spell->damage_remaining = damage_remaining; - lua_spell->effect_bitmask = effect_bitmask; + lua_spell->effect_flags.import_u64(effect_bitmask); lua_spell->had_dmg_remaining = (damage_remaining>0) ? true : false; lua_spell->had_triggers = had_triggers; lua_spell->initial_caster_char_id = caster_char_id;