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;