diff options
Diffstat (limited to 'src')
82 files changed, 2467 insertions, 1828 deletions
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index abb6126ca2c..2522c97de25 100644 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -22,6 +22,7 @@ #include "Player.h" #include "Spell.h" #include "ObjectAccessor.h" +#include "SpellHistory.h" #include "SpellMgr.h" #include "Creature.h" #include "Util.h" @@ -146,15 +147,15 @@ void PetAI::UpdateAI(uint32 diff) if (!spellInfo) continue; - if (me->GetCharmInfo() && me->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) + if (me->GetCharmInfo() && me->GetSpellHistory()->HasGlobalCooldown(spellInfo)) continue; if (spellInfo->IsPositive()) { if (spellInfo->CanBeUsedInCombat()) { - // check spell cooldown - if (me->HasSpellCooldown(spellInfo->Id)) + // check spell cooldown & school lock + if (!me->GetSpellHistory()->IsReady(spellInfo)) continue; // Check if we're in combat or commanded to attack diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp index e14e9fadafc..f267bf7c6c6 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp @@ -99,7 +99,7 @@ bool BattlegroundSA::ResetObjs() for (uint8 i = BG_SA_MAXNPC; i < BG_SA_MAXNPC + BG_SA_MAX_GY; i++) DelCreature(i); - for (uint8 i = 0; i < 6; i++) + for (uint8 i = 0; i < MAX_GATES; ++i) GateStatus[i] = BG_SA_GATE_OK; if (!AddCreature(BG_SA_NpcEntries[BG_SA_NPC_KANRETHAD], BG_SA_NPC_KANRETHAD, BG_SA_NpcSpawnlocs[BG_SA_NPC_KANRETHAD])) @@ -179,9 +179,6 @@ bool BattlegroundSA::ResetObjs() GetBGObject(BG_SA_TITAN_RELIC)->SetFaction(atF); GetBGObject(BG_SA_TITAN_RELIC)->Refresh(); - for (uint8 i = 0; i <= 5; i++) - GateStatus[i] = BG_SA_GATE_OK; - TotalTime = 0; ShipsStarted = false; @@ -221,6 +218,8 @@ bool BattlegroundSA::ResetObjs() GetBGObject(i)->SetFaction(atF); } + UpdateObjectInteractionFlags(); + for (uint8 i = BG_SA_BOMB; i < BG_SA_MAXOBJ; i++) { if (!AddObject(i, BG_SA_ObjEntries[BG_SA_BOMB], BG_SA_ObjSpawnlocs[i], 0, 0, 0, 0, RESPAWN_ONE_DAY)) @@ -481,28 +480,7 @@ void BattlegroundSA::AddPlayer(Player* player) SendTransportInit(player); - if (!ShipsStarted) - { - if (player->GetTeamId() == Attackers) - { - player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); - - if (urand(0, 1)) - player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f, 0); - else - player->TeleportTo(607, 2577.003f, 980.261f, 15.0f, 0.807f, 0); - - } - else - player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0); - } - else - { - if (player->GetTeamId() == Attackers) - player->TeleportTo(607, 1600.381f, -106.263f, 8.8745f, 3.78f, 0); - else - player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0); - } + TeleportToEntrancePosition(player); } void BattlegroundSA::RemovePlayer(Player* /*player*/, ObjectGuid /*guid*/, uint32 /*team*/) { } @@ -533,23 +511,31 @@ void BattlegroundSA::TeleportPlayers() player->ResetAllPowers(); player->CombatStopWithPets(true); - for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - if (Player* p = ObjectAccessor::FindPlayer(itr->first)) - p->CastSpell(p, SPELL_PREPARATION, true); + player->CastSpell(player, SPELL_PREPARATION, true); - if (player->GetTeamId() == Attackers) - { - player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + TeleportToEntrancePosition(player); + } + } +} - if (urand(0, 1)) - player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f, 0); - else - player->TeleportTo(607, 2577.003f, 980.261f, 15.0f, 0.807f, 0); - } +void BattlegroundSA::TeleportToEntrancePosition(Player* player) +{ + if (player->GetTeamId() == Attackers) + { + if (!ShipsStarted) + { + player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + + if (urand(0, 1)) + player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f, 0); else - player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0); + player->TeleportTo(607, 2577.003f, 980.261f, 15.0f, 0.807f, 0); } + else + player->TeleportTo(607, 1600.381f, -106.263f, 8.8745f, 3.78f, 0); } + else + player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0); } void BattlegroundSA::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker /*= NULL*/) @@ -628,6 +614,8 @@ void BattlegroundSA::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* } } } + + UpdateObjectInteractionFlags(); } else break; @@ -711,7 +699,7 @@ WorldSafeLocsEntry const* BattlegroundSA::GetClosestGraveYard(Player* player) safeloc = BG_SA_GYEntries[BG_SA_DEFENDER_LAST_GY]; closest = sWorldSafeLocsStore.LookupEntry(safeloc); - nearest = std::sqrt((closest->x - x)*(closest->x - x) + (closest->y - y)*(closest->y - y) + (closest->z - z)*(closest->z - z)); + nearest = player->GetExactDistSq(closest->x, closest->y, closest->z); for (uint8 i = BG_SA_RIGHT_CAPTURABLE_GY; i < BG_SA_MAX_GY; i++) { @@ -719,7 +707,7 @@ WorldSafeLocsEntry const* BattlegroundSA::GetClosestGraveYard(Player* player) continue; ret = sWorldSafeLocsStore.LookupEntry(BG_SA_GYEntries[i]); - dist = std::sqrt((ret->x - x)*(ret->x - x) + (ret->y - y)*(ret->y - y) + (ret->z - z)*(ret->z - z)); + dist = player->GetExactDistSq(ret->x, ret->y, ret->z); if (dist < nearest) { closest = ret; @@ -738,23 +726,66 @@ void BattlegroundSA::SendTime() UpdateWorldState(BG_SA_TIMER_SEC_DECS, ((end_of_round%60000)%10000)/1000); } +bool BattlegroundSA::CanInteractWithObject(uint32 objectId) +{ + switch (objectId) + { + case BG_SA_TITAN_RELIC: + if (GateStatus[BG_SA_ANCIENT_GATE] != BG_SA_GATE_DESTROYED || GateStatus[BG_SA_YELLOW_GATE] != BG_SA_GATE_DESTROYED) + return false; + // no break + case BG_SA_CENTRAL_FLAG: + if (GateStatus[BG_SA_RED_GATE] != BG_SA_GATE_DESTROYED && GateStatus[BG_SA_PURPLE_GATE] != BG_SA_GATE_DESTROYED) + return false; + // no break + case BG_SA_LEFT_FLAG: + case BG_SA_RIGHT_FLAG: + if (GateStatus[BG_SA_GREEN_GATE] != BG_SA_GATE_DESTROYED && GateStatus[BG_SA_BLUE_GATE] != BG_SA_GATE_DESTROYED) + return false; + break; + default: + ASSERT(false); + break; + } + + return true; +} + +void BattlegroundSA::UpdateObjectInteractionFlags(uint32 objectId) +{ + if (GameObject* go = GetBGObject(objectId)) + { + if (CanInteractWithObject(objectId)) + go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + else + go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + } +} + +void BattlegroundSA::UpdateObjectInteractionFlags() +{ + for (uint8 i = BG_SA_CENTRAL_FLAG; i <= BG_SA_LEFT_FLAG; ++i) + UpdateObjectInteractionFlags(i); + UpdateObjectInteractionFlags(BG_SA_TITAN_RELIC); +} + void BattlegroundSA::EventPlayerClickedOnFlag(Player* source, GameObject* go) { switch (go->GetEntry()) { case 191307: case 191308: - if (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED) + if (CanInteractWithObject(BG_SA_LEFT_FLAG)) CaptureGraveyard(BG_SA_LEFT_CAPTURABLE_GY, source); break; case 191305: case 191306: - if (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED) + if (CanInteractWithObject(BG_SA_RIGHT_FLAG)) CaptureGraveyard(BG_SA_RIGHT_CAPTURABLE_GY, source); break; case 191310: case 191309: - if ((GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED) && (GateStatus[BG_SA_RED_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_PURPLE_GATE] == BG_SA_GATE_DESTROYED)) + if (CanInteractWithObject(BG_SA_CENTRAL_FLAG)) CaptureGraveyard(BG_SA_CENTRAL_CAPTURABLE_GY, source); break; default: @@ -856,10 +887,7 @@ void BattlegroundSA::TitanRelicActivated(Player* clicker) if (!clicker) return; - if (GateStatus[BG_SA_ANCIENT_GATE] == BG_SA_GATE_DESTROYED && - GateStatus[BG_SA_YELLOW_GATE] == BG_SA_GATE_DESTROYED && - (GateStatus[BG_SA_PURPLE_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_RED_GATE] == BG_SA_GATE_DESTROYED) && - (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED)) + if (CanInteractWithObject(BG_SA_TITAN_RELIC)) { if (clicker->GetTeamId() == Attackers) { diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h index 7f9a656c979..118cea41a7b 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h @@ -620,6 +620,7 @@ class BattlegroundSA : public Battleground * -Teleport all players to good location */ void TeleportPlayers(); + void TeleportToEntrancePosition(Player* player); /** * \brief Called on start and between the two round * -Update faction of all vehicle @@ -627,6 +628,11 @@ class BattlegroundSA : public Battleground void OverrideGunFaction(); /// Set selectable or not demolisher, called on battle start, when boats arrive to dock void DemolisherStartState(bool start); + /// Checks if a player can interact with the given object + bool CanInteractWithObject(uint32 objectId); + /// Updates interaction flags of specific objects + void UpdateObjectInteractionFlags(uint32 objectId); + void UpdateObjectInteractionFlags(); /** * \brief Called when a gate is destroy * -Give honor to player witch destroy it diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 6586c5035ec..5cd9b363ae0 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -560,8 +560,8 @@ void LoadDBCStores(const std::string& dataPath) for (uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i) if (TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i)) { - if (pathLength[entry->path] < entry->index + 1) - pathLength[entry->path] = entry->index + 1; + if (pathLength[entry->PathID] < entry->NodeIndex + 1) + pathLength[entry->PathID] = entry->NodeIndex + 1; } // Set path length sTaxiPathNodesByPath.resize(pathCount); // 0 and some other indexes not used @@ -570,7 +570,7 @@ void LoadDBCStores(const std::string& dataPath) // fill data for (uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i) if (TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i)) - sTaxiPathNodesByPath[entry->path].set(entry->index, entry); + sTaxiPathNodesByPath[entry->PathID].set(entry->NodeIndex, entry); // Initialize global taxinodes mask // include existed nodes that have at least single not spell base (scripted) path diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 5c784f3fe69..5ccd5d2b7e5 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -30,13 +30,7 @@ #include <vector> // Structures using to access raw DBC data and required packing to portability - -// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform -#if defined(__GNUC__) -#pragma pack(1) -#else #pragma pack(push, 1) -#endif struct AchievementEntry { @@ -1939,17 +1933,17 @@ struct TaxiPathEntry struct TaxiPathNodeEntry { - // 0 m_ID - uint32 path; // 1 m_PathID - uint32 index; // 2 m_NodeIndex - uint32 mapid; // 3 m_ContinentID - float x; // 4 m_LocX - float y; // 5 m_LocY - float z; // 6 m_LocZ - uint32 actionFlag; // 7 m_flags - uint32 delay; // 8 m_delay - uint32 arrivalEventID; // 9 m_arrivalEventID - uint32 departureEventID; // 10 m_departureEventID + // 0 ID + uint32 PathID; // 1 + uint32 NodeIndex; // 2 + uint32 MapID; // 3 + float LocX; // 4 + float LocY; // 5 + float LocZ; // 6 + uint32 Flags; // 7 + uint32 Delay; // 8 + uint32 ArrivalEventID; // 9 + uint32 DepartureEventID; // 10 }; struct TeamContributionPointsEntry @@ -2177,12 +2171,7 @@ struct WorldStateUI }; */ -// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform -#if defined(__GNUC__) -#pragma pack() -#else #pragma pack(pop) -#endif // Structures not used for casting to loaded DBC data and not required then packing struct MapDifficulty diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 05de671830e..7f00fc7f9d8 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -150,8 +150,6 @@ m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo( for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i) m_spells[i] = 0; - m_CreatureSpellCooldowns.clear(); - m_CreatureCategoryCooldowns.clear(); DisableReputationGain = false; m_SightDistance = sWorld->getFloatConfig(CONFIG_SIGHT_MONSTER); @@ -2156,83 +2154,6 @@ uint32 Creature::GetShieldBlockValue() const //dunno mob block return (getLevel()/2 + uint32(GetStat(STAT_STRENGTH)/20)); } -void Creature::_AddCreatureSpellCooldown(uint32 spell_id, time_t end_time) -{ - m_CreatureSpellCooldowns[spell_id] = end_time; -} - -void Creature::_AddCreatureCategoryCooldown(uint32 category, time_t apply_time) -{ - m_CreatureCategoryCooldowns[category] = apply_time; -} - -void Creature::AddCreatureSpellCooldown(uint32 spellid) -{ - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); - if (!spellInfo) - return; - - uint32 cooldown = spellInfo->GetRecoveryTime(); - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellid, SPELLMOD_COOLDOWN, cooldown); - - if (cooldown) - _AddCreatureSpellCooldown(spellid, time(NULL) + cooldown/IN_MILLISECONDS); - - if (spellInfo->GetCategory()) - _AddCreatureCategoryCooldown(spellInfo->GetCategory(), time(NULL)); -} - -bool Creature::HasCategoryCooldown(uint32 spell_id) const -{ - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); - if (!spellInfo) - return false; - - CreatureSpellCooldowns::const_iterator itr = m_CreatureCategoryCooldowns.find(spellInfo->GetCategory()); - return(itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / IN_MILLISECONDS)) > time(NULL)); -} - -uint32 Creature::GetCreatureSpellCooldownDelay(uint32 spellId) const -{ - CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spellId); - time_t t = time(NULL); - return uint32(itr != m_CreatureSpellCooldowns.end() && itr->second > t ? itr->second - t : 0); -} - -bool Creature::HasSpellCooldown(uint32 spell_id) const -{ - CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spell_id); - return (itr != m_CreatureSpellCooldowns.end() && itr->second > time(NULL)) || HasCategoryCooldown(spell_id); -} - -void Creature::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) -{ - time_t curTime = time(NULL); - for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i) - { - if (m_spells[i] == 0) - continue; - - uint32 unSpellId = m_spells[i]; - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(unSpellId); - - // Not send cooldown for this spells - if (spellInfo->IsCooldownStartedOnEvent()) - continue; - - if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE) - continue; - - if ((idSchoolMask & spellInfo->GetSchoolMask()) && GetCreatureSpellCooldownDelay(unSpellId) < unTimeMs) - { - _AddCreatureSpellCooldown(unSpellId, curTime + unTimeMs/IN_MILLISECONDS); - if (UnitAI* ai = GetAI()) - ai->SpellInterrupted(unSpellId, unTimeMs); - } - } -} - bool Creature::HasSpell(uint32 spellID) const { uint8 i; diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index ec06bf90595..6f82d5dda4a 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -170,12 +170,7 @@ struct CreatureTemplate // Benchmarked: Faster than std::map (insert/find) typedef std::unordered_map<uint32, CreatureTemplate> CreatureTemplateContainer; -// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform -#if defined(__GNUC__) -#pragma pack(1) -#else #pragma pack(push, 1) -#endif // Defines base stats for creatures (used to calculate HP/mana/armor/attackpower/rangedattackpower/all damage). struct CreatureBaseStats @@ -307,12 +302,7 @@ enum ChatType CHAT_TYPE_END = 255 }; -// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform -#if defined(__GNUC__) -#pragma pack() -#else #pragma pack(pop) -#endif // `creature_addon` table struct CreatureAddon @@ -414,8 +404,6 @@ struct TrainerSpellData TrainerSpell const* Find(uint32 spell_id) const; }; -typedef std::map<uint32, time_t> CreatureSpellCooldowns; - // max different by z coordinate for creature aggro reaction #define CREATURE_Z_ATTACK_RANGE 3 @@ -494,14 +482,6 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject SpellSchoolMask GetMeleeDamageSchoolMask() const override { return m_meleeDamageSchoolMask; } void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); } - void _AddCreatureSpellCooldown(uint32 spell_id, time_t end_time); - void _AddCreatureCategoryCooldown(uint32 category, time_t apply_time); - void AddCreatureSpellCooldown(uint32 spellid); - bool HasSpellCooldown(uint32 spell_id) const; - bool HasCategoryCooldown(uint32 spell_id) const; - uint32 GetCreatureSpellCooldownDelay(uint32 spellId) const; - virtual void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) override; - bool HasSpell(uint32 spellID) const override; bool UpdateEntry(uint32 entry, CreatureData const* data = nullptr); @@ -575,8 +555,6 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject SpellInfo const* reachWithSpellCure(Unit* victim); uint32 m_spells[CREATURE_MAX_SPELLS]; - CreatureSpellCooldowns m_CreatureSpellCooldowns; - CreatureSpellCooldowns m_CreatureCategoryCooldowns; bool CanStartAttack(Unit const* u, bool force) const; float GetAttackDistance(Unit const* player) const; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 1290b5f0019..a4b140b9878 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -271,6 +271,16 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa SetGoAnimProgress(animprogress); break; } + + if (GameObjectAddon const* addon = sObjectMgr->GetGameObjectAddon(guidlow)) + { + if (addon->InvisibilityValue) + { + m_invisibility.AddFlag(addon->invisibilityType); + m_invisibility.AddValue(addon->invisibilityType, addon->InvisibilityValue); + } + } + LastUsedScriptID = GetGOInfo()->ScriptId; AIM_Initialize(); diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index b3e8510e2fb..5f1d2c793e6 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -576,6 +576,15 @@ struct GameObjectLocale StringVector CastBarCaption; }; +// `gameobject_addon` table +struct GameObjectAddon +{ + InvisibilityType invisibilityType; + uint32 InvisibilityValue; +}; + +typedef std::unordered_map<ObjectGuid::LowType, GameObjectAddon> GameObjectAddonContainer; + // client side GO show states enum GOState { diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index c82ae723f4c..b832aeb5614 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -201,8 +201,6 @@ enum ItemUpdateState ITEM_REMOVED = 3 }; -#define MAX_ITEM_SPELLS 5 - bool ItemCanGoIntoBag(ItemTemplate const* proto, ItemTemplate const* pBagProto); class Item : public Object diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 4be3a03040d..6392c3ee51b 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1008,61 +1008,6 @@ bool Object::PrintIndexError(uint32 index, bool set) const return false; } -bool Position::operator==(Position const &a) -{ - return (G3D::fuzzyEq(a.m_positionX, m_positionX) && - G3D::fuzzyEq(a.m_positionY, m_positionY) && - G3D::fuzzyEq(a.m_positionZ, m_positionZ) && - G3D::fuzzyEq(a.m_orientation, m_orientation)); -} - -bool Position::HasInLine(WorldObject const* target, float width) const -{ - if (!HasInArc(float(M_PI), target)) - return false; - width += target->GetObjectSize(); - float angle = GetRelativeAngle(target); - return std::fabs(std::sin(angle)) * GetExactDist2d(target->GetPositionX(), target->GetPositionY()) < width; -} - -std::string Position::ToString() const -{ - std::stringstream sstr; - sstr << "X: " << m_positionX << " Y: " << m_positionY << " Z: " << m_positionZ << " O: " << m_orientation; - return sstr.str(); -} - -ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer) -{ - float x, y, z, o; - buf >> x >> y >> z >> o; - streamer.m_pos->Relocate(x, y, z, o); - return buf; -} -ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer) -{ - float x, y, z; - streamer.m_pos->GetPosition(x, y, z); - buf << x << y << z; - return buf; -} - -ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer) -{ - float x, y, z; - buf >> x >> y >> z; - streamer.m_pos->Relocate(x, y, z); - return buf; -} - -ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer) -{ - float x, y, z, o; - streamer.m_pos->GetPosition(x, y, z, o); - buf << x << y << z << o; - return buf; -} - void MovementInfo::OutDebug() { TC_LOG_DEBUG("misc", "MOVEMENT INFO"); @@ -1423,92 +1368,6 @@ bool WorldObject::IsInRange3d(float x, float y, float z, float minRange, float m return distsq < maxdist * maxdist; } -void Position::RelocateOffset(const Position & offset) -{ - m_positionX = GetPositionX() + (offset.GetPositionX() * std::cos(GetOrientation()) + offset.GetPositionY() * std::sin(GetOrientation() + float(M_PI))); - m_positionY = GetPositionY() + (offset.GetPositionY() * std::cos(GetOrientation()) + offset.GetPositionX() * std::sin(GetOrientation())); - m_positionZ = GetPositionZ() + offset.GetPositionZ(); - SetOrientation(GetOrientation() + offset.GetOrientation()); -} - -void Position::GetPositionOffsetTo(const Position & endPos, Position & retOffset) const -{ - float dx = endPos.GetPositionX() - GetPositionX(); - float dy = endPos.GetPositionY() - GetPositionY(); - - retOffset.m_positionX = dx * std::cos(GetOrientation()) + dy * std::sin(GetOrientation()); - retOffset.m_positionY = dy * std::cos(GetOrientation()) - dx * std::sin(GetOrientation()); - retOffset.m_positionZ = endPos.GetPositionZ() - GetPositionZ(); - retOffset.SetOrientation(endPos.GetOrientation() - GetOrientation()); -} - -Position Position::GetPositionWithOffset(Position const& offset) const -{ - Position ret(*this); - ret.RelocateOffset(offset); - return ret; -} - -float Position::GetAngle(const Position* obj) const -{ - if (!obj) - return 0; - - return GetAngle(obj->GetPositionX(), obj->GetPositionY()); -} - -// Return angle in range 0..2*pi -float Position::GetAngle(const float x, const float y) const -{ - float dx = x - GetPositionX(); - float dy = y - GetPositionY(); - - float ang = std::atan2(dy, dx); - ang = (ang >= 0) ? ang : 2 * float(M_PI) + ang; - return ang; -} - -void Position::GetSinCos(const float x, const float y, float &vsin, float &vcos) const -{ - float dx = GetPositionX() - x; - float dy = GetPositionY() - y; - - if (std::fabs(dx) < 0.001f && std::fabs(dy) < 0.001f) - { - float angle = (float)rand_norm()*static_cast<float>(2*M_PI); - vcos = std::cos(angle); - vsin = std::sin(angle); - } - else - { - float dist = std::sqrt((dx*dx) + (dy*dy)); - vcos = dx / dist; - vsin = dy / dist; - } -} - -bool Position::HasInArc(float arc, const Position* obj, float border) const -{ - // always have self in arc - if (obj == this) - return true; - - // move arc to range 0.. 2*pi - arc = NormalizeOrientation(arc); - - float angle = GetAngle(obj); - angle -= m_orientation; - - // move angle to range -pi ... +pi - angle = NormalizeOrientation(angle); - if (angle > float(M_PI)) - angle -= 2.0f * float(M_PI); - - float lborder = -1 * (arc/border); // in range -pi..0 - float rborder = (arc/border); // in range 0..pi - return ((angle >= lborder) && (angle <= rborder)); -} - bool WorldObject::IsInBetween(const WorldObject* obj1, const WorldObject* obj2, float size) const { if (!obj1 || !obj2) @@ -1642,11 +1501,6 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const } } -bool Position::IsPositionValid() const -{ - return Trinity::IsValidMapCoord(m_positionX, m_positionY, m_positionZ, m_orientation); -} - float WorldObject::GetGridActivationRange() const { if (ToPlayer()) diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index c48d8ff4d18..a560afa7f1b 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -20,6 +20,7 @@ #define _OBJECT_H #include "Common.h" +#include "Position.h" #include "UpdateMask.h" #include "GridReference.h" #include "ObjectDefines.h" @@ -246,141 +247,6 @@ class Object Object& operator=(Object const& right) = delete; }; -struct Position -{ - Position(float x = 0, float y = 0, float z = 0, float o = 0) - : m_positionX(x), m_positionY(y), m_positionZ(z), m_orientation(NormalizeOrientation(o)) { } - - Position(const Position &loc) { Relocate(loc); } - - struct PositionXYZStreamer - { - explicit PositionXYZStreamer(Position& pos) : m_pos(&pos) { } - Position* m_pos; - }; - - struct PositionXYZOStreamer - { - explicit PositionXYZOStreamer(Position& pos) : m_pos(&pos) { } - Position* m_pos; - }; - - float m_positionX; - float m_positionY; - float m_positionZ; -// Better to limit access to m_orientation field, but this will be hard to achieve with many scripts using array initialization for this structure -//private: - float m_orientation; -//public: - - bool operator==(Position const &a); - - inline bool operator!=(Position const &a) - { - return !(operator==(a)); - } - - void Relocate(float x, float y) - { m_positionX = x; m_positionY = y;} - void Relocate(float x, float y, float z) - { m_positionX = x; m_positionY = y; m_positionZ = z; } - void Relocate(float x, float y, float z, float orientation) - { m_positionX = x; m_positionY = y; m_positionZ = z; SetOrientation(orientation); } - void Relocate(Position const &pos) - { m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; SetOrientation(pos.m_orientation); } - void Relocate(Position const* pos) - { m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; SetOrientation(pos->m_orientation); } - void RelocateOffset(Position const &offset); - void SetOrientation(float orientation) - { m_orientation = NormalizeOrientation(orientation); } - - float GetPositionX() const { return m_positionX; } - float GetPositionY() const { return m_positionY; } - float GetPositionZ() const { return m_positionZ; } - float GetOrientation() const { return m_orientation; } - - void GetPosition(float &x, float &y) const - { x = m_positionX; y = m_positionY; } - void GetPosition(float &x, float &y, float &z) const - { x = m_positionX; y = m_positionY; z = m_positionZ; } - void GetPosition(float &x, float &y, float &z, float &o) const - { x = m_positionX; y = m_positionY; z = m_positionZ; o = m_orientation; } - - Position GetPosition() const - { - return *this; - } - - Position::PositionXYZStreamer PositionXYZStream() - { - return PositionXYZStreamer(*this); - } - Position::PositionXYZOStreamer PositionXYZOStream() - { - return PositionXYZOStreamer(*this); - } - - bool IsPositionValid() const; - - float GetExactDist2dSq(float x, float y) const - { float dx = m_positionX - x; float dy = m_positionY - y; return dx*dx + dy*dy; } - float GetExactDist2d(const float x, const float y) const - { return std::sqrt(GetExactDist2dSq(x, y)); } - float GetExactDist2dSq(Position const* pos) const - { float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy; } - float GetExactDist2d(Position const* pos) const - { return std::sqrt(GetExactDist2dSq(pos)); } - float GetExactDistSq(float x, float y, float z) const - { float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz; } - float GetExactDist(float x, float y, float z) const - { return std::sqrt(GetExactDistSq(x, y, z)); } - float GetExactDistSq(Position const* pos) const - { float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; float dz = m_positionZ - pos->m_positionZ; return dx*dx + dy*dy + dz*dz; } - float GetExactDist(Position const* pos) const - { return std::sqrt(GetExactDistSq(pos)); } - - void GetPositionOffsetTo(Position const & endPos, Position & retOffset) const; - Position GetPositionWithOffset(Position const& offset) const; - - float GetAngle(Position const* pos) const; - float GetAngle(float x, float y) const; - float GetRelativeAngle(Position const* pos) const - { return GetAngle(pos) - m_orientation; } - float GetRelativeAngle(float x, float y) const { return GetAngle(x, y) - m_orientation; } - void GetSinCos(float x, float y, float &vsin, float &vcos) const; - - bool IsInDist2d(float x, float y, float dist) const - { return GetExactDist2dSq(x, y) < dist * dist; } - bool IsInDist2d(Position const* pos, float dist) const - { return GetExactDist2dSq(pos) < dist * dist; } - bool IsInDist(float x, float y, float z, float dist) const - { return GetExactDistSq(x, y, z) < dist * dist; } - bool IsInDist(Position const* pos, float dist) const - { return GetExactDistSq(pos) < dist * dist; } - bool HasInArc(float arcangle, Position const* pos, float border = 2.0f) const; - bool HasInLine(WorldObject const* target, float width) const; - std::string ToString() const; - - // modulos a radian orientation to the range of 0..2PI - static float NormalizeOrientation(float o) - { - // fmod only supports positive numbers. Thus we have - // to emulate negative numbers - if (o < 0) - { - float mod = o *-1; - mod = std::fmod(mod, 2.0f * static_cast<float>(M_PI)); - mod = -mod + 2.0f * static_cast<float>(M_PI); - return mod; - } - return std::fmod(o, 2.0f * static_cast<float>(M_PI)); - } -}; -ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer); -ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer); -ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer); -ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer); - struct MovementInfo { // common diff --git a/src/server/game/Entities/Object/ObjectGuid.h b/src/server/game/Entities/Object/ObjectGuid.h index 36dbdd72069..45881ddab6d 100644 --- a/src/server/game/Entities/Object/ObjectGuid.h +++ b/src/server/game/Entities/Object/ObjectGuid.h @@ -83,10 +83,12 @@ class ObjectGuid public: static ObjectGuid const Empty; + typedef uint32 LowType; + ObjectGuid() : _guid(0) { } explicit ObjectGuid(uint64 guid) : _guid(guid) { } - ObjectGuid(HighGuid hi, uint32 entry, uint32 counter) : _guid(counter ? uint64(counter) | (uint64(entry) << 24) | (uint64(hi) << 48) : 0) { } - ObjectGuid(HighGuid hi, uint32 counter) : _guid(counter ? uint64(counter) | (uint64(hi) << 48) : 0) { } + ObjectGuid(HighGuid hi, uint32 entry, LowType counter) : _guid(counter ? uint64(counter) | (uint64(entry) << 24) | (uint64(hi) << 48) : 0) { } + ObjectGuid(HighGuid hi, LowType counter) : _guid(counter ? uint64(counter) | (uint64(hi) << 48) : 0) { } operator uint64() const { return _guid; } PackedGuidReader ReadAsPacked() { return PackedGuidReader(*this); } @@ -99,11 +101,11 @@ class ObjectGuid uint64 GetRawValue() const { return _guid; } HighGuid GetHigh() const { return HighGuid((_guid >> 48) & 0x0000FFFF); } uint32 GetEntry() const { return HasEntry() ? uint32((_guid >> 24) & UI64LIT(0x0000000000FFFFFF)) : 0; } - uint32 GetCounter() const + LowType GetCounter() const { return HasEntry() - ? uint32(_guid & UI64LIT(0x0000000000FFFFFF)) - : uint32(_guid & UI64LIT(0x00000000FFFFFFFF)); + ? LowType(_guid & UI64LIT(0x0000000000FFFFFF)) + : LowType(_guid & UI64LIT(0x00000000FFFFFFFF)); } static uint32 GetMaxCounter(HighGuid high) diff --git a/src/server/game/Entities/Object/Position.cpp b/src/server/game/Entities/Object/Position.cpp new file mode 100644 index 00000000000..530e51cd8f5 --- /dev/null +++ b/src/server/game/Entities/Object/Position.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Position.h" +#include "ByteBuffer.h" +#include "G3D/g3dmath.h" +#include "GridDefines.h" + +bool Position::operator==(Position const &a) +{ + return (G3D::fuzzyEq(a.m_positionX, m_positionX) && + G3D::fuzzyEq(a.m_positionY, m_positionY) && + G3D::fuzzyEq(a.m_positionZ, m_positionZ) && + G3D::fuzzyEq(a.m_orientation, m_orientation)); +} + +void Position::RelocateOffset(const Position & offset) +{ + m_positionX = GetPositionX() + (offset.GetPositionX() * std::cos(GetOrientation()) + offset.GetPositionY() * std::sin(GetOrientation() + float(M_PI))); + m_positionY = GetPositionY() + (offset.GetPositionY() * std::cos(GetOrientation()) + offset.GetPositionX() * std::sin(GetOrientation())); + m_positionZ = GetPositionZ() + offset.GetPositionZ(); + SetOrientation(GetOrientation() + offset.GetOrientation()); +} + +bool Position::IsPositionValid() const +{ + return Trinity::IsValidMapCoord(m_positionX, m_positionY, m_positionZ, m_orientation); +} + +void Position::GetPositionOffsetTo(const Position & endPos, Position & retOffset) const +{ + float dx = endPos.GetPositionX() - GetPositionX(); + float dy = endPos.GetPositionY() - GetPositionY(); + + retOffset.m_positionX = dx * std::cos(GetOrientation()) + dy * std::sin(GetOrientation()); + retOffset.m_positionY = dy * std::cos(GetOrientation()) - dx * std::sin(GetOrientation()); + retOffset.m_positionZ = endPos.GetPositionZ() - GetPositionZ(); + retOffset.SetOrientation(endPos.GetOrientation() - GetOrientation()); +} + +Position Position::GetPositionWithOffset(Position const& offset) const +{ + Position ret(*this); + ret.RelocateOffset(offset); + return ret; +} + +float Position::GetAngle(const Position* obj) const +{ + if (!obj) + return 0; + + return GetAngle(obj->GetPositionX(), obj->GetPositionY()); +} + +// Return angle in range 0..2*pi +float Position::GetAngle(float x, float y) const +{ + float dx = x - GetPositionX(); + float dy = y - GetPositionY(); + + float ang = std::atan2(dy, dx); + ang = (ang >= 0) ? ang : 2 * float(M_PI) + ang; + return ang; +} + +void Position::GetSinCos(const float x, const float y, float &vsin, float &vcos) const +{ + float dx = GetPositionX() - x; + float dy = GetPositionY() - y; + + if (std::fabs(dx) < 0.001f && std::fabs(dy) < 0.001f) + { + float angle = (float)rand_norm()*static_cast<float>(2 * M_PI); + vcos = std::cos(angle); + vsin = std::sin(angle); + } + else + { + float dist = std::sqrt((dx*dx) + (dy*dy)); + vcos = dx / dist; + vsin = dy / dist; + } +} + +bool Position::HasInArc(float arc, const Position* obj, float border) const +{ + // always have self in arc + if (obj == this) + return true; + + // move arc to range 0.. 2*pi + arc = NormalizeOrientation(arc); + + float angle = GetAngle(obj); + angle -= m_orientation; + + // move angle to range -pi ... +pi + angle = NormalizeOrientation(angle); + if (angle > float(M_PI)) + angle -= 2.0f * float(M_PI); + + float lborder = -1 * (arc / border); // in range -pi..0 + float rborder = (arc / border); // in range 0..pi + return ((angle >= lborder) && (angle <= rborder)); +} + +bool Position::HasInLine(Position const* pos, float width) const +{ + if (!HasInArc(float(M_PI), pos)) + return false; + + float angle = GetRelativeAngle(pos); + return std::fabs(std::sin(angle)) * GetExactDist2d(pos->GetPositionX(), pos->GetPositionY()) < width; +} + +std::string Position::ToString() const +{ + std::stringstream sstr; + sstr << "X: " << m_positionX << " Y: " << m_positionY << " Z: " << m_positionZ << " O: " << m_orientation; + return sstr.str(); +} + +ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer) +{ + buf << streamer.Pos->GetPositionX(); + buf << streamer.Pos->GetPositionY(); + return buf; +} + +ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYStreamer const& streamer) +{ + float x, y; + buf >> x >> y; + streamer.Pos->Relocate(x, y); + return buf; +} + +ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer) +{ + buf << streamer.Pos->GetPositionX(); + buf << streamer.Pos->GetPositionY(); + buf << streamer.Pos->GetPositionZ(); + return buf; +} + +ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer) +{ + float x, y, z; + buf >> x >> y >> z; + streamer.Pos->Relocate(x, y, z); + return buf; +} + +ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer) +{ + buf << streamer.Pos->GetPositionX(); + buf << streamer.Pos->GetPositionY(); + buf << streamer.Pos->GetPositionZ(); + buf << streamer.Pos->GetOrientation(); + return buf; +} + +ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer) +{ + float x, y, z, o; + buf >> x >> y >> z >> o; + streamer.Pos->Relocate(x, y, z, o); + return buf; +} diff --git a/src/server/game/Entities/Object/Position.h b/src/server/game/Entities/Object/Position.h new file mode 100644 index 00000000000..5bd37567811 --- /dev/null +++ b/src/server/game/Entities/Object/Position.h @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef Trinity_game_Position_h__ +#define Trinity_game_Position_h__ + +#include "Common.h" + +class ByteBuffer; + +struct Position +{ + Position(float x = 0, float y = 0, float z = 0, float o = 0) + : m_positionX(x), m_positionY(y), m_positionZ(z), m_orientation(NormalizeOrientation(o)) { } + + Position(Position const& loc) { Relocate(loc); } + + struct PositionXYStreamer + { + explicit PositionXYStreamer(Position& pos) : Pos(&pos) { } + Position* Pos; + }; + + struct PositionXYZStreamer + { + explicit PositionXYZStreamer(Position& pos) : Pos(&pos) { } + Position* Pos; + }; + + struct PositionXYZOStreamer + { + explicit PositionXYZOStreamer(Position& pos) : Pos(&pos) { } + Position* Pos; + }; + + float m_positionX; + float m_positionY; + float m_positionZ; + // Better to limit access to _orientation field, to guarantee the value is normalized +private: + float m_orientation; + +public: + bool operator==(Position const &a); + + inline bool operator!=(Position const &a) + { + return !(operator==(a)); + } + + void Relocate(float x, float y) + { + m_positionX = x; m_positionY = y; + } + + void Relocate(float x, float y, float z) + { + m_positionX = x; m_positionY = y; m_positionZ = z; + } + + void Relocate(float x, float y, float z, float orientation) + { + m_positionX = x; m_positionY = y; m_positionZ = z; SetOrientation(orientation); + } + + void Relocate(Position const &pos) + { + m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; SetOrientation(pos.m_orientation); + } + + void Relocate(Position const* pos) + { + m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; SetOrientation(pos->m_orientation); + } + + void RelocateOffset(Position const &offset); + + void SetOrientation(float orientation) + { + m_orientation = NormalizeOrientation(orientation); + } + + float GetPositionX() const { return m_positionX; } + float GetPositionY() const { return m_positionY; } + float GetPositionZ() const { return m_positionZ; } + float GetOrientation() const { return m_orientation; } + + void GetPosition(float &x, float &y) const + { + x = m_positionX; y = m_positionY; + } + + void GetPosition(float &x, float &y, float &z) const + { + x = m_positionX; y = m_positionY; z = m_positionZ; + } + + void GetPosition(float &x, float &y, float &z, float &o) const + { + x = m_positionX; y = m_positionY; z = m_positionZ; o = m_orientation; + } + + Position GetPosition() const { return *this; } + + Position::PositionXYStreamer PositionXYStream() { return PositionXYStreamer(*this); } + Position::PositionXYZStreamer PositionXYZStream() { return PositionXYZStreamer(*this); } + Position::PositionXYZOStreamer PositionXYZOStream() { return PositionXYZOStreamer(*this); } + + bool IsPositionValid() const; + + float GetExactDist2dSq(float x, float y) const + { + float dx = m_positionX - x; float dy = m_positionY - y; return dx*dx + dy*dy; + } + + float GetExactDist2d(const float x, const float y) const + { + return std::sqrt(GetExactDist2dSq(x, y)); + } + + float GetExactDist2dSq(Position const* pos) const + { + float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy; + } + + float GetExactDist2d(Position const* pos) const + { + return std::sqrt(GetExactDist2dSq(pos)); + } + + float GetExactDistSq(float x, float y, float z) const + { + float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz; + } + + float GetExactDist(float x, float y, float z) const + { + return std::sqrt(GetExactDistSq(x, y, z)); + } + + float GetExactDistSq(Position const* pos) const + { + float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; float dz = m_positionZ - pos->m_positionZ; return dx*dx + dy*dy + dz*dz; + } + + float GetExactDist(Position const* pos) const + { + return std::sqrt(GetExactDistSq(pos)); + } + + void GetPositionOffsetTo(Position const & endPos, Position & retOffset) const; + Position GetPositionWithOffset(Position const& offset) const; + + float GetAngle(Position const* pos) const; + float GetAngle(float x, float y) const; + float GetRelativeAngle(Position const* pos) const + { + return GetAngle(pos) - m_orientation; + } + + float GetRelativeAngle(float x, float y) const { return GetAngle(x, y) - m_orientation; } + void GetSinCos(float x, float y, float &vsin, float &vcos) const; + + bool IsInDist2d(float x, float y, float dist) const + { + return GetExactDist2dSq(x, y) < dist * dist; + } + + bool IsInDist2d(Position const* pos, float dist) const + { + return GetExactDist2dSq(pos) < dist * dist; + } + + bool IsInDist(float x, float y, float z, float dist) const + { + return GetExactDistSq(x, y, z) < dist * dist; + } + + bool IsInDist(Position const* pos, float dist) const + { + return GetExactDistSq(pos) < dist * dist; + } + + bool HasInArc(float arcangle, Position const* pos, float border = 2.0f) const; + bool HasInLine(Position const* pos, float width) const; + std::string ToString() const; + + // modulos a radian orientation to the range of 0..2PI + static float NormalizeOrientation(float o) + { + // fmod only supports positive numbers. Thus we have + // to emulate negative numbers + if (o < 0) + { + float mod = o *-1; + mod = std::fmod(mod, 2.0f * static_cast<float>(M_PI)); + mod = -mod + 2.0f * static_cast<float>(M_PI); + return mod; + } + return std::fmod(o, 2.0f * static_cast<float>(M_PI)); + } +}; + +ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer); +ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYStreamer const& streamer); +ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer); +ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer); +ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer); +ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer); + +#endif // Trinity_game_Position_h__ diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index d5d6bdf9831..97cdb0cf1df 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -24,6 +24,7 @@ #include "SpellMgr.h" #include "Pet.h" #include "Formulas.h" +#include "SpellHistory.h" #include "SpellAuras.h" #include "SpellAuraEffects.h" #include "Unit.h" @@ -407,7 +408,7 @@ void Pet::SavePetToDB(PetSaveMode mode) RemoveAllAuras(); _SaveSpells(trans); - _SaveSpellCooldowns(trans); + GetSpellHistory()->SaveToDB<Pet>(trans); CharacterDatabase.CommitTransaction(trans); // current/stable/not_in_slot @@ -1106,77 +1107,11 @@ uint32 Pet::GetCurrentFoodBenefitLevel(uint32 itemlevel) const void Pet::_LoadSpellCooldowns() { - m_CreatureSpellCooldowns.clear(); - m_CreatureCategoryCooldowns.clear(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL_COOLDOWN); stmt->setUInt32(0, m_charmInfo->GetPetNumber()); - PreparedQueryResult result = CharacterDatabase.Query(stmt); - - if (result) - { - time_t curTime = time(NULL); - - PacketCooldowns cooldowns; - WorldPacket data; - - do - { - Field* fields = result->Fetch(); - - uint32 spell_id = fields[0].GetUInt32(); - time_t db_time = time_t(fields[1].GetUInt32()); - - if (!sSpellMgr->GetSpellInfo(spell_id)) - { - TC_LOG_ERROR("entities.pet", "Pet %u have unknown spell %u in `pet_spell_cooldown`, skipping.", m_charmInfo->GetPetNumber(), spell_id); - continue; - } + PreparedQueryResult cooldownsResult = CharacterDatabase.Query(stmt); - // skip outdated cooldown - if (db_time <= curTime) - continue; - - cooldowns[spell_id] = uint32(db_time - curTime)*IN_MILLISECONDS; - - _AddCreatureSpellCooldown(spell_id, db_time); - - TC_LOG_DEBUG("entities.pet", "Pet (Number: %u) spell %u cooldown loaded (%u secs).", m_charmInfo->GetPetNumber(), spell_id, uint32(db_time-curTime)); - } - while (result->NextRow()); - - if (!cooldowns.empty()) - { - BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, cooldowns); - GetOwner()->GetSession()->SendPacket(&data); - } - } -} - -void Pet::_SaveSpellCooldowns(SQLTransaction& trans) -{ - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PET_SPELL_COOLDOWNS); - stmt->setUInt32(0, m_charmInfo->GetPetNumber()); - trans->Append(stmt); - - time_t curTime = time(NULL); - - // remove oudated and save active - for (CreatureSpellCooldowns::iterator itr = m_CreatureSpellCooldowns.begin(); itr != m_CreatureSpellCooldowns.end();) - { - if (itr->second <= curTime) - m_CreatureSpellCooldowns.erase(itr++); - else - { - stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET_SPELL_COOLDOWN); - stmt->setUInt32(0, m_charmInfo->GetPetNumber()); - stmt->setUInt32(1, itr->first); - stmt->setUInt32(2, uint32(itr->second)); - trans->Append(stmt); - - ++itr; - } - } + GetSpellHistory()->LoadFromDB<Pet>(cooldownsResult); } void Pet::_LoadSpells() @@ -2025,40 +1960,6 @@ void Pet::SynchronizeLevelWithOwner() } } -void Pet::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) -{ - PacketCooldowns cooldowns; - WorldPacket data; - time_t curTime = time(NULL); - for (PetSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) - { - if (itr->second.state == PETSPELL_REMOVED) - continue; - - uint32 unSpellId = itr->first; - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(unSpellId); - - // Not send cooldown for this spells - if (spellInfo->IsCooldownStartedOnEvent()) - continue; - - if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE) - continue; - - if ((idSchoolMask & spellInfo->GetSchoolMask()) && GetCreatureSpellCooldownDelay(unSpellId) < unTimeMs) - { - cooldowns[unSpellId] = unTimeMs; - _AddCreatureSpellCooldown(unSpellId, curTime + unTimeMs/IN_MILLISECONDS); - } - } - - if (!cooldowns.empty()) - { - BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, cooldowns); - GetOwner()->GetSession()->SendPacket(&data); - } -} - Player* Pet::GetOwner() const { return Minion::GetOwner()->ToPlayer(); diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index 62d82aaab1b..1cc86ea2a20 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -108,7 +108,6 @@ class Pet : public Guardian bool IsPetAura(Aura const* aura); void _LoadSpellCooldowns(); - void _SaveSpellCooldowns(SQLTransaction& trans); void _LoadAuras(uint32 timediff); void _SaveAuras(SQLTransaction& trans); void _LoadSpells(); @@ -121,7 +120,6 @@ class Pet : public Guardian bool unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true); bool removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true); void CleanupActionBar(); - virtual void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) override; PetSpellMap m_spells; AutoSpellList m_autospells; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 32fd5c53803..030c2a25110 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -67,6 +67,7 @@ #include "SpellAuraEffects.h" #include "SpellAuras.h" #include "SpellMgr.h" +#include "SpellHistory.h" #include "Transport.h" #include "UpdateData.h" #include "UpdateFieldFlags.h" @@ -3345,12 +3346,10 @@ void Player::InitStatsForLevel(bool reapplyMods) void Player::SendInitialSpells() { - time_t curTime = time(NULL); - time_t infTime = curTime + infinityCooldownDelayCheck; - + uint16 spellCooldowns = GetSpellHistory()->GetCooldownsSizeForPacket(); uint16 spellCount = 0; - WorldPacket data(SMSG_INITIAL_SPELLS, (1+2+4*m_spells.size()+2+m_spellCooldowns.size()*(2+2+2+4+4))); + WorldPacket data(SMSG_INITIAL_SPELLS, (1 + 2 + 4 * m_spells.size() + 2 + spellCooldowns * (2 + 2 + 2 + 4 + 4))); data << uint8(0); size_t countPos = data.wpos(); @@ -3372,40 +3371,7 @@ void Player::SendInitialSpells() data.put<uint16>(countPos, spellCount); // write real count value - uint16 spellCooldowns = m_spellCooldowns.size(); - data << uint16(spellCooldowns); - for (SpellCooldowns::const_iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); ++itr) - { - SpellInfo const* sEntry = sSpellMgr->GetSpellInfo(itr->first); - if (!sEntry) - continue; - - data << uint32(itr->first); - - data << uint16(itr->second.itemid); // cast item id - data << uint16(sEntry->GetCategory()); // spell category - - // send infinity cooldown in special format - if (itr->second.end >= infTime) - { - data << uint32(1); // cooldown - data << uint32(0x80000000); // category cooldown - continue; - } - - time_t cooldown = itr->second.end > curTime ? (itr->second.end-curTime)*IN_MILLISECONDS : 0; - - if (sEntry->GetCategory()) // may be wrong, but anyway better than nothing... - { - data << uint32(0); // cooldown - data << uint32(cooldown); // category cooldown - } - else - { - data << uint32(cooldown); // cooldown - data << uint32(0); // category cooldown - } - } + GetSpellHistory()->WritePacket<Player>(data); GetSession()->SendPacket(&data); @@ -4202,154 +4168,19 @@ bool Player::Has310Flyer(bool checkAllSpells, uint32 excludeSpellId) return false; } -void Player::RemoveSpellCooldown(uint32 spell_id, bool update /* = false */) -{ - m_spellCooldowns.erase(spell_id); - - if (update) - SendClearCooldown(spell_id, this); -} - -// I am not sure which one is more efficient -void Player::RemoveCategoryCooldown(uint32 cat) -{ - SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(cat); - if (i_scstore != sSpellsByCategoryStore.end()) - for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset) - RemoveSpellCooldown(*i_scset, true); -} - -void Player::RemoveSpellCategoryCooldown(uint32 cat, bool update /* = false */) -{ - SpellCategoryStore::const_iterator ct = sSpellsByCategoryStore.find(cat); - if (ct == sSpellsByCategoryStore.end()) - return; - - const SpellCategorySet& ct_set = ct->second; - for (SpellCooldowns::const_iterator i = m_spellCooldowns.begin(); i != m_spellCooldowns.end();) - { - if (ct_set.find(i->first) != ct_set.end()) - RemoveSpellCooldown((i++)->first, update); - else - ++i; - } -} - void Player::RemoveArenaSpellCooldowns(bool removeActivePetCooldowns) { // remove cooldowns on spells that have < 10 min CD - - SpellCooldowns::iterator itr, next; - for (itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); itr = next) + GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool { - next = itr; - ++next; - SpellInfo const* entry = sSpellMgr->GetSpellInfo(itr->first); - // check if spellentry is present and if the cooldown is less than 10 min - if (entry && - entry->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS && - entry->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS) - { - // remove & notify - RemoveSpellCooldown(itr->first, true); - } - } + SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); + return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS; + }, true); // pet cooldowns if (removeActivePetCooldowns) if (Pet* pet = GetPet()) - { - // notify player - for (CreatureSpellCooldowns::const_iterator itr2 = pet->m_CreatureSpellCooldowns.begin(); itr2 != pet->m_CreatureSpellCooldowns.end(); ++itr2) - SendClearCooldown(itr2->first, pet); - - // actually clear cooldowns - pet->m_CreatureSpellCooldowns.clear(); - } -} - -void Player::RemoveAllSpellCooldown() -{ - if (!m_spellCooldowns.empty()) - { - for (SpellCooldowns::const_iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); ++itr) - SendClearCooldown(itr->first, this); - - m_spellCooldowns.clear(); - } -} - -void Player::_LoadSpellCooldowns(PreparedQueryResult result) -{ - // some cooldowns can be already set at aura loading... - - //QueryResult* result = CharacterDatabase.PQuery("SELECT spell, item, time FROM character_spell_cooldown WHERE guid = '%u'", GetGUIDLow()); - - if (result) - { - time_t curTime = time(NULL); - - do - { - Field* fields = result->Fetch(); - uint32 spell_id = fields[0].GetUInt32(); - uint32 item_id = fields[1].GetUInt32(); - time_t db_time = time_t(fields[2].GetUInt32()); - - if (!sSpellMgr->GetSpellInfo(spell_id)) - { - TC_LOG_ERROR("entities.player.loading", "Player %u has unknown spell %u in `character_spell_cooldown`, skipping.", GetGUIDLow(), spell_id); - continue; - } - - // skip outdated cooldown - if (db_time <= curTime) - continue; - - AddSpellCooldown(spell_id, item_id, db_time); - - TC_LOG_DEBUG("entities.player.loading", "Player (GUID: %u) spell %u, item %u cooldown loaded (%u secs).", GetGUIDLow(), spell_id, item_id, uint32(db_time-curTime)); - } - while (result->NextRow()); - } -} - -void Player::_SaveSpellCooldowns(SQLTransaction& trans) -{ - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN); - stmt->setUInt32(0, GetGUIDLow()); - trans->Append(stmt); - - time_t curTime = time(NULL); - time_t infTime = curTime + infinityCooldownDelayCheck; - - bool first_round = true; - std::ostringstream ss; - - // remove outdated and save active - for (SpellCooldowns::iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end();) - { - if (itr->second.end <= curTime) - m_spellCooldowns.erase(itr++); - else if (itr->second.end <= infTime) // not save locked cooldowns, it will be reset or set at reload - { - if (first_round) - { - ss << "INSERT INTO character_spell_cooldown (guid, spell, item, time) VALUES "; - first_round = false; - } - // next new/changed record prefix - else - ss << ','; - ss << '(' << GetGUIDLow() << ',' << itr->first << ',' << itr->second.itemid << ',' << uint64(itr->second.end) << ')'; - ++itr; - } - else - ++itr; - } - // if something changed execute - if (!first_round) - trans->Append(ss.str().c_str()); + pet->GetSpellHistory()->ResetAllCooldowns(); } uint32 Player::ResetTalentsCost() const @@ -4897,7 +4728,7 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe stmt->setUInt32(0, guid); trans->Append(stmt); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWNS); stmt->setUInt32(0, guid); trans->Append(stmt); @@ -8382,7 +8213,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 if (procVictim & PROC_FLAG_TAKEN_DAMAGE) //if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE) { - for (uint8 i = 0; i < MAX_ITEM_SPELLS; ++i) + for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { _Spell const& spellData = proto->Spells[i]; @@ -12425,10 +12256,9 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update) { m_weaponChangeTimer = spellProto->StartRecoveryTime; - GetGlobalCooldownMgr().AddGlobalCooldown(spellProto, m_weaponChangeTimer); - + GetSpellHistory()->AddGlobalCooldown(spellProto, m_weaponChangeTimer); WorldPacket data; - BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_INCLUDE_GCD, cooldownSpell, 0); + GetSpellHistory()->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_INCLUDE_GCD, cooldownSpell, 0); GetSession()->SendPacket(&data); } } @@ -17811,7 +17641,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) // has to be called after last Relocate() in Player::LoadFromDB SetFallInformation(0, GetPositionZ()); - _LoadSpellCooldowns(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS)); + GetSpellHistory()->LoadFromDB<Player>(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS)); // Spell code allow apply any auras to dead character in load time in aura/spell/item loading // Do now before stats re-calculation cleanup for ghost state unexpected auras @@ -19517,7 +19347,7 @@ void Player::SaveToDB(bool create /*=false*/) _SaveMonthlyQuestStatus(trans); _SaveTalents(trans); _SaveSpells(trans); - _SaveSpellCooldowns(trans); + GetSpellHistory()->SaveToDB<Player>(trans); _SaveActions(trans); _SaveAuras(trans); _SaveSkills(trans); @@ -20754,41 +20584,8 @@ void Player::PetSpellInitialize() data.put<uint8>(spellsCountPos, addlist); - uint8 cooldownsCount = pet->m_CreatureSpellCooldowns.size() + pet->m_CreatureCategoryCooldowns.size(); - data << uint8(cooldownsCount); - - time_t curTime = time(NULL); - - for (CreatureSpellCooldowns::const_iterator itr = pet->m_CreatureSpellCooldowns.begin(); itr != pet->m_CreatureSpellCooldowns.end(); ++itr) - { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first); - if (!spellInfo) - { - data << uint32(0); - data << uint16(0); - data << uint32(0); - data << uint32(0); - continue; - } - - time_t cooldown = (itr->second > curTime) ? (itr->second - curTime) * IN_MILLISECONDS : 0; - data << uint32(itr->first); // spell ID - - CreatureSpellCooldowns::const_iterator categoryitr = pet->m_CreatureCategoryCooldowns.find(spellInfo->GetCategory()); - if (categoryitr != pet->m_CreatureCategoryCooldowns.end()) - { - time_t categoryCooldown = (categoryitr->second > curTime) ? (categoryitr->second - curTime) * IN_MILLISECONDS : 0; - data << uint16(spellInfo->GetCategory()); // spell category - data << uint32(cooldown); // spell cooldown - data << uint32(categoryCooldown); // category cooldown - } - else - { - data << uint16(0); - data << uint32(cooldown); - data << uint32(0); - } - } + //Cooldowns + pet->GetSpellHistory()->WritePacket<Pet>(data); GetSession()->SendPacket(&data); } @@ -20827,7 +20624,7 @@ void Player::VehicleSpellInitialize() if (!vehicle) return; - uint8 cooldownCount = vehicle->m_CreatureSpellCooldowns.size(); + uint8 cooldownCount = vehicle->GetSpellHistory()->GetCooldownsSizeForPacket(); WorldPacket data(SMSG_PET_SPELLS, 8 + 2 + 4 + 4 + 4 * 10 + 1 + 1 + cooldownCount * (4 + 2 + 4 + 4)); data << uint64(vehicle->GetGUID()); // Guid @@ -20868,41 +20665,7 @@ void Player::VehicleSpellInitialize() data << uint8(0); // Auras? // Cooldowns - data << uint8(cooldownCount); - - time_t now = sWorld->GetGameTime(); - - for (CreatureSpellCooldowns::const_iterator itr = vehicle->m_CreatureSpellCooldowns.begin(); itr != vehicle->m_CreatureSpellCooldowns.end(); ++itr) - { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first); - if (!spellInfo) - { - data << uint32(0); - data << uint16(0); - data << uint32(0); - data << uint32(0); - continue; - } - - time_t cooldown = (itr->second > now) ? (itr->second - now) * IN_MILLISECONDS : 0; - data << uint32(itr->first); // spell ID - - CreatureSpellCooldowns::const_iterator categoryitr = vehicle->m_CreatureCategoryCooldowns.find(spellInfo->GetCategory()); - if (categoryitr != vehicle->m_CreatureCategoryCooldowns.end()) - { - time_t categoryCooldown = (categoryitr->second > now) ? (categoryitr->second - now) * IN_MILLISECONDS : 0; - data << uint16(spellInfo->GetCategory()); // spell category - data << uint32(cooldown); // spell cooldown - data << uint32(categoryCooldown); // category cooldown - } - else - { - data << uint16(0); - data << uint32(cooldown); - data << uint32(0); - } - } - + vehicle->GetSpellHistory()->WritePacket<Pet>(data); GetSession()->SendPacket(&data); } @@ -21522,9 +21285,9 @@ void Player::ContinueTaxiFlight() float distPrev = MAP_SIZE*MAP_SIZE; float distNext = - (nodeList[0].x-GetPositionX())*(nodeList[0].x-GetPositionX())+ - (nodeList[0].y-GetPositionY())*(nodeList[0].y-GetPositionY())+ - (nodeList[0].z-GetPositionZ())*(nodeList[0].z-GetPositionZ()); + (nodeList[0].LocX-GetPositionX())*(nodeList[0].LocX-GetPositionX())+ + (nodeList[0].LocY-GetPositionY())*(nodeList[0].LocY-GetPositionY())+ + (nodeList[0].LocZ-GetPositionZ())*(nodeList[0].LocZ-GetPositionZ()); for (uint32 i = 1; i < nodeList.size(); ++i) { @@ -21532,20 +21295,20 @@ void Player::ContinueTaxiFlight() TaxiPathNodeEntry const& prevNode = nodeList[i-1]; // skip nodes at another map - if (node.mapid != GetMapId()) + if (node.MapID != GetMapId()) continue; distPrev = distNext; distNext = - (node.x-GetPositionX())*(node.x-GetPositionX())+ - (node.y-GetPositionY())*(node.y-GetPositionY())+ - (node.z-GetPositionZ())*(node.z-GetPositionZ()); + (node.LocX-GetPositionX())*(node.LocX-GetPositionX())+ + (node.LocY-GetPositionY())*(node.LocY-GetPositionY())+ + (node.LocZ-GetPositionZ())*(node.LocZ-GetPositionZ()); float distNodes = - (node.x-prevNode.x)*(node.x-prevNode.x)+ - (node.y-prevNode.y)*(node.y-prevNode.y)+ - (node.z-prevNode.z)*(node.z-prevNode.z); + (node.LocX-prevNode.LocX)*(node.LocX-prevNode.LocX)+ + (node.LocY-prevNode.LocY)*(node.LocY-prevNode.LocY)+ + (node.LocZ-prevNode.LocZ)*(node.LocZ-prevNode.LocZ); if (distNext + distPrev < distNodes) { @@ -21557,39 +21320,6 @@ void Player::ContinueTaxiFlight() GetSession()->SendDoFlight(mountDisplayId, path, startNode); } -void Player::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) -{ - PacketCooldowns cooldowns; - WorldPacket data; - time_t curTime = time(NULL); - for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) - { - if (itr->second->state == PLAYERSPELL_REMOVED) - continue; - uint32 unSpellId = itr->first; - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(unSpellId); - - // Not send cooldown for this spells - if (spellInfo->IsCooldownStartedOnEvent()) - continue; - - if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE) - continue; - - if ((idSchoolMask & spellInfo->GetSchoolMask()) && GetSpellCooldownDelay(unSpellId) < unTimeMs) - { - cooldowns[unSpellId] = unTimeMs; - AddSpellCooldown(unSpellId, 0, curTime + unTimeMs/IN_MILLISECONDS); - } - } - - if (!cooldowns.empty()) - { - BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, cooldowns); - GetSession()->SendPacket(&data); - } -} - void Player::InitDataForForm(bool reapplyMods) { ShapeshiftForm form = GetShapeshiftForm(); @@ -22011,206 +21741,6 @@ void Player::UpdatePvP(bool state, bool _override) } } -bool Player::HasSpellCooldown(uint32 spell_id) const -{ - SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id); - return itr != m_spellCooldowns.end() && itr->second.end > time(NULL); -} - -uint32 Player::GetSpellCooldownDelay(uint32 spell_id) const -{ - SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id); - time_t t = time(NULL); - return uint32(itr != m_spellCooldowns.end() && itr->second.end > t ? itr->second.end - t : 0); -} - -void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 itemId, Spell* spell, bool infinityCooldown) -{ - // init cooldown values - uint32 cat = 0; - int32 rec = -1; - int32 catrec = -1; - - // some special item spells without correct cooldown in SpellInfo - // cooldown information stored in item prototype - // This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client. - - if (itemId) - { - if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId)) - { - for (uint8 idx = 0; idx < MAX_ITEM_SPELLS; ++idx) - { - if (uint32(proto->Spells[idx].SpellId) == spellInfo->Id) - { - cat = proto->Spells[idx].SpellCategory; - rec = proto->Spells[idx].SpellCooldown; - catrec = proto->Spells[idx].SpellCategoryCooldown; - break; - } - } - } - } - - // if no cooldown found above then base at DBC data - if (rec < 0 && catrec < 0) - { - cat = spellInfo->GetCategory(); - rec = spellInfo->RecoveryTime; - catrec = spellInfo->CategoryRecoveryTime; - } - - time_t curTime = time(NULL); - - time_t catrecTime; - time_t recTime; - - bool needsCooldownPacket = false; - - // overwrite time for selected category - if (infinityCooldown) - { - // use +MONTH as infinity mark for spell cooldown (will checked as MONTH/2 at save ans skipped) - // but not allow ignore until reset or re-login - catrecTime = catrec > 0 ? curTime+infinityCooldownDelay : 0; - recTime = rec > 0 ? curTime+infinityCooldownDelay : catrecTime; - } - else - { - // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK) - // prevent 0 cooldowns set by another way - if (rec <= 0 && catrec <= 0 && (cat == 76 || (spellInfo->IsAutoRepeatRangedSpell() && spellInfo->Id != 75))) - rec = GetAttackTime(RANGED_ATTACK); - - // Now we have cooldown data (if found any), time to apply mods - if (rec > 0) - ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, rec, spell); - - if (catrec > 0 && !spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS)) - ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, catrec, spell); - - if (int32 cooldownMod = GetTotalAuraModifier(SPELL_AURA_MOD_COOLDOWN)) - { - // Apply SPELL_AURA_MOD_COOLDOWN only to own spells - if (HasSpell(spellInfo->Id)) - { - needsCooldownPacket = true; - rec += cooldownMod * IN_MILLISECONDS; // SPELL_AURA_MOD_COOLDOWN does not affect category cooldows, verified with shaman shocks - } - } - - // replace negative cooldowns by 0 - if (rec < 0) rec = 0; - if (catrec < 0) catrec = 0; - - // no cooldown after applying spell mods - if (rec == 0 && catrec == 0) - return; - - catrecTime = catrec ? curTime+catrec/IN_MILLISECONDS : 0; - recTime = rec ? curTime+rec/IN_MILLISECONDS : catrecTime; - } - - // self spell cooldown - if (recTime > 0) - { - AddSpellCooldown(spellInfo->Id, itemId, recTime); - - if (needsCooldownPacket) - { - WorldPacket data; - BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, rec); - SendDirectMessage(&data); - } - } - - // category spells - if (cat && catrec > 0) - { - SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(cat); - if (i_scstore != sSpellsByCategoryStore.end()) - { - for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset) - { - if (*i_scset == spellInfo->Id) // skip main spell, already handled above - continue; - - AddSpellCooldown(*i_scset, itemId, catrecTime); - } - } - } -} - -void Player::AddSpellCooldown(uint32 spellid, uint32 itemid, time_t end_time) -{ - SpellCooldown sc; - sc.end = end_time; - sc.itemid = itemid; - m_spellCooldowns[spellid] = sc; -} - -void Player::ModifySpellCooldown(uint32 spellId, int32 cooldown) -{ - SpellCooldowns::iterator itr = m_spellCooldowns.find(spellId); - if (itr == m_spellCooldowns.end()) - return; - - time_t now = time(NULL); - if (itr->second.end + (cooldown / IN_MILLISECONDS) > now) - itr->second.end += (cooldown / IN_MILLISECONDS); - else - m_spellCooldowns.erase(itr); - - WorldPacket data(SMSG_MODIFY_COOLDOWN, 4 + 8 + 4); - data << uint32(spellId); // Spell ID - data << uint64(GetGUID()); // Player GUID - data << int32(cooldown); // Cooldown mod in milliseconds - GetSession()->SendPacket(&data); - - TC_LOG_DEBUG("misc", "ModifySpellCooldown:: Player: %s (GUID: %u) Spell: %u cooldown: %u", GetName().c_str(), GetGUIDLow(), spellId, GetSpellCooldownDelay(spellId)); -} - -void Player::SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId /*= 0*/, Spell* spell /*= NULL*/, bool setCooldown /*= true*/) -{ - // start cooldowns at server side, if any - if (setCooldown) - AddSpellAndCategoryCooldowns(spellInfo, itemId, spell); - - // Send activate cooldown timer (possible 0) at client side - WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8); - data << uint32(spellInfo->Id); - data << uint64(GetGUID()); - SendDirectMessage(&data); - - uint32 cat = spellInfo->GetCategory(); - if (cat && spellInfo->CategoryRecoveryTime) - { - SpellCategoryStore::const_iterator ct = sSpellsByCategoryStore.find(cat); - if (ct != sSpellsByCategoryStore.end()) - { - SpellCategorySet const& catSet = ct->second; - for (SpellCooldowns::const_iterator i = m_spellCooldowns.begin(); i != m_spellCooldowns.end(); ++i) - { - if (i->first == spellInfo->Id) // skip main spell, already handled above - continue; - - SpellInfo const* spellInfo2 = sSpellMgr->GetSpellInfo(i->first); - if (!spellInfo2 || !spellInfo2->IsCooldownStartedOnEvent()) - continue; - - if (catSet.find(i->first) != catSet.end()) - { - // Send activate cooldown timer (possible 0) at client side - WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8); - data << uint32(i->first); - data << uint64(GetGUID()); - SendDirectMessage(&data); - } - } - } - } -} - void Player::UpdatePotionCooldown(Spell* spell) { // no potion used i combat or still in combat @@ -22222,14 +21752,14 @@ void Player::UpdatePotionCooldown(Spell* spell) { // spell/item pair let set proper cooldown (except not existed charged spell cooldown spellmods for potions) if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(m_lastPotionId)) - for (uint8 idx = 0; idx < MAX_ITEM_SPELLS; ++idx) + for (uint8 idx = 0; idx < MAX_ITEM_PROTO_SPELLS; ++idx) if (proto->Spells[idx].SpellId && proto->Spells[idx].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE) if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Spells[idx].SpellId)) - SendCooldownEvent(spellInfo, m_lastPotionId); + GetSpellHistory()->SendCooldownEvent(spellInfo, m_lastPotionId); } // from spell cases (m_lastPotionId set in Spell::SendSpellCooldown) else - SendCooldownEvent(spell->m_spellInfo, m_lastPotionId, spell); + GetSpellHistory()->SendCooldownEvent(spell->m_spellInfo, m_lastPotionId, spell); m_lastPotionId = 0; } @@ -23139,14 +22669,13 @@ void Player::ApplyEquipCooldown(Item* pItem) continue; // Don't replace longer cooldowns by equip cooldown if we have any. - SpellCooldowns::iterator itr = m_spellCooldowns.find(spellData.SpellId); - if (itr != m_spellCooldowns.end() && itr->second.itemid == pItem->GetEntry() && itr->second.end > time(NULL) + 30) + if (GetSpellHistory()->GetRemainingCooldown(spellData.SpellId) > 30 * IN_MILLISECONDS) continue; - AddSpellCooldown(spellData.SpellId, pItem->GetEntry(), time(NULL) + 30); + GetSpellHistory()->AddCooldown(spellData.SpellId, pItem->GetEntry(), std::chrono::seconds(30)); - WorldPacket data(SMSG_ITEM_COOLDOWN, 12); - data << pItem->GetGUID(); + WorldPacket data(SMSG_ITEM_COOLDOWN, 8 + 4); + data << uint64(pItem->GetGUID()); data << uint32(spellData.SpellId); GetSession()->SendPacket(&data); } @@ -24017,7 +23546,7 @@ uint32 Player::GetResurrectionSpellId() } // Reincarnation (passive spell) // prio: 1 // Glyph of Renewed Life - if (prio < 1 && HasSpell(20608) && !HasSpellCooldown(21169) && (HasAura(58059) || HasItemCount(17030))) + if (prio < 1 && HasSpell(20608) && !GetSpellHistory()->HasCooldown(21169) && (HasAura(58059) || HasItemCount(17030))) spell_id = 21169; return spell_id; @@ -26072,14 +25601,6 @@ void Player::RemoveAtLoginFlag(AtLoginFlags flags, bool persist /*= false*/) } } -void Player::SendClearCooldown(uint32 spell_id, Unit* target) -{ - WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8); - data << uint32(spell_id); - data << uint64(target->GetGUID()); - SendDirectMessage(&data); -} - void Player::ResetMap() { // this may be called during Map::Update diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index e3a7f39b2ba..af640e4c73c 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -128,13 +128,6 @@ typedef std::unordered_map<uint32, PlayerTalent*> PlayerTalentMap; typedef std::unordered_map<uint32, PlayerSpell*> PlayerSpellMap; typedef std::list<SpellModifier*> SpellModList; -struct SpellCooldown -{ - time_t end; - uint16 itemid; -}; - -typedef std::map<uint32, SpellCooldown> SpellCooldowns; typedef std::unordered_map<uint32 /*instanceId*/, time_t/*releaseTime*/> InstanceTimeMap; enum TrainerSpellState @@ -1655,8 +1648,6 @@ class Player : public Unit, public GridObject<Player> PlayerSpellMap const& GetSpellMap() const { return m_spells; } PlayerSpellMap & GetSpellMap() { return m_spells; } - SpellCooldowns const& GetSpellCooldownMap() const { return m_spellCooldowns; } - void AddSpellMod(SpellModifier* mod, bool apply); bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = NULL); template <class T> T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell* spell = NULL); @@ -1666,26 +1657,7 @@ class Player : public Unit, public GridObject<Player> void DropModCharge(SpellModifier* mod, Spell* spell); void SetSpellModTakingSpell(Spell* spell, bool apply); - static uint32 const infinityCooldownDelay = MONTH; // used for set "infinity cooldowns" for spells and check - static uint32 const infinityCooldownDelayCheck = MONTH/2; - bool HasSpellCooldown(uint32 spell_id) const; - uint32 GetSpellCooldownDelay(uint32 spell_id) const; - void AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 itemId, Spell* spell = NULL, bool infinityCooldown = false); - void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time); - void ModifySpellCooldown(uint32 spellId, int32 cooldown); - void SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId = 0, Spell* spell = NULL, bool setCooldown = true); - void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) override; - void RemoveSpellCooldown(uint32 spell_id, bool update = false); - void RemoveSpellCategoryCooldown(uint32 cat, bool update = false); - void SendClearCooldown(uint32 spell_id, Unit* target); - - GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; } - - void RemoveCategoryCooldown(uint32 cat); void RemoveArenaSpellCooldowns(bool removeActivePetCooldowns = false); - void RemoveAllSpellCooldown(); - void _LoadSpellCooldowns(PreparedQueryResult result); - void _SaveSpellCooldowns(SQLTransaction& trans); uint32 GetLastPotionId() { return m_lastPotionId; } void SetLastPotionId(uint32 item_id) { m_lastPotionId = item_id; } void UpdatePotionCooldown(Spell* spell = NULL); @@ -1975,8 +1947,6 @@ class Player : public Unit, public GridObject<Player> //End of PvP System - inline SpellCooldowns GetSpellCooldowns() const { return m_spellCooldowns; } - void SetDrunkValue(uint8 newDrunkValue, uint32 itemId = 0); uint8 GetDrunkValue() const { return GetByteValue(PLAYER_BYTES_3, 1); } static DrunkenState GetDrunkenstateByValue(uint8 value); @@ -2493,8 +2463,6 @@ class Player : public Unit, public GridObject<Player> PlayerTalentMap* m_talents[MAX_TALENT_SPECS]; uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use - GlobalCooldownMgr m_GlobalCooldownMgr; - uint8 m_activeSpec; uint8 m_specsCount; @@ -2662,8 +2630,6 @@ class Player : public Unit, public GridObject<Player> AchievementMgr* m_achievementMgr; ReputationMgr* m_reputationMgr; - SpellCooldowns m_spellCooldowns; - uint32 m_ChampioningFaction; uint32 m_timeSyncCounter; diff --git a/src/server/game/Entities/Totem/Totem.cpp b/src/server/game/Entities/Totem/Totem.cpp index 39a078a907f..85ee51aebf5 100644 --- a/src/server/game/Entities/Totem/Totem.cpp +++ b/src/server/game/Entities/Totem/Totem.cpp @@ -20,6 +20,7 @@ #include "Group.h" #include "Opcodes.h" #include "Player.h" +#include "SpellHistory.h" #include "SpellMgr.h" #include "SpellInfo.h" #include "WorldPacket.h" @@ -128,7 +129,7 @@ void Totem::UnSummon(uint32 msTime) owner->SendAutoRepeatCancel(this); if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(GetUInt32Value(UNIT_CREATED_BY_SPELL))) - owner->SendCooldownEvent(spell, 0, NULL, false); + GetSpellHistory()->SendCooldownEvent(spell, 0, nullptr, false); if (Group* group = owner->GetGroup()) { diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index d2fc27728ac..85dccddf186 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -32,7 +32,7 @@ Transport::Transport() : GameObject(), _transportInfo(NULL), _isMoving(true), _pendingStop(false), _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), - _passengerTeleportItr(_passengers.begin()), _delayedAddModel(false) + _passengerTeleportItr(_passengers.begin()), _delayedAddModel(false), _delayedTeleport(false) { m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION; } @@ -173,13 +173,13 @@ void Transport::Update(uint32 diff) MoveToNextWaypoint(); - sScriptMgr->OnRelocate(this, _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z); + sScriptMgr->OnRelocate(this, _currentFrame->Node->NodeIndex, _currentFrame->Node->MapID, _currentFrame->Node->LocX, _currentFrame->Node->LocY, _currentFrame->Node->LocZ); - TC_LOG_DEBUG("entities.transport", "Transport %u (%s) moved to node %u %u %f %f %f", GetEntry(), GetName().c_str(), _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z); + TC_LOG_DEBUG("entities.transport", "Transport %u (%s) moved to node %u %u %f %f %f", GetEntry(), GetName().c_str(), _currentFrame->Node->NodeIndex, _currentFrame->Node->MapID, _currentFrame->Node->LocX, _currentFrame->Node->LocY, _currentFrame->Node->LocZ); // Departure event if (_currentFrame->IsTeleportFrame()) - if (TeleportTransport(_nextFrame->Node->mapid, _nextFrame->Node->x, _nextFrame->Node->y, _nextFrame->Node->z, _nextFrame->InitialOrientation)) + if (TeleportTransport(_nextFrame->Node->MapID, _nextFrame->Node->LocX, _nextFrame->Node->LocY, _nextFrame->Node->LocZ, _nextFrame->InitialOrientation)) return; // Update more in new map thread } @@ -226,6 +226,14 @@ void Transport::Update(uint32 diff) sScriptMgr->OnTransportUpdate(this, diff); } +void Transport::DelayedUpdate(uint32 diff) +{ + if (GetKeyFrames().size() <= 1) + return; + + DelayedTeleportTransport(); +} + void Transport::AddPassenger(WorldObject* passenger) { if (!IsInWorld()) @@ -591,36 +599,8 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl if (oldMap->GetId() != newMapid) { - Map* newMap = sMapMgr->CreateBaseMap(newMapid); + _delayedTeleport = true; UnloadStaticPassengers(); - GetMap()->RemoveFromMap<Transport>(this, false); - SetMap(newMap); - - for (_passengerTeleportItr = _passengers.begin(); _passengerTeleportItr != _passengers.end();) - { - WorldObject* obj = (*_passengerTeleportItr++); - - float destX, destY, destZ, destO; - obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO); - TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, o); - - switch (obj->GetTypeId()) - { - case TYPEID_PLAYER: - if (!obj->ToPlayer()->TeleportTo(newMapid, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT)) - RemovePassenger(obj); - break; - case TYPEID_DYNAMICOBJECT: - obj->AddObjectToRemoveList(); - break; - default: - RemovePassenger(obj); - break; - } - } - - Relocate(x, y, z, o); - GetMap()->AddToMap<Transport>(this); return true; } else @@ -643,6 +623,48 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl } } +void Transport::DelayedTeleportTransport() +{ + if (!_delayedTeleport) + return; + + _delayedTeleport = false; + Map* newMap = sMapMgr->CreateBaseMap(_nextFrame->Node->MapID); + GetMap()->RemoveFromMap<Transport>(this, false); + SetMap(newMap); + + float x = _nextFrame->Node->LocX, + y = _nextFrame->Node->LocY, + z = _nextFrame->Node->LocZ, + o =_nextFrame->InitialOrientation; + + for (_passengerTeleportItr = _passengers.begin(); _passengerTeleportItr != _passengers.end();) + { + WorldObject* obj = (*_passengerTeleportItr++); + + float destX, destY, destZ, destO; + obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO); + TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, o); + + switch (obj->GetTypeId()) + { + case TYPEID_PLAYER: + if (!obj->ToPlayer()->TeleportTo(_nextFrame->Node->MapID, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT)) + RemovePassenger(obj); + break; + case TYPEID_DYNAMICOBJECT: + obj->AddObjectToRemoveList(); + break; + default: + RemovePassenger(obj); + break; + } + } + + Relocate(x, y, z, o); + GetMap()->AddToMap<Transport>(this); +} + void Transport::UpdatePassengerPositions(PassengerSet& passengers) { for (PassengerSet::iterator itr = passengers.begin(); itr != passengers.end(); ++itr) @@ -697,9 +719,9 @@ void Transport::UpdatePassengerPositions(PassengerSet& passengers) void Transport::DoEventIfAny(KeyFrame const& node, bool departure) { - if (uint32 eventid = departure ? node.Node->departureEventID : node.Node->arrivalEventID) + if (uint32 eventid = departure ? node.Node->DepartureEventID : node.Node->ArrivalEventID) { - TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of %s path", departure ? "departure" : "arrival", eventid, node.Node->index, GetName().c_str()); + TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of %s path", departure ? "departure" : "arrival", eventid, node.Node->NodeIndex, GetName().c_str()); GetMap()->ScriptsStart(sEventScripts, eventid, this, this); EventInform(eventid); } diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h index 90c1828253e..c56ceb1696d 100644 --- a/src/server/game/Entities/Transport/Transport.h +++ b/src/server/game/Entities/Transport/Transport.h @@ -39,6 +39,7 @@ class Transport : public GameObject, public TransportBase void CleanupsBeforeDelete(bool finalCleanup = true) override; void Update(uint32 diff) override; + void DelayedUpdate(uint32 diff); void BuildUpdate(UpdateDataMapType& data_map) override; @@ -103,6 +104,7 @@ class Transport : public GameObject, public TransportBase void MoveToNextWaypoint(); float CalculateSegmentPos(float perc); bool TeleportTransport(uint32 newMapid, float x, float y, float z, float o); + void DelayedTeleportTransport(); void UpdatePassengerPositions(PassengerSet& passengers); void DoEventIfAny(KeyFrame const& node, bool departure); @@ -127,6 +129,7 @@ class Transport : public GameObject, public TransportBase PassengerSet _staticPassengers; bool _delayedAddModel; + bool _delayedTeleport; }; #endif diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 9d7cdb895b2..219ee8b1002 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -51,6 +51,7 @@ #include "SpellAuras.h" #include "Spell.h" #include "SpellInfo.h" +#include "SpellHistory.h" #include "SpellMgr.h" #include "TemporarySummon.h" #include "Totem.h" @@ -163,7 +164,7 @@ Unit::Unit(bool isWorldObject) : i_AI(NULL), i_disabledAI(NULL), m_AutoRepeatFirstCast(false), m_procDeep(0), m_removedAurasCount(0), i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_ThreatManager(this), m_vehicle(NULL), m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), - m_HostileRefManager(this), _lastDamagedTime(0) + m_HostileRefManager(this), _lastDamagedTime(0), m_spellHistory(new SpellHistory(this)) { m_objectType |= TYPEMASK_UNIT; m_objectTypeId = TYPEID_UNIT; @@ -257,24 +258,6 @@ Unit::Unit(bool isWorldObject) : } //////////////////////////////////////////////////////////// -// Methods of class GlobalCooldownMgr -bool GlobalCooldownMgr::HasGlobalCooldown(SpellInfo const* spellInfo) const -{ - GlobalCooldownList::const_iterator itr = m_GlobalCooldowns.find(spellInfo->StartRecoveryCategory); - return itr != m_GlobalCooldowns.end() && itr->second.duration && getMSTimeDiff(itr->second.cast_time, getMSTime()) < itr->second.duration; -} - -void GlobalCooldownMgr::AddGlobalCooldown(SpellInfo const* spellInfo, uint32 gcd) -{ - m_GlobalCooldowns[spellInfo->StartRecoveryCategory] = GlobalCooldown(gcd, getMSTime()); -} - -void GlobalCooldownMgr::CancelGlobalCooldown(SpellInfo const* spellInfo) -{ - m_GlobalCooldowns[spellInfo->StartRecoveryCategory].duration = 0; -} - -//////////////////////////////////////////////////////////// // Methods of class Unit Unit::~Unit() { @@ -291,6 +274,7 @@ Unit::~Unit() delete i_motionMaster; delete m_charmInfo; delete movespline; + delete m_spellHistory; ASSERT(!m_duringRemoveFromWorld); ASSERT(!m_attacking); @@ -406,7 +390,7 @@ void Unit::UpdateSplinePosition() pos.m_positionX = loc.x; pos.m_positionY = loc.y; pos.m_positionZ = loc.z; - pos.m_orientation = loc.orientation; + pos.SetOrientation(loc.orientation); if (TransportBase* transport = GetDirectTransport()) transport->CalculatePassengerPosition(loc.x, loc.y, loc.z, &loc.orientation); @@ -2925,6 +2909,8 @@ void Unit::_UpdateSpells(uint32 time) ++itr; } } + + m_spellHistory->Update(); } void Unit::_UpdateAutoRepeatSpell() @@ -4860,13 +4846,13 @@ void Unit::AddGameObject(GameObject* gameObj) m_gameObj.push_back(gameObj); gameObj->SetOwnerGUID(GetGUID()); - if (GetTypeId() == TYPEID_PLAYER && gameObj->GetSpellId()) + if (gameObj->GetSpellId()) { SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(gameObj->GetSpellId()); // Need disable spell use for owner if (createBySpell && createBySpell->IsCooldownStartedOnEvent()) // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases) - ToPlayer()->AddSpellAndCategoryCooldowns(createBySpell, 0, NULL, true); + GetSpellHistory()->StartCooldown(createBySpell, 0, nullptr, true); } } @@ -4891,14 +4877,11 @@ void Unit::RemoveGameObject(GameObject* gameObj, bool del) { RemoveAurasDueToSpell(spellid); - if (GetTypeId() == TYPEID_PLAYER) - { - SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid); - // Need activate spell use for owner - if (createBySpell && createBySpell->IsCooldownStartedOnEvent()) - // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases) - ToPlayer()->SendCooldownEvent(createBySpell); - } + SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid); + // Need activate spell use for owner + if (createBySpell && createBySpell->IsCooldownStartedOnEvent()) + // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases) + GetSpellHistory()->SendCooldownEvent(createBySpell); } m_gameObj.remove(gameObj); @@ -5488,8 +5471,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster); for (std::vector<uint32>::iterator itr = RandomSpells.begin(); itr != RandomSpells.end(); ++itr) { - if (!ToPlayer()->HasSpellCooldown(*itr)) - ToPlayer()->AddSpellCooldown(*itr, 0, time(NULL) + cooldown); + if (!GetSpellHistory()->HasCooldown(*itr)) + GetSpellHistory()->AddCooldown(*itr, 0, std::chrono::seconds(cooldown)); } break; } @@ -5534,8 +5517,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster); for (std::vector<uint32>::iterator itr = RandomSpells.begin(); itr != RandomSpells.end(); ++itr) { - if (!ToPlayer()->HasSpellCooldown(*itr)) - ToPlayer()->AddSpellCooldown(*itr, 0, time(NULL) + cooldown); + if (!GetSpellHistory()->HasCooldown(*itr)) + GetSpellHistory()->AddCooldown(*itr, 0, std::chrono::seconds(cooldown)); } break; } @@ -5639,20 +5622,17 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // Glyph of Ice Block case 56372: { - Player* player = ToPlayer(); - if (!player) + if (GetTypeId() != TYPEID_PLAYER) return false; - SpellCooldowns const cooldowns = player->GetSpellCooldowns(); - // remove cooldowns on all ranks of Frost Nova - for (SpellCooldowns::const_iterator itr = cooldowns.begin(); itr != cooldowns.end(); ++itr) + GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool { SpellInfo const* cdSpell = sSpellMgr->GetSpellInfo(itr->first); - // Frost Nova - if (cdSpell && cdSpell->SpellFamilyName == SPELLFAMILY_MAGE - && cdSpell->SpellFamilyFlags[0] & 0x00000040) - player->RemoveSpellCooldown(cdSpell->Id, true); - } + if (!cdSpell || cdSpell->SpellFamilyName != SPELLFAMILY_MAGE + || !(cdSpell->SpellFamilyFlags[0] & 0x00000040)) + return false; + return true; + }, true); break; } case 47020: // Enter vehicle XT-002 (Scrapbot) @@ -6061,7 +6041,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere int32 basepoints1 = CalculatePct(GetMaxPower(Powers(POWER_MANA)), triggerAmount * 2); // Improved Leader of the Pack // Check cooldown of heal spell cooldown - if (GetTypeId() == TYPEID_PLAYER && !ToPlayer()->HasSpellCooldown(34299)) + if (!GetSpellHistory()->HasCooldown(34299)) CastCustomSpell(this, 68285, &basepoints1, 0, 0, true, 0, triggeredByAura); break; } @@ -6732,7 +6712,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere return false; // custom cooldown processing case - if (cooldown && player->HasSpellCooldown(dummySpell->Id)) + if (cooldown && GetSpellHistory()->HasCooldown(dummySpell->Id)) return false; if (triggeredByAura->GetBase() && castItem->GetGUID() != triggeredByAura->GetBase()->GetCastItemGUID()) @@ -6798,7 +6778,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // apply cooldown before cast to prevent processing itself if (cooldown) - player->AddSpellCooldown(dummySpell->Id, 0, time(NULL) + cooldown); + player->GetSpellHistory()->AddCooldown(dummySpell->Id, 0, std::chrono::seconds(cooldown)); // Attack Twice for (uint32 i = 0; i < 2; ++i) @@ -7040,7 +7020,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere return false; // custom cooldown processing case - if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(dummySpell->Id)) + if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(dummySpell->Id)) return false; uint32 spellId = 0; @@ -7087,13 +7067,13 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere return false; // Remove cooldown (Chain Lightning - has Category Recovery time) - ToPlayer()->RemoveSpellCooldown(spellId); + GetSpellHistory()->ResetCooldown(spellId); } CastSpell(victim, spellId, true, castItem, triggeredByAura); if (cooldown && GetTypeId() == TYPEID_PLAYER) - ToPlayer()->AddSpellCooldown(dummySpell->Id, 0, time(NULL) + cooldown); + GetSpellHistory()->AddCooldown(dummySpell->Id, 0, std::chrono::seconds(cooldown)); return true; } @@ -7106,8 +7086,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere uint32 spell = sSpellMgr->GetSpellWithRank(26364, aurEff->GetSpellInfo()->GetRank()); // custom cooldown processing case - if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(spell)) - ToPlayer()->RemoveSpellCooldown(spell); + if (GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(spell)) + GetSpellHistory()->ResetCooldown(spell); CastSpell(target, spell, true, castItem, triggeredByAura); aurEff->GetBase()->DropCharge(); @@ -7399,7 +7379,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere if (cooldown_spell_id == 0) cooldown_spell_id = triggered_spell_id; - if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(cooldown_spell_id)) + if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(cooldown_spell_id)) return false; if (basepoints0) @@ -7408,7 +7388,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura, originalCaster); if (cooldown && GetTypeId() == TYPEID_PLAYER) - ToPlayer()->AddSpellCooldown(cooldown_spell_id, 0, time(NULL) + cooldown); + GetSpellHistory()->AddCooldown(cooldown_spell_id, 0, std::chrono::seconds(cooldown)); return true; } @@ -7629,9 +7609,9 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp *handled = true; if (cooldown && GetTypeId() == TYPEID_PLAYER) { - if (ToPlayer()->HasSpellCooldown(100000)) + if (GetSpellHistory()->HasCooldown(100000)) return false; - ToPlayer()->AddSpellCooldown(100000, 0, time(NULL) + cooldown); + GetSpellHistory()->AddCooldown(100000, 0, std::chrono::seconds(cooldown)); } return true; } @@ -8300,7 +8280,11 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg return false; // Howling Blast - ToPlayer()->RemoveSpellCategoryCooldown(1248, true); + GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first); + return spellInfo && spellInfo->GetCategory() == 1248; + }, true); } // Custom basepoints/target for exist spell @@ -8319,13 +8303,13 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg if (!target) return false; - if (cooldown && target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->HasSpellCooldown(trigger_spell_id)) + if (cooldown && target->GetTypeId() == TYPEID_PLAYER && target->GetSpellHistory()->HasCooldown(trigger_spell_id)) return false; target->CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura); if (cooldown && GetTypeId() == TYPEID_PLAYER) - ToPlayer()->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown); + GetSpellHistory()->AddCooldown(trigger_spell_id, 0, std::chrono::seconds(cooldown)); return true; } // Cast positive spell on enemy target @@ -8408,8 +8392,11 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg case 50227: { // Remove cooldown on Shield Slam - if (GetTypeId() == TYPEID_PLAYER) - ToPlayer()->RemoveSpellCategoryCooldown(1209, true); + GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first); + return spellInfo && spellInfo->GetCategory() == 1209; + }, true); break; } // Maelstrom Weapon @@ -8469,8 +8456,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg case 58628: { // remove cooldown of Death Grip - if (GetTypeId() == TYPEID_PLAYER) - ToPlayer()->RemoveSpellCooldown(49576, true); + GetSpellHistory()->ResetCooldown(49576, true); return true; } // Savage Defense @@ -8501,7 +8487,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg } } - if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(trigger_spell_id)) + if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(trigger_spell_id)) return false; // extra attack should hit same target @@ -8518,7 +8504,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura); if (cooldown && GetTypeId() == TYPEID_PLAYER) - ToPlayer()->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown); + GetSpellHistory()->AddCooldown(trigger_spell_id, 0, std::chrono::seconds(cooldown)); return true; } @@ -8614,13 +8600,13 @@ bool Unit::HandleOverrideClassScriptAuraProc(Unit* victim, uint32 /*damage*/, Au return false; } - if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id)) + if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(triggered_spell_id)) return false; CastSpell(victim, triggered_spell_id, true, castItem, triggeredByAura); if (cooldown && GetTypeId() == TYPEID_PLAYER) - ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown); + GetSpellHistory()->AddCooldown(triggered_spell_id, 0, std::chrono::seconds(cooldown)); return true; } @@ -9355,14 +9341,11 @@ void Unit::SetMinion(Minion *minion, bool apply) if (minion->IsPetGhoul()) minion->setPowerType(POWER_ENERGY); - if (GetTypeId() == TYPEID_PLAYER) - { - // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL)); + // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL)); - if (spellInfo && (spellInfo->IsCooldownStartedOnEvent())) - ToPlayer()->AddSpellAndCategoryCooldowns(spellInfo, 0, NULL, true); - } + if (spellInfo && (spellInfo->IsCooldownStartedOnEvent())) + GetSpellHistory()->StartCooldown(spellInfo, 0, nullptr, true); } else { @@ -9396,13 +9379,10 @@ void Unit::SetMinion(Minion *minion, bool apply) } } - if (GetTypeId() == TYPEID_PLAYER) - { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL)); - // Remove infinity cooldown - if (spellInfo && (spellInfo->IsCooldownStartedOnEvent())) - ToPlayer()->SendCooldownEvent(spellInfo); - } + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL)); + // Remove infinity cooldown + if (spellInfo && (spellInfo->IsCooldownStartedOnEvent())) + GetSpellHistory()->SendCooldownEvent(spellInfo); //if (minion->HasUnitTypeMask(UNIT_MASK_GUARDIAN)) { @@ -15532,18 +15512,11 @@ void Unit::SetControlled(bool apply, UnitState state) { case UNIT_STATE_STUNNED: SetStunned(true); - // i need to stop fear on stun and root or i will get teleport to destination issue as MVMGEN for fear keeps going on - if (HasUnitState(UNIT_STATE_FLEEING)) - SetFeared(false); CastStop(); break; case UNIT_STATE_ROOT: if (!HasUnitState(UNIT_STATE_STUNNED)) - { SetRooted(true); - if (HasUnitState(UNIT_STATE_FLEEING)) - SetFeared(false); - } break; case UNIT_STATE_CONFUSED: if (!HasUnitState(UNIT_STATE_STUNNED)) @@ -15631,11 +15604,9 @@ void Unit::SetStunned(bool apply) // setting MOVEMENTFLAG_ROOT RemoveUnitMovementFlag(MOVEMENTFLAG_MASK_MOVING); AddUnitMovementFlag(MOVEMENTFLAG_ROOT); + StopMoving(); - // Creature specific - if (GetTypeId() != TYPEID_PLAYER) - StopMoving(); - else + if (GetTypeId() == TYPEID_PLAYER) SetStandState(UNIT_STAND_STATE_STAND); WorldPacket data(SMSG_FORCE_MOVE_ROOT, 8); @@ -15679,6 +15650,7 @@ void Unit::SetRooted(bool apply) // setting MOVEMENTFLAG_ROOT RemoveUnitMovementFlag(MOVEMENTFLAG_MASK_MOVING); AddUnitMovementFlag(MOVEMENTFLAG_ROOT); + StopMoving(); if (GetTypeId() == TYPEID_PLAYER) { @@ -15692,7 +15664,6 @@ void Unit::SetRooted(bool apply) WorldPacket data(SMSG_SPLINE_MOVE_ROOT, 8); data << GetPackGUID(); SendMessageToSet(&data, true); - StopMoving(); } } else @@ -17787,27 +17758,6 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) data->append(fieldBuffer); } -void Unit::BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown) -{ - data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + 4 + 4); - data << uint64(GetGUID()); - data << uint8(flags); - data << uint32(spellId); - data << uint32(cooldown); -} - -void Unit::BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns) -{ - data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + (4 + 4) * cooldowns.size()); - data << uint64(GetGUID()); - data << uint8(flags); - for (std::unordered_map<uint32, uint32>::const_iterator itr = cooldowns.begin(); itr != cooldowns.end(); ++itr) - { - data << uint32(itr->first); - data << uint32(itr->second); - } -} - int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const { int32 val = 0; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index ddf43f30971..088a0bbdf73 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -339,6 +339,7 @@ class AuraEffect; class Creature; class Spell; class SpellInfo; +class SpellHistory; class DynamicObject; class GameObject; class Item; @@ -1031,30 +1032,6 @@ enum CurrentSpellTypes #define CURRENT_FIRST_NON_MELEE_SPELL 1 #define CURRENT_MAX_SPELL 4 -struct GlobalCooldown -{ - explicit GlobalCooldown(uint32 _dur = 0, uint32 _time = 0) : duration(_dur), cast_time(_time) { } - - uint32 duration; - uint32 cast_time; -}; - -typedef std::unordered_map<uint32 /*category*/, GlobalCooldown> GlobalCooldownList; - -class GlobalCooldownMgr // Shared by Player and CharmInfo -{ -public: - GlobalCooldownMgr() { } - -public: - bool HasGlobalCooldown(SpellInfo const* spellInfo) const; - void AddGlobalCooldown(SpellInfo const* spellInfo, uint32 gcd); - void CancelGlobalCooldown(SpellInfo const* spellInfo); - -private: - GlobalCooldownList m_GlobalCooldowns; -}; - enum ActiveStates { ACT_PASSIVE = 0x01, // 0x01 - passive @@ -1171,8 +1148,6 @@ struct CharmInfo CharmSpellInfo* GetCharmSpell(uint8 index) { return &(_charmspells[index]); } - GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; } - void SetIsCommandAttack(bool val); bool IsCommandAttack(); void SetIsCommandFollow(bool val); @@ -1205,8 +1180,6 @@ struct CharmInfo float _stayX; float _stayY; float _stayZ; - - GlobalCooldownMgr m_GlobalCooldownMgr; }; // for clearing special attacks @@ -1237,16 +1210,6 @@ enum PlayerTotemType SUMMON_TYPE_TOTEM_AIR = 83 }; -/// Spell cooldown flags sent in SMSG_SPELL_COOLDOWN -enum SpellCooldownFlags -{ - SPELL_COOLDOWN_FLAG_NONE = 0x0, - SPELL_COOLDOWN_FLAG_INCLUDE_GCD = 0x1, ///< Starts GCD in addition to normal cooldown specified in the packet - SPELL_COOLDOWN_FLAG_INCLUDE_EVENT_COOLDOWNS = 0x2 ///< Starts GCD for spells that should start their cooldown on events, requires SPELL_COOLDOWN_FLAG_INCLUDE_GCD set -}; - -typedef std::unordered_map<uint32, uint32> PacketCooldowns; - // delay time next attack to prevent client attack animation problems #define ATTACK_DISPLAY_DELAY 200 #define MAX_PLAYER_STEALTH_DETECT_RANGE 30.0f // max distance for detection targets by player @@ -1585,8 +1548,6 @@ class Unit : public WorldObject void SetAuraStack(uint32 spellId, Unit* target, uint32 stack); void SendPlaySpellVisual(uint32 id); void SendPlaySpellImpact(ObjectGuid guid, uint32 id); - void BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown); - void BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns); void DeMorph(); @@ -1845,7 +1806,6 @@ class Unit : public WorldObject void SetChannelObjectGuid(ObjectGuid guid) { SetGuidValue(UNIT_FIELD_CHANNEL_OBJECT, guid); } void SetCurrentCastSpell(Spell* pSpell); - virtual void ProhibitSpellSchool(SpellSchoolMask /*idSchoolMask*/, uint32 /*unTimeMs*/) { } void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed = true, bool withInstant = true); void FinishSpell(CurrentSpellTypes spellType, bool ok = true); @@ -1863,6 +1823,9 @@ class Unit : public WorldObject Spell* FindCurrentSpellBySpellId(uint32 spell_id) const; int32 GetCurrentSpellCastTime(uint32 spell_id) const; + SpellHistory* GetSpellHistory() { return m_spellHistory; } + SpellHistory const* GetSpellHistory() const { return m_spellHistory; } + ObjectGuid m_SummonSlot[MAX_SUMMON_SLOT]; ObjectGuid m_ObjectSlot[MAX_GAMEOBJECT_SLOT]; @@ -2293,6 +2256,8 @@ class Unit : public WorldObject bool _isWalkingBeforeCharm; ///< Are we walking before we were charmed? time_t _lastDamagedTime; // Part of Evade mechanics + + SpellHistory* m_spellHistory; }; namespace Trinity diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 59e4e871970..a3414c72613 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -1039,6 +1039,66 @@ void ObjectMgr::LoadCreatureAddons() TC_LOG_INFO("server.loading", ">> Loaded %u creature addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } +void ObjectMgr::LoadGameObjectAddons() +{ + uint32 oldMSTime = getMSTime(); + + // 0 1 2 + QueryResult result = WorldDatabase.Query("SELECT guid, invisibilityType, invisibilityValue FROM gameobject_addon"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 gameobject addon definitions. DB table `gameobject_addon` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + ObjectGuid::LowType guid = fields[0].GetUInt64(); + + const GameObjectData* goData = GetGOData(guid); + if (!goData) + { + TC_LOG_ERROR("sql.sql", "GameObject (GUID: " UI64FMTD ") does not exist but has a record in `gameobject_addon`", guid); + continue; + } + + GameObjectAddon& gameObjectAddon = _gameObjectAddonStore[guid]; + gameObjectAddon.invisibilityType = InvisibilityType(fields[1].GetUInt8()); + gameObjectAddon.InvisibilityValue = fields[2].GetUInt32(); + + if (gameObjectAddon.invisibilityType >= TOTAL_INVISIBILITY_TYPES) + { + TC_LOG_ERROR("sql.sql", "GameObject (GUID: " UI64FMTD ") has invalid InvisibilityType in `gameobject_addon`", guid); + gameObjectAddon.invisibilityType = INVISIBILITY_GENERAL; + gameObjectAddon.InvisibilityValue = 0; + } + + if (gameObjectAddon.invisibilityType && !gameObjectAddon.InvisibilityValue) + { + TC_LOG_ERROR("sql.sql", "GameObject (GUID: " UI64FMTD ") has InvisibilityType set but has no InvisibilityValue in `gameobject_addon`, set to 1", guid); + gameObjectAddon.InvisibilityValue = 1; + } + + ++count; + } + while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u gameobject addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + +GameObjectAddon const* ObjectMgr::GetGameObjectAddon(ObjectGuid::LowType lowguid) +{ + GameObjectAddonContainer::const_iterator itr = _gameObjectAddonStore.find(lowguid); + if (itr != _gameObjectAddonStore.end()) + return &(itr->second); + + return NULL; +} + CreatureAddon const* ObjectMgr::GetCreatureAddon(uint32 lowguid) { CreatureAddonContainer::const_iterator itr = _creatureAddonStore.find(lowguid); @@ -4941,11 +5001,11 @@ void ObjectMgr::LoadEventScripts() { TaxiPathNodeEntry const& node = sTaxiPathNodesByPath[path_idx][node_idx]; - if (node.arrivalEventID) - evt_scripts.insert(node.arrivalEventID); + if (node.ArrivalEventID) + evt_scripts.insert(node.ArrivalEventID); - if (node.departureEventID) - evt_scripts.insert(node.departureEventID); + if (node.DepartureEventID) + evt_scripts.insert(node.DepartureEventID); } } diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index f9562a12335..f18e39077f3 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -49,12 +49,7 @@ struct PlayerClassLevelInfo; struct PlayerInfo; struct PlayerLevelInfo; -// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform -#if defined(__GNUC__) -#pragma pack(1) -#else #pragma pack(push, 1) -#endif struct PageText { @@ -82,12 +77,7 @@ private: uint8 _summonGroup; ///< Summon's group id }; -// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform -#if defined(__GNUC__) -#pragma pack() -#else #pragma pack(pop) -#endif // DB scripting commands enum ScriptCommands @@ -732,6 +722,7 @@ class ObjectMgr static void ChooseCreatureFlags(CreatureTemplate const* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, CreatureData const* data = NULL); EquipmentInfo const* GetEquipmentInfo(uint32 entry, int8& id); CreatureAddon const* GetCreatureAddon(uint32 lowguid); + GameObjectAddon const* GetGameObjectAddon(ObjectGuid::LowType lowguid); CreatureAddon const* GetCreatureTemplateAddon(uint32 entry); ItemTemplate const* GetItemTemplate(uint32 entry); ItemTemplateContainer const* GetItemTemplateStore() const { return &_itemTemplateStore; } @@ -974,6 +965,7 @@ class ObjectMgr void LoadLinkedRespawn(); bool SetCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid); void LoadCreatureAddons(); + void LoadGameObjectAddons(); void LoadCreatureModelInfo(); void LoadEquipmentTemplates(); void LoadGameObjectLocales(); @@ -1419,6 +1411,7 @@ class ObjectMgr CreatureModelContainer _creatureModelStore; CreatureAddonContainer _creatureAddonStore; CreatureAddonContainer _creatureTemplateAddonStore; + GameObjectAddonContainer _gameObjectAddonStore; EquipmentInfoContainer _equipmentInfoStore; LinkedRespawnContainer _linkedRespawnStore; CreatureLocaleContainer _creatureLocaleStore; diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 9ff2041ee92..0bf33eee234 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -30,6 +30,7 @@ #include "Pet.h" #include "World.h" #include "Group.h" +#include "SpellHistory.h" #include "SpellInfo.h" #include "Player.h" @@ -344,8 +345,6 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe if (result == SPELL_CAST_OK) { - pet->ToCreature()->AddCreatureSpellCooldown(spellid); - unit_target = spell->m_targets.GetUnitTarget(); //10% chance to play special pet attack talk, else growl @@ -379,8 +378,8 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe else spell->SendPetCastResult(result); - if (!pet->ToCreature()->HasSpellCooldown(spellid)) - GetPlayer()->SendClearCooldown(spellid, pet); + if (!pet->GetSpellHistory()->HasCooldown(spellid)) + pet->GetSpellHistory()->ResetCooldown(spellid, true); spell->finish(false); delete spell; @@ -794,7 +793,6 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) { if (Creature* creature = caster->ToCreature()) { - creature->AddCreatureSpellCooldown(spellId); if (Pet* pet = creature->ToPet()) { // 10% chance to play special pet attack talk, else growl @@ -812,16 +810,8 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) { spell->SendPetCastResult(result); - if (caster->GetTypeId() == TYPEID_PLAYER) - { - if (!caster->ToPlayer()->HasSpellCooldown(spellId)) - GetPlayer()->SendClearCooldown(spellId, caster); - } - else - { - if (!caster->ToCreature()->HasSpellCooldown(spellId)) - GetPlayer()->SendClearCooldown(spellId, caster); - } + if (!caster->GetSpellHistory()->HasCooldown(spellId)) + caster->GetSpellHistory()->ResetCooldown(spellId, true); spell->finish(false); delete spell; diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 5f641bf713f..a6108b36c13 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -491,8 +491,6 @@ void WorldSession::HandlePetCancelAuraOpcode(WorldPacket& recvPacket) } pet->RemoveOwnedAura(spellId, ObjectGuid::Empty, 0, AURA_REMOVE_BY_CANCEL); - - pet->AddCreatureSpellCooldown(spellId); } void WorldSession::HandleCancelGrowthAuraOpcode(WorldPacket& /*recvPacket*/) { } diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp index a9dc7f26b8e..af0f5b0fc75 100644 --- a/src/server/game/Handlers/TaxiHandler.cpp +++ b/src/server/game/Handlers/TaxiHandler.cpp @@ -237,7 +237,7 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData) TaxiPathNodeEntry const& node = flight->GetPath()[flight->GetCurrentNode()]; flight->SkipCurrentNode(); - GetPlayer()->TeleportTo(curDestNode->map_id, node.x, node.y, node.z, GetPlayer()->GetOrientation()); + GetPlayer()->TeleportTo(curDestNode->map_id, node.LocX, node.LocY, node.LocZ, GetPlayer()->GetOrientation()); } return; } diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 42bf61b6e38..da806e5b038 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -426,7 +426,26 @@ void InstanceScript::DoUseDoorOrButton(ObjectGuid guid, uint32 withRestoreTime / TC_LOG_ERROR("scripts", "InstanceScript: DoUseDoorOrButton can't use gameobject entry %u, because type is %u.", go->GetEntry(), go->GetGoType()); } else - TC_LOG_DEBUG("scripts", "InstanceScript: HandleGameObject failed"); + TC_LOG_DEBUG("scripts", "InstanceScript: DoUseDoorOrButton failed"); +} + +void InstanceScript::DoCloseDoorOrButton(ObjectGuid guid) +{ + if (!guid) + return; + + if (GameObject* go = instance->GetGameObject(guid)) + { + if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR || go->GetGoType() == GAMEOBJECT_TYPE_BUTTON) + { + if (go->getLootState() == GO_ACTIVATED) + go->ResetDoorOrButton(); + } + else + TC_LOG_ERROR("scripts", "InstanceScript: DoCloseDoorOrButton can't use gameobject entry %u, because type is %u.", go->GetEntry(), go->GetGoType()); + } + else + TC_LOG_DEBUG("scripts", "InstanceScript: DoCloseDoorOrButton failed"); } void InstanceScript::DoRespawnGameObject(ObjectGuid guid, uint32 timeToDespawn /*= MINUTE*/) diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index 41a9e9d0be1..be05a9f4495 100644 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -191,6 +191,7 @@ class InstanceScript : public ZoneScript // Change active state of doors or buttons void DoUseDoorOrButton(ObjectGuid guid, uint32 withRestoreTime = 0, bool useAlternativeState = false); + void DoCloseDoorOrButton(ObjectGuid guid); // Respawns a GO having negative spawntimesecs in gameobject-table void DoRespawnGameObject(ObjectGuid guid, uint32 timeToDespawn = MINUTE); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index dad24de7288..c1a462497cd 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2562,6 +2562,17 @@ inline void Map::setNGrid(NGridType *grid, uint32 x, uint32 y) void Map::DelayedUpdate(const uint32 t_diff) { + for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();) + { + Transport* transport = *_transportsUpdateIter; + ++_transportsUpdateIter; + + if (!transport->IsInWorld()) + continue; + + transport->DelayedUpdate(t_diff); + } + RemoveAllObjectsInRemoveList(); // Don't unload grids if it's battleground, since we may have manually added GOs, creatures, those doesn't load from DB at grid re-load ! diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 3bbd6068e4e..43fcbaba31c 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -210,12 +210,7 @@ public: ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0); }; -// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform -#if defined(__GNUC__) -#pragma pack(1) -#else #pragma pack(push, 1) -#endif struct InstanceTemplate { @@ -241,11 +236,7 @@ struct ZoneDynamicInfo uint32 LightFadeInTime; }; -#if defined(__GNUC__) -#pragma pack() -#else #pragma pack(pop) -#endif #define MAX_HEIGHT 100000.0f // can be use for find ground height at surface #define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp index b2e30473632..dadc2eeeac3 100644 --- a/src/server/game/Maps/TransportMgr.cpp +++ b/src/server/game/Maps/TransportMgr.cpp @@ -112,7 +112,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl Movement::PointsArray splinePath, allPoints; bool mapChange = false; for (size_t i = 0; i < path.size(); ++i) - allPoints.push_back(G3D::Vector3(path[i].x, path[i].y, path[i].z)); + allPoints.push_back(G3D::Vector3(path[i].LocX, path[i].LocY, path[i].LocZ)); // Add extra points to allow derivative calculations for all path nodes allPoints.insert(allPoints.begin(), allPoints.front().lerp(allPoints[1], -0.2f)); @@ -129,7 +129,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl if (!mapChange) { TaxiPathNodeEntry const& node_i = path[i]; - if (i != path.size() - 1 && (node_i.actionFlag & 1 || node_i.mapid != path[i + 1].mapid)) + if (i != path.size() - 1 && (node_i.Flags & 1 || node_i.MapID != path[i + 1].MapID)) { keyFrames.back().Teleport = true; mapChange = true; @@ -142,8 +142,8 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl k.InitialOrientation = Position::NormalizeOrientation(std::atan2(h.y, h.x) + float(M_PI)); keyFrames.push_back(k); - splinePath.push_back(G3D::Vector3(node_i.x, node_i.y, node_i.z)); - transport->mapsUsed.insert(k.Node->mapid); + splinePath.push_back(G3D::Vector3(node_i.LocX, node_i.LocY, node_i.LocZ)); + transport->mapsUsed.insert(k.Node->MapID); } } else @@ -153,12 +153,12 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl if (splinePath.size() >= 2) { // Remove special catmull-rom spline points - if (!keyFrames.front().IsStopFrame() && !keyFrames.front().Node->arrivalEventID && !keyFrames.front().Node->departureEventID) + if (!keyFrames.front().IsStopFrame() && !keyFrames.front().Node->ArrivalEventID && !keyFrames.front().Node->DepartureEventID) { splinePath.erase(splinePath.begin()); keyFrames.erase(keyFrames.begin()); } - if (!keyFrames.back().IsStopFrame() && !keyFrames.back().Node->arrivalEventID && !keyFrames.back().Node->departureEventID) + if (!keyFrames.back().IsStopFrame() && !keyFrames.back().Node->ArrivalEventID && !keyFrames.back().Node->DepartureEventID) { splinePath.pop_back(); keyFrames.pop_back(); @@ -311,7 +311,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl float curPathTime = 0.0f; if (keyFrames[0].IsStopFrame()) { - curPathTime = float(keyFrames[0].Node->delay); + curPathTime = float(keyFrames[0].Node->Delay); keyFrames[0].DepartureTime = uint32(curPathTime * IN_MILLISECONDS); } @@ -322,7 +322,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl { keyFrames[i].ArriveTime = uint32(curPathTime * IN_MILLISECONDS); keyFrames[i - 1].NextArriveTime = keyFrames[i].ArriveTime; - curPathTime += float(keyFrames[i].Node->delay); + curPathTime += float(keyFrames[i].Node->Delay); keyFrames[i].DepartureTime = uint32(curPathTime * IN_MILLISECONDS); } else @@ -374,10 +374,10 @@ Transport* TransportMgr::CreateTransport(uint32 entry, uint32 guid /*= 0*/, Map* // ...at first waypoint TaxiPathNodeEntry const* startNode = tInfo->keyFrames.begin()->Node; - uint32 mapId = startNode->mapid; - float x = startNode->x; - float y = startNode->y; - float z = startNode->z; + uint32 mapId = startNode->MapID; + float x = startNode->LocX; + float y = startNode->LocY; + float z = startNode->LocZ; float o = tInfo->keyFrames.begin()->InitialOrientation; // initialize the gameobject base diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h index dbd99bd163a..fff7b9d8afa 100644 --- a/src/server/game/Maps/TransportMgr.h +++ b/src/server/game/Maps/TransportMgr.h @@ -61,7 +61,7 @@ struct KeyFrame uint32 NextArriveTime; bool IsTeleportFrame() const { return Teleport; } - bool IsStopFrame() const { return Node->actionFlag == 2; } + bool IsStopFrame() const { return Node->Flags == 2; } }; struct TransportTemplate diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 685bcd338a9..06c58a408da 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -3599,4 +3599,12 @@ enum DiminishingLevels DIMINISHING_LEVEL_TAUNT_IMMUNE = 4 }; +/// Spell cooldown flags sent in SMSG_SPELL_COOLDOWN +enum SpellCooldownFlags +{ + SPELL_COOLDOWN_FLAG_NONE = 0x0, + SPELL_COOLDOWN_FLAG_INCLUDE_GCD = 0x1, ///< Starts GCD in addition to normal cooldown specified in the packet + SPELL_COOLDOWN_FLAG_INCLUDE_EVENT_COOLDOWNS = 0x2 ///< Starts GCD for spells that should start their cooldown on events, requires SPELL_COOLDOWN_FLAG_INCLUDE_GCD set +}; + #endif diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index a4c3831cf82..f91fc1985d5 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -248,10 +248,10 @@ uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const if (i_currentNode >= i_path->size()) return i_path->size(); - uint32 curMapId = (*i_path)[i_currentNode].mapid; + uint32 curMapId = (*i_path)[i_currentNode].MapID; for (uint32 i = i_currentNode; i < i_path->size(); ++i) { - if ((*i_path)[i].mapid != curMapId) + if ((*i_path)[i].MapID != curMapId) return i; } @@ -296,7 +296,7 @@ void FlightPathMovementGenerator::DoReset(Player* player) uint32 end = GetPathAtMapEnd(); for (uint32 i = GetCurrentNode(); i != end; ++i) { - G3D::Vector3 vertice((*i_path)[i].x, (*i_path)[i].y, (*i_path)[i].z); + G3D::Vector3 vertice((*i_path)[i].LocX, (*i_path)[i].LocY, (*i_path)[i].LocZ); init.Path().push_back(vertice); } init.SetFirstPointId(GetCurrentNode()); @@ -332,10 +332,10 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport() if (i_path->empty()) return; - uint32 map0 = (*i_path)[0].mapid; + uint32 map0 = (*i_path)[0].MapID; for (size_t i = 1; i < i_path->size(); ++i) { - if ((*i_path)[i].mapid != map0) + if ((*i_path)[i].MapID != map0) { i_currentNode = i; return; @@ -345,9 +345,9 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport() void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry const& node, bool departure) { - if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID) + if (uint32 eventid = departure ? node.DepartureEventID : node.ArrivalEventID) { - TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.index, node.path, player->GetName().c_str()); + TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.NodeIndex, node.PathID, player->GetName().c_str()); player->GetMap()->ScriptsStart(sEventScripts, eventid, player, player); } } @@ -355,7 +355,7 @@ void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry bool FlightPathMovementGenerator::GetResetPos(Player*, float& x, float& y, float& z) { const TaxiPathNodeEntry& node = (*i_path)[i_currentNode]; - x = node.x; y = node.y; z = node.z; + x = node.LocX; y = node.LocY; z = node.LocZ; return true; } @@ -364,10 +364,10 @@ void FlightPathMovementGenerator::InitEndGridInfo() /*! Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will be reinitialized for each flightmaster at the end of each spline (or stop) in the flight. */ uint32 nodeCount = (*i_path).size(); //! Number of nodes in path. - _endMapId = (*i_path)[nodeCount - 1].mapid; //! MapId of last node + _endMapId = (*i_path)[nodeCount - 1].MapID; //! MapId of last node _preloadTargetNode = nodeCount - 3; - _endGridX = (*i_path)[nodeCount - 1].x; - _endGridY = (*i_path)[nodeCount - 1].y; + _endGridX = (*i_path)[nodeCount - 1].LocX; + _endGridY = (*i_path)[nodeCount - 1].LocY; } void FlightPathMovementGenerator::PreloadEndGrid() diff --git a/src/server/game/Movement/Spline/MoveSplineFlag.h b/src/server/game/Movement/Spline/MoveSplineFlag.h index 62fe808b6f5..0a3b41d412a 100644 --- a/src/server/game/Movement/Spline/MoveSplineFlag.h +++ b/src/server/game/Movement/Spline/MoveSplineFlag.h @@ -24,11 +24,7 @@ namespace Movement { -#if defined( __GNUC__ ) -#pragma pack(1) -#else #pragma pack(push, 1) -#endif class MoveSplineFlag { @@ -136,11 +132,7 @@ namespace Movement bool unknown12 : 1; bool unknown13 : 1; }; -#if defined( __GNUC__ ) -#pragma pack() -#else #pragma pack(pop) -#endif } #endif // TRINITYSERVER_MOVESPLINEFLAG_H diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index 68abadccf75..4b47e51fde6 100644 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -1363,11 +1363,7 @@ enum PacketProcessing class WorldSession; class WorldPacket; -#if defined(__GNUC__) -#pragma pack(1) -#else #pragma pack(push, 1) -#endif struct OpcodeHandler { @@ -1379,11 +1375,7 @@ struct OpcodeHandler extern OpcodeHandler opcodeTable[NUM_MSG_TYPES]; -#if defined(__GNUC__) -#pragma pack() -#else #pragma pack(pop) -#endif /// Lookup opcode name for human understandable logging inline const char* LookupOpcodeName(uint16 id) diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index d79392177e4..d6055e9733b 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -1370,6 +1370,7 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co case MSG_RANDOM_ROLL: // not profiled case CMSG_TIME_SYNC_RESP: // not profiled case CMSG_TRAINER_BUY_SPELL: // not profiled + case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: // not profiled { // "0" is a magic number meaning there's no limit for the opcode. // All the opcodes above must cause little CPU usage and no sync/async database queries at all diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index de2dc26b643..378f5f0d622 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -27,6 +27,7 @@ #include "ObjectAccessor.h" #include "Util.h" #include "Spell.h" +#include "SpellHistory.h" #include "SpellAuraEffects.h" #include "Battleground.h" #include "OutdoorPvPMgr.h" @@ -1108,15 +1109,13 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const // Remove cooldown of spells triggered on stance change - they may share cooldown with stance spell if (spellId) { - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->RemoveSpellCooldown(spellId); + target->GetSpellHistory()->ResetCooldown(spellId); target->CastSpell(target, spellId, true, NULL, this); } if (spellId2) { - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->RemoveSpellCooldown(spellId2); + target->GetSpellHistory()->ResetCooldown(spellId2); target->CastSpell(target, spellId2, true, NULL, this); } @@ -3852,10 +3851,11 @@ void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint } else { - if (int32(target->GetHealth()) > GetAmount()) - target->ModifyHealth(-GetAmount()); - else - target->SetHealth(1); + if (target->GetHealth() > 0) + { + int32 value = std::min<int32>(target->GetHealth() - 1, GetAmount()); + target->ModifyHealth(-value); + } target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); } } @@ -3867,19 +3867,15 @@ void AuraEffect::HandleAuraModIncreaseMaxHealth(AuraApplication const* aurApp, u Unit* target = aurApp->GetTarget(); - uint32 oldhealth = target->GetHealth(); - double healthPercentage = (double)oldhealth / (double)target->GetMaxHealth(); + float percent = target->GetHealthPct(); target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); // refresh percentage - if (oldhealth > 0) + if (target->GetHealth() > 0) { - uint32 newhealth = uint32(ceil((double)target->GetMaxHealth() * healthPercentage)); - if (newhealth == 0) - newhealth = 1; - - target->SetHealth(newhealth); + uint32 newHealth = std::max<uint32>(target->CountPctFromMaxHealth(int32(percent)), 1); + target->SetHealth(newHealth); } } @@ -3943,8 +3939,12 @@ void AuraEffect::HandleAuraModIncreaseHealthPercent(AuraApplication const* aurAp // Unit will keep hp% after MaxHealth being modified if unit is alive. float percent = target->GetHealthPct(); target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount()), apply); - if (target->IsAlive()) - target->SetHealth(target->CountPctFromMaxHealth(int32(percent))); + + if (target->GetHealth() > 0) + { + uint32 newHealth = std::max<uint32>(target->CountPctFromMaxHealth(int32(percent)), 1); + target->SetHealth(newHealth); + } } void AuraEffect::HandleAuraIncreaseBaseHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 0ba059b1952..5479dcdbf00 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -25,6 +25,7 @@ #include "Player.h" #include "Unit.h" #include "Spell.h" +#include "SpellHistory.h" #include "SpellAuraEffects.h" #include "DynamicObject.h" #include "ObjectAccessor.h" @@ -418,7 +419,7 @@ void Aura::_ApplyForTarget(Unit* target, Unit* caster, AuraApplication * auraApp if (m_spellInfo->IsCooldownStartedOnEvent()) { Item* castItem = m_castItemGuid ? caster->ToPlayer()->GetItemByGuid(m_castItemGuid) : NULL; - caster->ToPlayer()->AddSpellAndCategoryCooldowns(m_spellInfo, castItem ? castItem->GetEntry() : 0, NULL, true); + caster->GetSpellHistory()->StartCooldown(m_spellInfo, castItem ? castItem->GetEntry() : 0, nullptr, true); } } } @@ -446,12 +447,9 @@ void Aura::_UnapplyForTarget(Unit* target, Unit* caster, AuraApplication * auraA m_removedApplications.push_back(auraApp); // reset cooldown state for spells - if (caster && caster->GetTypeId() == TYPEID_PLAYER) - { - if (GetSpellInfo()->IsCooldownStartedOnEvent()) - // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases) - caster->ToPlayer()->SendCooldownEvent(GetSpellInfo()); - } + if (caster && GetSpellInfo()->IsCooldownStartedOnEvent()) + // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases) + caster->GetSpellHistory()->SendCooldownEvent(GetSpellInfo()); } // removes aura from all targets @@ -1215,7 +1213,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b break; case 60970: // Heroic Fury (remove Intercept cooldown) if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->RemoveSpellCooldown(20252, true); + target->GetSpellHistory()->ResetCooldown(20252, true); break; } break; @@ -1497,15 +1495,15 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b // check cooldown if (caster->GetTypeId() == TYPEID_PLAYER) { - if (caster->ToPlayer()->HasSpellCooldown(aura->GetId())) + if (caster->GetSpellHistory()->HasCooldown(aura->GetId())) { // This additional check is needed to add a minimal delay before cooldown in in effect // to allow all bubbles broken by a single damage source proc mana return - if (caster->ToPlayer()->GetSpellCooldownDelay(aura->GetId()) <= 11) + if (caster->GetSpellHistory()->GetRemainingCooldown(aura->GetId()) <= 11) break; } else // and add if needed - caster->ToPlayer()->AddSpellCooldown(aura->GetId(), 0, uint32(time(NULL) + 12)); + caster->GetSpellHistory()->AddCooldown(aura->GetId(), 0, std::chrono::seconds(12)); } // effect on caster @@ -1558,14 +1556,14 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b // Glyph of Guardian Spirit if (AuraEffect* aurEff = player->GetAuraEffect(63231, 0)) { - if (!player->HasSpellCooldown(47788)) + if (!player->GetSpellHistory()->HasCooldown(47788)) break; - player->RemoveSpellCooldown(GetSpellInfo()->Id, true); - player->AddSpellCooldown(GetSpellInfo()->Id, 0, uint32(time(NULL) + aurEff->GetAmount())); + player->GetSpellHistory()->ResetCooldown(GetSpellInfo()->Id, true); + player->GetSpellHistory()->AddCooldown(GetSpellInfo()->Id, 0, std::chrono::seconds(aurEff->GetAmount())); WorldPacket data; - player->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, GetSpellInfo()->Id, aurEff->GetAmount()*IN_MILLISECONDS); + player->GetSpellHistory()->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, GetSpellInfo()->Id, aurEff->GetAmount() * IN_MILLISECONDS); player->SendDirectMessage(&data); } break; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index dbe87daa1a1..94bb90487bc 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -50,6 +50,7 @@ #include "SpellScript.h" #include "InstanceScript.h" #include "SpellInfo.h" +#include "SpellHistory.h" #include "Battlefield.h" #include "BattlefieldMgr.h" @@ -3226,7 +3227,7 @@ void Spell::cast(bool skipCheck) //Clear spell cooldowns after every spell is cast if .cheat cooldown is enabled. if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_COOLDOWN)) - m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id, true); + m_caster->GetSpellHistory()->ResetCooldown(m_spellInfo->Id, true); } SetExecutedCurrently(false); @@ -3430,30 +3431,7 @@ void Spell::_handle_finish_phase() void Spell::SendSpellCooldown() { - Player* _player = m_caster->ToPlayer(); - if (!_player) - { - // Handle pet cooldowns here if needed instead of in PetAI to avoid hidden cooldown restarts - Creature* _creature = m_caster->ToCreature(); - if (_creature && (_creature->IsPet() || _creature->IsGuardian())) - _creature->AddCreatureSpellCooldown(m_spellInfo->Id); - - return; - } - - // mana/health/etc potions, disabled by client (until combat out as declarate) - if (m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent())) - { - // need in some way provided data for Spell::finish SendCooldownEvent - _player->SetLastPotionId(m_CastItem->GetEntry()); - return; - } - - // have infinity cooldown but set at aura apply // do not set cooldown for triggered spells (needed by reincarnation) - if (m_spellInfo->IsCooldownStartedOnEvent() || m_spellInfo->IsPassive() || (_triggeredCastFlags & TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD)) - return; - - _player->AddSpellAndCategoryCooldowns(m_spellInfo, m_CastItem ? m_CastItem->GetEntry() : 0, this); + m_caster->GetSpellHistory()->HandleCooldowns(m_spellInfo, m_CastItem, this); } void Spell::update(uint32 difftime) @@ -4635,23 +4613,26 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_CASTER_DEAD; // check cooldowns to prevent cheating - if (m_caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE)) + if (!m_spellInfo->IsPassive()) { - //can cast triggered (by aura only?) spells while have this flag - if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE) && m_caster->ToPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY)) - return SPELL_FAILED_SPELL_IN_PROGRESS; + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + //can cast triggered (by aura only?) spells while have this flag + if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE) && m_caster->ToPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY)) + return SPELL_FAILED_SPELL_IN_PROGRESS; - if (m_caster->ToPlayer()->HasSpellCooldown(m_spellInfo->Id)) + // check if we are using a potion in combat for the 2nd+ time. Cooldown is added only after caster gets out of combat + if (m_caster->ToPlayer()->GetLastPotionId() && m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent())) + return SPELL_FAILED_NOT_READY; + } + + if (!m_caster->GetSpellHistory()->IsReady(m_spellInfo)) { if (m_triggeredByAuraSpell) return SPELL_FAILED_DONT_REPORT; else return SPELL_FAILED_NOT_READY; } - - // check if we are using a potion in combat for the 2nd+ time. Cooldown is added only after caster gets out of combat - if (m_caster->ToPlayer()->GetLastPotionId() && m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent())) - return SPELL_FAILED_NOT_READY; } if (m_spellInfo->HasAttribute(SPELL_ATTR7_IS_CHEAT_SPELL) && !m_caster->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS)) @@ -5504,13 +5485,13 @@ SpellCastResult Spell::CheckPetCast(Unit* target) } // cooldown - if (Creature const* creatureCaster = m_caster->ToCreature()) - if (creatureCaster->HasSpellCooldown(m_spellInfo->Id)) + if (Creature* creatureCaster = m_caster->ToCreature()) + if (!creatureCaster->GetSpellHistory()->IsReady(m_spellInfo)) return SPELL_FAILED_NOT_READY; // Check if spell is affected by GCD if (m_spellInfo->StartRecoveryCategory > 0) - if (m_caster->GetCharmInfo() && m_caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo)) + if (m_caster->GetCharmInfo() && m_caster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo)) return SPELL_FAILED_NOT_READY; return CheckCast(true); @@ -5801,7 +5782,7 @@ SpellCastResult Spell::CheckItems() if (!proto) return SPELL_FAILED_ITEM_NOT_READY; - for (uint8 i = 0; i < MAX_ITEM_SPELLS; ++i) + for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) if (proto->Spells[i].SpellCharges) if (m_CastItem->GetSpellCharges(i) == 0) return SPELL_FAILED_NO_CHARGES_REMAIN; @@ -7230,13 +7211,11 @@ enum GCDLimits bool Spell::HasGlobalCooldown() const { - // Only player or controlled units have global cooldown - if (m_caster->GetCharmInfo()) - return m_caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo); - else if (m_caster->GetTypeId() == TYPEID_PLAYER) - return m_caster->ToPlayer()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo); - else + // Only players or controlled units have global cooldown + if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo()) return false; + + return m_caster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo); } void Spell::TriggerGlobalCooldown() @@ -7245,6 +7224,10 @@ void Spell::TriggerGlobalCooldown() if (!gcd) return; + // Only players or controlled units have global cooldown + if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo()) + return; + if (m_caster->GetTypeId() == TYPEID_PLAYER) if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_COOLDOWN)) return; @@ -7266,11 +7249,7 @@ void Spell::TriggerGlobalCooldown() gcd = MAX_GCD; } - // Only players or controlled units have global cooldown - if (m_caster->GetCharmInfo()) - m_caster->GetCharmInfo()->GetGlobalCooldownMgr().AddGlobalCooldown(m_spellInfo, gcd); - else if (m_caster->GetTypeId() == TYPEID_PLAYER) - m_caster->ToPlayer()->GetGlobalCooldownMgr().AddGlobalCooldown(m_spellInfo, gcd); + m_caster->GetSpellHistory()->AddGlobalCooldown(m_spellInfo, gcd); } void Spell::CancelGlobalCooldown() @@ -7283,10 +7262,10 @@ void Spell::CancelGlobalCooldown() return; // Only players or controlled units have global cooldown - if (m_caster->GetCharmInfo()) - m_caster->GetCharmInfo()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo); - else if (m_caster->GetTypeId() == TYPEID_PLAYER) - m_caster->ToPlayer()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo); + if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo()) + return; + + m_caster->GetSpellHistory()->CancelGlobalCooldown(m_spellInfo); } namespace Trinity @@ -7405,7 +7384,7 @@ bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target) } else if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_LINE)) { - if (!_caster->HasInLine(target, _caster->GetObjectSize())) + if (!_caster->HasInLine(target, _caster->GetObjectSize() + target->GetObjectSize())) return false; } else @@ -7422,7 +7401,7 @@ WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Po bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target) { // return all targets on missile trajectory (0 - size of a missile) - if (!_caster->HasInLine(target, 0)) + if (!_caster->HasInLine(target, target->GetObjectSize())) return false; return WorldObjectSpellAreaTargetCheck::operator ()(target); } diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 2ae2930aeb0..1aac88ac602 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -473,6 +473,7 @@ class Spell void ReSetTimer() { m_timer = m_casttime > 0 ? m_casttime : 0; } bool IsNextMeleeSwingSpell() const; bool IsTriggered() const { return (_triggeredCastFlags & TRIGGERED_FULL_MASK) != 0; } + bool IsIgnoringCooldowns() const { return (_triggeredCastFlags & TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD) != 0; } bool IsChannelActive() const { return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0; } bool IsAutoActionResetSpell() const; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index cb518ee6099..3829e12b790 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -48,6 +48,7 @@ #include "GridNotifiers.h" #include "Formulas.h" #include "ScriptMgr.h" +#include "SpellHistory.h" #include "GameObjectAI.h" #include "AccountMgr.h" #include "InstanceScript.h" @@ -769,8 +770,8 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex) return; // Reset cooldown on stealth if needed - if (unitTarget->ToPlayer()->HasSpellCooldown(1784)) - unitTarget->ToPlayer()->RemoveSpellCooldown(1784); + if (unitTarget->GetSpellHistory()->HasCooldown(1784)) + unitTarget->GetSpellHistory()->ResetCooldown(1784); unitTarget->CastSpell(unitTarget, 1784, true); return; @@ -879,7 +880,7 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex) // Remove spell cooldown (not category) if spell triggering spell with cooldown and same category if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime && m_spellInfo->GetCategory() == spellInfo->GetCategory()) - m_caster->ToPlayer()->RemoveSpellCooldown(spellInfo->Id); + m_caster->GetSpellHistory()->ResetCooldown(spellInfo->Id); // original caster guid only for GO cast m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID); @@ -932,7 +933,7 @@ void Spell::EffectTriggerMissileSpell(SpellEffIndex effIndex) // Remove spell cooldown (not category) if spell triggering spell with cooldown and same category if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime && m_spellInfo->GetCategory() == spellInfo->GetCategory()) - m_caster->ToPlayer()->RemoveSpellCooldown(spellInfo->Id); + m_caster->GetSpellHistory()->ResetCooldown(spellInfo->Id); // original caster guid only for GO cast m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID); @@ -3472,7 +3473,7 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex) if (m_originalCaster) { int32 duration = m_spellInfo->GetDuration(); - unitTarget->ProhibitSpellSchool(curSpellInfo->GetSchoolMask(), unitTarget->ModSpellDuration(m_spellInfo, unitTarget, duration, false, 1 << effIndex)); + unitTarget->GetSpellHistory()->LockSpellSchool(curSpellInfo->GetSchoolMask(), unitTarget->ModSpellDuration(m_spellInfo, unitTarget, duration, false, 1 << effIndex)); } ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo->Id); unitTarget->InterruptSpell(CurrentSpellTypes(i), false); @@ -5839,7 +5840,7 @@ void Spell::EffectCastButtons(SpellEffIndex effIndex) if (!spellInfo) continue; - if (!p_caster->HasSpell(spell_id) || p_caster->HasSpellCooldown(spell_id)) + if (!p_caster->HasSpell(spell_id) || p_caster->GetSpellHistory()->HasCooldown(spell_id)) continue; if (!spellInfo->HasAttribute(SPELL_ATTR7_SUMMON_PLAYER_TOTEM)) diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp new file mode 100644 index 00000000000..09e3be690b1 --- /dev/null +++ b/src/server/game/Spells/SpellHistory.cpp @@ -0,0 +1,643 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "WorldPacket.h" +#include "SpellHistory.h" +#include "Pet.h" +#include "Player.h" +#include "SpellInfo.h" +#include "Spell.h" +#include "World.h" +#include "Opcodes.h" + +SpellHistory::Clock::duration const SpellHistory::InfinityCooldownDelay = std::chrono::duration_cast<SpellHistory::Clock::duration>(std::chrono::seconds(MONTH)); +SpellHistory::Clock::duration const SpellHistory::InfinityCooldownDelayCheck = std::chrono::duration_cast<SpellHistory::Clock::duration>(std::chrono::seconds(MONTH / 2)); + +template<> +struct SpellHistory::PersistenceHelper<Player> +{ + static CharacterDatabaseStatements const CooldownsDeleteStatement = CHAR_DEL_CHAR_SPELL_COOLDOWNS; + static CharacterDatabaseStatements const CooldownsInsertStatement = CHAR_INS_CHAR_SPELL_COOLDOWN; + + static void SetIdentifier(PreparedStatement* stmt, uint8 index, Unit* owner) { stmt->setUInt32(index, owner->GetGUID().GetCounter()); } + + static bool ReadCooldown(Field* fields, uint32* spellId, CooldownEntry* cooldownEntry) + { + *spellId = fields[0].GetUInt32(); + if (!sSpellMgr->GetSpellInfo(*spellId)) + return false; + + cooldownEntry->CooldownEnd = Clock::from_time_t(time_t(fields[2].GetUInt32())); + cooldownEntry->ItemId = fields[1].GetUInt32(); + return true; + } + + static void WriteCooldown(PreparedStatement* stmt, uint8& index, CooldownStorageType::value_type const& cooldown) + { + stmt->setUInt32(index++, cooldown.first); + stmt->setUInt32(index++, cooldown.second.ItemId); + stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CooldownEnd))); + } +}; + +template<> +struct SpellHistory::PersistenceHelper<Pet> +{ + static CharacterDatabaseStatements const CooldownsDeleteStatement = CHAR_DEL_PET_SPELL_COOLDOWNS; + static CharacterDatabaseStatements const CooldownsInsertStatement = CHAR_INS_PET_SPELL_COOLDOWN; + + static void SetIdentifier(PreparedStatement* stmt, uint8 index, Unit* owner) { stmt->setUInt32(index, owner->GetCharmInfo()->GetPetNumber()); } + + static bool ReadCooldown(Field* fields, uint32* spellId, CooldownEntry* cooldownEntry) + { + *spellId = fields[0].GetUInt32(); + if (!sSpellMgr->GetSpellInfo(*spellId)) + return false; + + cooldownEntry->CooldownEnd = Clock::from_time_t(time_t(fields[1].GetUInt32())); + cooldownEntry->ItemId = 0; + return true; + } + + static void WriteCooldown(PreparedStatement* stmt, uint8& index, CooldownStorageType::value_type const& cooldown) + { + stmt->setUInt32(index++, cooldown.first); + stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CooldownEnd))); + } +}; + +template<class OwnerType> +void SpellHistory::LoadFromDB(PreparedQueryResult cooldownsResult) +{ + typedef PersistenceHelper<OwnerType> StatementInfo; + + if (cooldownsResult) + { + do + { + uint32 spellId; + CooldownEntry cooldown; + if (StatementInfo::ReadCooldown(cooldownsResult->Fetch(), &spellId, &cooldown)) + _spellCooldowns[spellId] = cooldown; + + } while (cooldownsResult->NextRow()); + } +} + +template<class OwnerType> +void SpellHistory::SaveToDB(SQLTransaction& trans) +{ + typedef PersistenceHelper<OwnerType> StatementInfo; + + uint8 index = 0; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(StatementInfo::CooldownsDeleteStatement); + StatementInfo::SetIdentifier(stmt, index++, _owner); + trans->Append(stmt); + + for (auto const& p : _spellCooldowns) + { + if (!p.second.OnHold) + { + index = 0; + stmt = CharacterDatabase.GetPreparedStatement(StatementInfo::CooldownsInsertStatement); + StatementInfo::SetIdentifier(stmt, index++, _owner); + StatementInfo::WriteCooldown(stmt, index, p); + trans->Append(stmt); + } + } +} + +void SpellHistory::Update() +{ + SQLTransaction t; + Clock::time_point now = Clock::now(); + for (auto itr = _spellCooldowns.begin(); itr != _spellCooldowns.end();) + { + if (itr->second.CooldownEnd < now) + itr = _spellCooldowns.erase(itr); + else + ++itr; + } +} + +void SpellHistory::HandleCooldowns(SpellInfo const* spellInfo, Item const* item, Spell* spell /*= nullptr*/) +{ + if (Player* player = _owner->ToPlayer()) + { + // potions start cooldown until exiting combat + if (item && (item->IsPotion() || spellInfo->IsCooldownStartedOnEvent())) + { + player->SetLastPotionId(item->GetEntry()); + return; + } + } + + if (spellInfo->IsCooldownStartedOnEvent() || spellInfo->IsPassive() || (spell && spell->IsIgnoringCooldowns())) + return; + + StartCooldown(spellInfo, item ? item->GetEntry() : 0, spell); +} + +bool SpellHistory::IsReady(SpellInfo const* spellInfo) const +{ + if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) + if (IsSchoolLocked(spellInfo->GetSchoolMask())) + return false; + + if (HasCooldown(spellInfo->Id)) + return false; + + return true; +} + +template<> +void SpellHistory::WritePacket<Pet>(WorldPacket& packet) const +{ + Clock::time_point now = Clock::now(); + + uint8 cooldownsCount = _spellCooldowns.size(); + packet << uint8(cooldownsCount); + + for (auto const& spellCooldown : _spellCooldowns) + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellCooldown.first); + if (!spellInfo) + { + packet << uint32(0); + packet << uint16(0); + packet << uint32(0); + packet << uint32(0); + continue; + } + + packet << uint32(spellCooldown.first); // spell ID + packet << uint16(spellInfo->GetCategory()); // spell category + if (!spellCooldown.second.OnHold) + { + uint32 cooldownDuration = spellCooldown.second.CooldownEnd > now ? std::chrono::duration_cast<std::chrono::milliseconds>(spellCooldown.second.CooldownEnd - now).count() : 0; + if (cooldownDuration <= 0) + { + packet << uint32(0); + packet << uint32(0); + continue; + } + + if (spellInfo->GetCategory()) + { + packet << uint32(0); + packet << uint32(cooldownDuration); + } + else + { + packet << uint32(cooldownDuration); + packet << uint32(0); + } + } + } +} + +template<> +void SpellHistory::WritePacket<Player>(WorldPacket& packet) const +{ + Clock::time_point now = Clock::now(); + Clock::time_point infTime = now + InfinityCooldownDelayCheck; + + uint16 cooldownsCount = _spellCooldowns.size(); + size_t dataPos = packet.wpos(); + packet << uint16(cooldownsCount); + + for (auto const& spellCooldown : _spellCooldowns) + { + SpellInfo const* sEntry = sSpellMgr->GetSpellInfo(spellCooldown.first); + if (!sEntry) + { + --cooldownsCount; + continue; + } + + packet << uint32(spellCooldown.first); + + packet << uint16(spellCooldown.second.ItemId); // cast item id + packet << uint16(sEntry->GetCategory()); // spell category + + // send infinity cooldown in special format + if (spellCooldown.second.CooldownEnd >= infTime) + { + packet << uint32(1); // cooldown + packet << uint32(0x80000000); // category cooldown + continue; + } + + uint32 cooldownDuration = spellCooldown.second.CooldownEnd > now ? std::chrono::duration_cast<std::chrono::milliseconds>(spellCooldown.second.CooldownEnd - now).count() : 0; + + if (sEntry->GetCategory()) // may be wrong, but anyway better than nothing... + { + packet << uint32(0); // cooldown + packet << uint32(cooldownDuration); // category cooldown + } + else + { + packet << uint32(cooldownDuration); // cooldown + packet << uint32(0); // category cooldown + } + } + + packet.put<uint16>(dataPos, cooldownsCount); +} + +void SpellHistory::StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spell* spell /*= nullptr*/, bool onHold /*= false*/) +{ + // init cooldown values + uint32 categoryId = 0; + int32 cooldown = -1; + int32 categoryCooldown = -1; + + // some special item spells without correct cooldown in SpellInfo + // cooldown information stored in item prototype + if (itemId) + { + if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId)) + { + for (uint8 idx = 0; idx < MAX_ITEM_PROTO_SPELLS; ++idx) + { + if (uint32(proto->Spells[idx].SpellId) == spellInfo->Id) + { + categoryId = proto->Spells[idx].SpellCategory; + cooldown = proto->Spells[idx].SpellCooldown; + categoryCooldown = proto->Spells[idx].SpellCategoryCooldown; + break; + } + } + } + } + + // if no cooldown found above then base at DBC data + if (cooldown < 0 && categoryCooldown < 0) + { + categoryId = spellInfo->GetCategory(); + cooldown = spellInfo->RecoveryTime; + categoryCooldown = spellInfo->CategoryRecoveryTime; + } + + Clock::time_point curTime = Clock::now(); + Clock::time_point catrecTime; + Clock::time_point recTime; + bool needsCooldownPacket = false; + + // overwrite time for selected category + if (onHold) + { + // use +MONTH as infinite cooldown marker + catrecTime = categoryCooldown > 0 ? (curTime + InfinityCooldownDelay) : curTime; + recTime = cooldown > 0 ? (curTime + InfinityCooldownDelay) : catrecTime; + } + else + { + // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK) + // prevent 0 cooldowns set by another way + if (cooldown <= 0 && categoryCooldown <= 0 && (categoryId == 76 || (spellInfo->IsAutoRepeatRangedSpell() && spellInfo->Id != 75))) + cooldown = _owner->GetAttackTime(RANGED_ATTACK); + + // Now we have cooldown data (if found any), time to apply mods + if (Player* modOwner = _owner->GetSpellModOwner()) + { + if (cooldown > 0) + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, cooldown, spell); + + if (categoryCooldown > 0 && !spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS)) + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, categoryCooldown, spell); + } + + if (int32 cooldownMod = _owner->GetTotalAuraModifier(SPELL_AURA_MOD_COOLDOWN)) + { + // Apply SPELL_AURA_MOD_COOLDOWN only to own spells + Player* playerOwner = GetPlayerOwner(); + if (!playerOwner || playerOwner->HasSpell(spellInfo->Id)) + { + needsCooldownPacket = true; + cooldown += cooldownMod * IN_MILLISECONDS; // SPELL_AURA_MOD_COOLDOWN does not affect category cooldows, verified with shaman shocks + } + } + + // replace negative cooldowns by 0 + if (cooldown < 0) + cooldown = 0; + + if (categoryCooldown < 0) + categoryCooldown = 0; + + // no cooldown after applying spell mods + if (cooldown == 0 && categoryCooldown == 0) + return; + + catrecTime = categoryCooldown ? curTime + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(categoryCooldown)) : curTime; + recTime = cooldown ? curTime + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(cooldown)) : catrecTime; + } + + // self spell cooldown + if (recTime != curTime) + { + AddCooldown(spellInfo->Id, itemId, recTime, onHold); + + if (needsCooldownPacket) + { + if (Player* playerOwner = GetPlayerOwner()) + { + WorldPacket spellCooldown; + BuildCooldownPacket(spellCooldown, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, cooldown); + playerOwner->SendDirectMessage(&spellCooldown); + } + } + } + + // category spells + if (categoryId && catrecTime != curTime) + { + SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(categoryId); + if (i_scstore != sSpellsByCategoryStore.end()) + { + for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset) + { + if (*i_scset == spellInfo->Id) // skip main spell, already handled above + continue; + + AddCooldown(*i_scset, itemId, catrecTime, onHold); + } + } + } +} + +void SpellHistory::SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId /*= 0*/, Spell* spell /*= nullptr*/, bool startCooldown /*= true*/) +{ + // start cooldowns at server side, if any + if (startCooldown) + StartCooldown(spellInfo, itemId, spell); + + if (Player* player = GetPlayerOwner()) + { + // Send activate cooldown timer (possible 0) at client side + WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8); + data << uint32(spellInfo->Id); + data << uint64(_owner->GetGUID()); + player->SendDirectMessage(&data); + + uint32 category = spellInfo->GetCategory(); + if (category && spellInfo->CategoryRecoveryTime) + { + SpellCategoryStore::const_iterator ct = sSpellsByCategoryStore.find(category); + if (ct != sSpellsByCategoryStore.end()) + { + for (auto const& cooldownPair : _spellCooldowns) + { + uint32 categorySpell = cooldownPair.first; + if (!ct->second.count(categorySpell)) + continue; + + if (categorySpell == spellInfo->Id) // skip main spell, already handled above + continue; + + SpellInfo const* spellInfo2 = sSpellMgr->EnsureSpellInfo(categorySpell); + if (!spellInfo2->IsCooldownStartedOnEvent()) + continue; + + data.Initialize(SMSG_COOLDOWN_EVENT, 4 + 8); + data << uint32(categorySpell); + data << uint64(_owner->GetGUID()); + player->SendDirectMessage(&data); + } + } + } + } +} + +void SpellHistory::AddCooldown(uint32 spellId, uint32 itemId, Clock::time_point cooldownEnd, bool onHold /*= false*/) +{ + CooldownEntry& cooldownEntry = _spellCooldowns[spellId]; + cooldownEntry.CooldownEnd = cooldownEnd; + cooldownEntry.ItemId = itemId; + cooldownEntry.OnHold = onHold; +} + +void SpellHistory::ModifyCooldown(uint32 spellId, int32 cooldownModMs) +{ + auto itr = _spellCooldowns.find(spellId); + if (!cooldownModMs || itr == _spellCooldowns.end()) + return; + + Clock::time_point now = Clock::now(); + Clock::duration offset = std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(cooldownModMs)); + if (itr->second.CooldownEnd + offset > now) + itr->second.CooldownEnd += offset; + else + _spellCooldowns.erase(itr); + + if (Player* playerOwner = GetPlayerOwner()) + { + WorldPacket modifyCooldown(SMSG_MODIFY_COOLDOWN, 4 + 8 + 4); + modifyCooldown << uint32(spellId); + modifyCooldown << uint64(_owner->GetGUID()); + modifyCooldown << int32(cooldownModMs); + playerOwner->SendDirectMessage(&modifyCooldown); + } +} + +void SpellHistory::ResetCooldown(uint32 spellId, bool update /*= false*/) +{ + auto itr = _spellCooldowns.find(spellId); + if (itr == _spellCooldowns.end()) + return; + + ResetCooldown(itr, update); +} + +void SpellHistory::ResetCooldown(CooldownStorageType::iterator& itr, bool update /*= false*/) +{ + if (update) + { + if (Player* playerOwner = GetPlayerOwner()) + { + WorldPacket data(SMSG_CLEAR_COOLDOWN, 4 + 8); + data << uint32(itr->first); + data << uint64(_owner->GetGUID()); + playerOwner->SendDirectMessage(&data); + } + } + + itr = _spellCooldowns.erase(itr); +} + +void SpellHistory::ResetAllCooldowns() +{ + if (GetPlayerOwner()) + { + std::vector<int32> cooldowns; + cooldowns.reserve(_spellCooldowns.size()); + for (auto const& p : _spellCooldowns) + cooldowns.push_back(p.first); + + SendClearCooldowns(cooldowns); + } + + _spellCooldowns.clear(); +} + +bool SpellHistory::HasCooldown(uint32 spellId) const +{ + return _spellCooldowns.count(spellId) != 0; +} + +uint32 SpellHistory::GetRemainingCooldown(uint32 spellId) const +{ + auto itr = _spellCooldowns.find(spellId); + if (itr == _spellCooldowns.end()) + return 0; + + Clock::time_point now = Clock::now(); + if (itr->second.CooldownEnd < now) + return 0; + + Clock::duration remaining = itr->second.CooldownEnd - now; + return uint32(std::chrono::duration_cast<std::chrono::milliseconds>(remaining).count()); +} + +void SpellHistory::LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTime) +{ + Clock::time_point lockoutEnd = Clock::now() + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(lockoutTime)); + for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i) + if (SpellSchoolMask(1 << i) & schoolMask) + _schoolLockouts[i] = lockoutEnd; + + std::set<uint32> knownSpells; + if (Player* plrOwner = _owner->ToPlayer()) + { + for (auto const& p : plrOwner->GetSpellMap()) + if (p.second->state != PLAYERSPELL_REMOVED) + knownSpells.insert(p.first); + } + else if (Pet* petOwner = _owner->ToPet()) + { + for (auto const& p : petOwner->m_spells) + if (p.second.state != PETSPELL_REMOVED) + knownSpells.insert(p.first); + } + else + { + Creature* creatureOwner = _owner->ToCreature(); + for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i) + if (creatureOwner->m_spells[i]) + knownSpells.insert(creatureOwner->m_spells[i]); + } + + PacketCooldowns cooldowns; + WorldPacket spellCooldowns; + for (uint32 spellId : knownSpells) + { + SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(spellId); + if (spellInfo->IsCooldownStartedOnEvent()) + continue; + + if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE) + continue; + + if ((schoolMask & spellInfo->GetSchoolMask()) && GetRemainingCooldown(spellId) < lockoutTime) + { + cooldowns[spellId] = lockoutTime; + AddCooldown(spellId, 0, lockoutEnd); + } + } + + if (Player* player = GetPlayerOwner()) + { + if (!cooldowns.empty()) + { + BuildCooldownPacket(spellCooldowns, SPELL_COOLDOWN_FLAG_NONE, cooldowns); + player->SendDirectMessage(&spellCooldowns); + } + } +} + +bool SpellHistory::IsSchoolLocked(SpellSchoolMask schoolMask) const +{ + Clock::time_point now = Clock::now(); + for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i) + if (SpellSchoolMask(1 << i) & schoolMask) + if (_schoolLockouts[i] > now) + return true; + + return false; +} + +bool SpellHistory::HasGlobalCooldown(SpellInfo const* spellInfo) const +{ + auto itr = _globalCooldowns.find(spellInfo->StartRecoveryCategory); + return itr != _globalCooldowns.end() && itr->second > Clock::now(); +} + +void SpellHistory::AddGlobalCooldown(SpellInfo const* spellInfo, uint32 duration) +{ + _globalCooldowns[spellInfo->StartRecoveryCategory] = Clock::now() + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(duration)); +} + +void SpellHistory::CancelGlobalCooldown(SpellInfo const* spellInfo) +{ + _globalCooldowns[spellInfo->StartRecoveryCategory] = Clock::time_point(Clock::duration(0)); +} + +Player* SpellHistory::GetPlayerOwner() const +{ + return _owner->GetCharmerOrOwnerPlayerOrPlayerItself(); +} + +void SpellHistory::SendClearCooldowns(std::vector<int32> const& cooldowns) const +{ + if (Player* playerOwner = GetPlayerOwner()) + { + for (int32 spell : cooldowns) + { + WorldPacket data(SMSG_CLEAR_COOLDOWN, 4 + 8); + data << uint32(spell); + data << uint64(_owner->GetGUID()); + playerOwner->SendDirectMessage(&data); + } + } +} + +void SpellHistory::BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown) const +{ + data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + 4 + 4); + data << uint64(_owner->GetGUID()); + data << uint8(flags); + data << uint32(spellId); + data << uint32(cooldown); +} + +void SpellHistory::BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns) const +{ + data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + (4 + 4) * cooldowns.size()); + data << uint64(_owner->GetGUID()); + data << uint8(flags); + for (auto const& cooldown : cooldowns) + { + data << cooldown.first; + data << cooldown.second; + } +} + +template void SpellHistory::LoadFromDB<Player>(PreparedQueryResult cooldownsResult); +template void SpellHistory::LoadFromDB<Pet>(PreparedQueryResult cooldownsResult); +template void SpellHistory::SaveToDB<Player>(SQLTransaction& trans); +template void SpellHistory::SaveToDB<Pet>(SQLTransaction& trans); diff --git a/src/server/game/Spells/SpellHistory.h b/src/server/game/Spells/SpellHistory.h new file mode 100644 index 00000000000..f1533d57aef --- /dev/null +++ b/src/server/game/Spells/SpellHistory.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef SpellHistory_h__ +#define SpellHistory_h__ + +#include "SharedDefines.h" +#include "QueryResult.h" +#include "Transaction.h" +#include <chrono> +#include <deque> + +class Item; +class Player; +class Spell; +class SpellInfo; +class Unit; +struct SpellCategoryEntry; + +class SpellHistory +{ +public: + typedef std::chrono::system_clock Clock; + + struct CooldownEntry + { + CooldownEntry() : ItemId(0), OnHold(false) { } + CooldownEntry(Clock::time_point endTime, uint32 itemId) : CooldownEnd(endTime), ItemId(itemId), OnHold(false) { } + + Clock::time_point CooldownEnd; + uint32 ItemId; + bool OnHold; + }; + + typedef std::unordered_map<uint32 /*spellId*/, CooldownEntry> CooldownStorageType; + typedef std::unordered_map<uint32 /*categoryId*/, Clock::time_point> GlobalCooldownStorageType; + + explicit SpellHistory(Unit* owner) : _owner(owner), _schoolLockouts() { } + + template<class OwnerType> + void LoadFromDB(PreparedQueryResult cooldownsResult); + + template<class OwnerType> + void SaveToDB(SQLTransaction& trans); + + void Update(); + + void HandleCooldowns(SpellInfo const* spellInfo, Item const* item, Spell* spell = nullptr); + bool IsReady(SpellInfo const* spellInfo) const; + template<class OwnerType> + void WritePacket(WorldPacket& packet) const; + + // Cooldowns + static Clock::duration const InfinityCooldownDelay; // used for set "infinity cooldowns" for spells and check + static Clock::duration const InfinityCooldownDelayCheck; + + void StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spell* spell = nullptr, bool onHold = false); + void SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId = 0, Spell* spell = nullptr, bool startCooldown = true); + + template<class Type, class Period> + void AddCooldown(uint32 spellId, uint32 itemId, std::chrono::duration<Type, Period> cooldownDuration) + { + AddCooldown(spellId, itemId, Clock::now() + std::chrono::duration_cast<Clock::duration>(cooldownDuration)); + } + + void AddCooldown(uint32 spellId, uint32 itemId, Clock::time_point cooldownEnd, bool onHold = false); + void ModifyCooldown(uint32 spellId, int32 cooldownModMs); + void ResetCooldown(uint32 spellId, bool update = false); + void ResetCooldown(CooldownStorageType::iterator& itr, bool update = false); + template<typename Predicate> + void ResetCooldowns(Predicate predicate, bool update = false) + { + std::vector<int32> resetCooldowns; + resetCooldowns.reserve(_spellCooldowns.size()); + for (auto itr = _spellCooldowns.begin(); itr != _spellCooldowns.end();) + { + if (predicate(itr)) + { + resetCooldowns.push_back(itr->first); + ResetCooldown(itr, false); + } + else + ++itr; + } + + if (update && !resetCooldowns.empty()) + SendClearCooldowns(resetCooldowns); + } + + void ResetAllCooldowns(); + bool HasCooldown(uint32 spellId) const; + uint32 GetRemainingCooldown(uint32 spellId) const; + + // School lockouts + void LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTime); + bool IsSchoolLocked(SpellSchoolMask schoolMask) const; + + // Global cooldown + bool HasGlobalCooldown(SpellInfo const* spellInfo) const; + void AddGlobalCooldown(SpellInfo const* spellInfo, uint32 duration); + void CancelGlobalCooldown(SpellInfo const* spellInfo); + + void BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown) const; + + CooldownStorageType::size_type GetCooldownsSizeForPacket() const { return _spellCooldowns.size(); } + +private: + Player* GetPlayerOwner() const; + void SendClearCooldowns(std::vector<int32> const& cooldowns) const; + + typedef std::unordered_map<uint32, uint32> PacketCooldowns; + void BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns) const; + + Unit* _owner; + CooldownStorageType _spellCooldowns; + Clock::time_point _schoolLockouts[MAX_SPELL_SCHOOL]; + GlobalCooldownStorageType _globalCooldowns; + + template<class T> + struct PersistenceHelper { }; +}; + +#endif // SpellHistory_h__ diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index be1384588fb..13290320084 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2954,6 +2954,10 @@ void SpellMgr::LoadSpellInfoCorrections() switch (spellInfo->Id) { + case 63026: // Force Cast (HACK: Target shouldn't be changed) + case 63137: // Force Cast (HACK: Target shouldn't be changed; summon position should be untied from spell destination) + spellInfo->Effects[0].TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB); + break; case 53096: // Quetz'lun's Judgment case 70743: // AoD Special case 70614: // AoD Special - Vegard @@ -3130,6 +3134,7 @@ void SpellMgr::LoadSpellInfoCorrections() case 64823: // Item - Druid T8 Balance 4P Bonus case 34477: // Misdirection case 44401: // Missile Barrage + case 18820: // Insight spellInfo->ProcCharges = 1; break; case 44544: // Fingers of Frost diff --git a/src/server/game/Warden/Warden.h b/src/server/game/Warden/Warden.h index 4d46773adcd..695c6730b27 100644 --- a/src/server/game/Warden/Warden.h +++ b/src/server/game/Warden/Warden.h @@ -57,11 +57,7 @@ enum WardenCheckType MODULE_CHECK = 0xD9 // 217: uint Seed + byte[20] SHA1 (check to ensure module isn't injected) }; -#if defined(__GNUC__) -#pragma pack(1) -#else #pragma pack(push, 1) -#endif struct WardenModuleUse { @@ -84,11 +80,7 @@ struct WardenHashRequest uint8 Seed[16]; }; -#if defined(__GNUC__) -#pragma pack() -#else #pragma pack(pop) -#endif struct ClientWardenModule { diff --git a/src/server/game/Warden/WardenWin.h b/src/server/game/Warden/WardenWin.h index 31d28b22e23..ab6ef7c8c65 100644 --- a/src/server/game/Warden/WardenWin.h +++ b/src/server/game/Warden/WardenWin.h @@ -25,11 +25,7 @@ #include "ByteBuffer.h" #include "Warden.h" -#if defined(__GNUC__) -#pragma pack(1) -#else #pragma pack(push, 1) -#endif struct WardenInitModuleRequest { @@ -61,11 +57,7 @@ struct WardenInitModuleRequest uint8 Function3_set; }; -#if defined(__GNUC__) -#pragma pack() -#else #pragma pack(pop) -#endif class WorldSession; class Warden; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 9a84fa1670d..5f54154fab1 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1523,6 +1523,9 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Gameobject Data..."); sObjectMgr->LoadGameobjects(); + + TC_LOG_INFO("server.loading", "Loading GameObject Addon Data..."); + sObjectMgr->LoadGameObjectAddons(); // must be after LoadGameObjectTemplate() and LoadGameobjects() TC_LOG_INFO("server.loading", "Loading Creature Linked Respawn..."); sObjectMgr->LoadLinkedRespawn(); // must be after LoadCreatures(), LoadGameObjects() diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 0b74eb6bee7..c8a908f6930 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -35,6 +35,7 @@ #include "GroupMgr.h" #include "MMapFactory.h" #include "DisableMgr.h" +#include "SpellHistory.h" class misc_commandscript : public CommandScript { @@ -708,7 +709,7 @@ public: if (!*args) { - target->RemoveAllSpellCooldown(); + target->GetSpellHistory()->ResetAllCooldowns(); handler->PSendSysMessage(LANG_REMOVEALL_COOLDOWN, nameLink.c_str()); } else @@ -718,14 +719,15 @@ public: if (!spellIid) return false; - if (!sSpellMgr->GetSpellInfo(spellIid)) + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellIid); + if (!spellInfo) { handler->PSendSysMessage(LANG_UNKNOWN_SPELL, target == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str()); handler->SetSentErrorMessage(true); return false; } - target->RemoveSpellCooldown(spellIid, true); + target->GetSpellHistory()->ResetCooldown(spellIid, true); handler->PSendSysMessage(LANG_REMOVE_COOLDOWN, spellIid, target == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str()); } return true; @@ -1438,7 +1440,7 @@ public: * Player %s %s (guid: %u) - I. LANG_PINFO_PLAYER * ** GM Mode active, Phase: -1 - II. LANG_PINFO_GM_ACTIVE (if GM) * ** Banned: (Type, Reason, Time, By) - III. LANG_PINFO_BANNED (if banned) - * ** Muted: (Time, Reason, By) - IV. LANG_PINFO_MUTED (if muted) + * ** Muted: (Reason, Time, By) - IV. LANG_PINFO_MUTED (if muted) * * Account: %s (id: %u), GM Level: %u - V. LANG_PINFO_ACC_ACCOUNT * * Last Login: %u (Failed Logins: %u) - VI. LANG_PINFO_ACC_LASTLOGIN * * Uses OS: %s - Latency: %u ms - VII. LANG_PINFO_ACC_OS @@ -1691,7 +1693,7 @@ public: // Output IV. LANG_PINFO_MUTED if mute is applied if (muteTime > 0) - handler->PSendSysMessage(LANG_PINFO_MUTED, secsToTimeString(muteTime - time(NULL), true).c_str(), muteReason.c_str(), muteBy.c_str()); + handler->PSendSysMessage(LANG_PINFO_MUTED, muteReason.c_str(), secsToTimeString(muteTime - time(nullptr), true).c_str(), muteBy.c_str()); // Output V. LANG_PINFO_ACC_ACCOUNT handler->PSendSysMessage(LANG_PINFO_ACC_ACCOUNT, userName.c_str(), accId, security); diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index 4667b7c2767..54d1f314140 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -136,7 +136,7 @@ public: return false; } - Player* target = handler->getSelectedPlayer(); + Player* target = handler->getSelectedPlayerOrSelf(); if (!target) { handler->SendSysMessage(LANG_NO_CHAR_SELECTED); @@ -164,17 +164,6 @@ public: if (!*args) return false; - // char* pmana = strtok((char*)args, " "); - // if (!pmana) - // return false; - - // char* pmanaMax = strtok(NULL, " "); - // if (!pmanaMax) - // return false; - - // int32 manam = atoi(pmanaMax); - // int32 mana = atoi(pmana); - int32 energy = atoi((char*)args)*10; int32 energym = atoi((char*)args)*10; @@ -185,7 +174,7 @@ public: return false; } - Player* target = handler->getSelectedPlayer(); + Player* target = handler->getSelectedPlayerOrSelf(); if (!target) { handler->SendSysMessage(LANG_NO_CHAR_SELECTED); @@ -215,17 +204,6 @@ public: if (!*args) return false; - // char* pmana = strtok((char*)args, " "); - // if (!pmana) - // return false; - - // char* pmanaMax = strtok(NULL, " "); - // if (!pmanaMax) - // return false; - - // int32 manam = atoi(pmanaMax); - // int32 mana = atoi(pmana); - int32 rage = atoi((char*)args)*10; int32 ragem = atoi((char*)args)*10; @@ -236,7 +214,7 @@ public: return false; } - Player* target = handler->getSelectedPlayer(); + Player* target = handler->getSelectedPlayerOrSelf(); if (!target) { handler->SendSysMessage(LANG_NO_CHAR_SELECTED); @@ -274,7 +252,7 @@ public: return false; } - Player* target = handler->getSelectedPlayer(); + Player* target = handler->getSelectedPlayerOrSelf(); if (!target) { handler->SendSysMessage(LANG_NO_CHAR_SELECTED); @@ -390,7 +368,7 @@ public: else mark = atoi(pmark); - Player* target = handler->getSelectedPlayer(); + Player* target = handler->getSelectedPlayerOrSelf(); if (target == NULL) { handler->SendSysMessage(LANG_NO_CHAR_SELECTED); @@ -945,7 +923,7 @@ public: return false; } - Player* target = handler->getSelectedPlayer(); + Player* target = handler->getSelectedPlayerOrSelf(); if (!target) { handler->SendSysMessage(LANG_NO_CHAR_SELECTED); @@ -986,7 +964,7 @@ public: if (!*args) return false; - Player* target = handler->getSelectedPlayer(); + Player* target = handler->getSelectedPlayerOrSelf(); if (!target) { handler->SendSysMessage(LANG_NO_CHAR_SELECTED); @@ -1107,7 +1085,7 @@ public: if (!*args) return false; - Player* target = handler->getSelectedPlayer(); + Player* target = handler->getSelectedPlayerOrSelf(); if (!target) { handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); @@ -1137,7 +1115,7 @@ public: if (drunklevel > 100) drunklevel = 100; - if (Player* target = handler->getSelectedPlayer()) + if (Player* target = handler->getSelectedPlayerOrSelf()) target->SetDrunkValue(drunklevel); return true; @@ -1148,7 +1126,7 @@ public: if (!*args) return false; - Player* target = handler->getSelectedPlayer(); + Player* target = handler->getSelectedPlayerOrSelf(); if (!target) { handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); @@ -1302,7 +1280,7 @@ public: if (!*args) return false; - Player* target = handler->getSelectedPlayer(); + Player* target = handler->getSelectedPlayerOrSelf(); if (!target) { handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); @@ -1324,7 +1302,7 @@ public: if (!*args) return false; - Player* target = handler->getSelectedPlayer(); + Player* target = handler->getSelectedPlayerOrSelf(); if (!target) { diff --git a/src/server/scripts/Kalimdor/zone_winterspring.cpp b/src/server/scripts/Kalimdor/zone_winterspring.cpp index ec1291c6d18..5cb6e78b399 100644 --- a/src/server/scripts/Kalimdor/zone_winterspring.cpp +++ b/src/server/scripts/Kalimdor/zone_winterspring.cpp @@ -377,12 +377,12 @@ public: void DoSummonPriestess() { // Summon 2 Elune priestess and make each of them move to a different spot - if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[0].m_positionX, wingThicketLocations[0].m_positionY, wingThicketLocations[0].m_positionZ, wingThicketLocations[0].m_orientation, TEMPSUMMON_CORPSE_DESPAWN, 0)) + if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[0].m_positionX, wingThicketLocations[0].m_positionY, wingThicketLocations[0].m_positionZ, wingThicketLocations[0].GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0)) { priestess->GetMotionMaster()->MovePoint(0, wingThicketLocations[3].m_positionX, wingThicketLocations[3].m_positionY, wingThicketLocations[3].m_positionZ); _firstPriestessGUID = priestess->GetGUID(); } - if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[1].m_positionX, wingThicketLocations[1].m_positionY, wingThicketLocations[1].m_positionZ, wingThicketLocations[1].m_orientation, TEMPSUMMON_CORPSE_DESPAWN, 0)) + if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[1].m_positionX, wingThicketLocations[1].m_positionY, wingThicketLocations[1].m_positionZ, wingThicketLocations[1].GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0)) { // Left priestess should have a distinct move point because she is the one who starts the dialogue at point reach priestess->GetMotionMaster()->MovePoint(1, wingThicketLocations[4].m_positionX, wingThicketLocations[4].m_positionY, wingThicketLocations[4].m_positionZ); @@ -480,7 +480,7 @@ public: break; case SAY_PRIESTESS_ALTAR_13: // summon the Guardian of Elune - if (Creature* guard = me->SummonCreature(NPC_GUARDIAN_ELUNE, wingThicketLocations[2].m_positionX, wingThicketLocations[2].m_positionY, wingThicketLocations[2].m_positionZ, wingThicketLocations[2].m_orientation, TEMPSUMMON_CORPSE_DESPAWN, 0)) + if (Creature* guard = me->SummonCreature(NPC_GUARDIAN_ELUNE, wingThicketLocations[2].m_positionX, wingThicketLocations[2].m_positionY, wingThicketLocations[2].m_positionZ, wingThicketLocations[2].GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0)) { guard->GetMotionMaster()->MovePoint(0, wingThicketLocations[5].m_positionX, wingThicketLocations[5].m_positionY, wingThicketLocations[5].m_positionZ); _guardEluneGUID = guard->GetGUID(); diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp index 39c9fbe37a6..c56a49cb92c 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp @@ -741,7 +741,7 @@ class boss_dreadscale : public CreatureScript switch (pointId) { case 0: - instance->DoUseDoorOrButton(instance->GetGuidData(GO_MAIN_GATE_DOOR)); + instance->DoCloseDoorOrButton(instance->GetGuidData(GO_MAIN_GATE_DOOR)); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); me->SetReactState(REACT_AGGRESSIVE); me->SetInCombatWithZone(); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp index 15bdedc75db..68430f6f0f7 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp @@ -24,6 +24,7 @@ #include "PassiveAI.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellHistory.h" #include "SpellAuraEffects.h" #include "SpellScript.h" #include "Transport.h" @@ -644,10 +645,10 @@ protected: { if (Instance->GetBossState(DATA_ICECROWN_GUNSHIP_BATTLE) == IN_PROGRESS && !me->HasUnitState(UNIT_STATE_CASTING) && !me->HasReactState(REACT_PASSIVE) && - !me->HasSpellCooldown(BurningPitchId)) + !me->GetSpellHistory()->HasCooldown(BurningPitchId)) { DoCastAOE(BurningPitchId, true); - me->_AddCreatureSpellCooldown(BurningPitchId, time(NULL) + urand(3000, 4000) / IN_MILLISECONDS); + me->GetSpellHistory()->AddCooldown(BurningPitchId, 0, std::chrono::milliseconds(urand(3000, 4000))); } } @@ -1469,7 +1470,7 @@ struct npc_gunship_boarding_addAI : public gunship_npc_AI DoCast(me, SPELL_BATTLE_EXPERIENCE, true); DoCast(me, SPELL_TELEPORT_TO_ENEMY_SHIP, true); DoCast(me, Instance->GetData(DATA_TEAM_IN_INSTANCE) == HORDE ? SPELL_MELEE_TARGETING_ON_ORGRIMS_HAMMER : SPELL_MELEE_TARGETING_ON_SKYBREAKER, true); - me->_AddCreatureSpellCooldown(BurningPitchId, time(NULL) + 3); + me->GetSpellHistory()->AddCooldown(BurningPitchId, 0, std::chrono::seconds(3)); std::list<Player*> players; Trinity::UnitAuraCheck check(true, Instance->GetData(DATA_TEAM_IN_INSTANCE) == HORDE ? SPELL_ON_ORGRIMS_HAMMER_DECK : SPELL_ON_SKYBREAKER_DECK); @@ -1698,11 +1699,11 @@ class npc_gunship_rocketeer : public CreatureScript return; uint32 spellId = me->GetEntry() == NPC_SKYBREAKER_MORTAR_SOLDIER ? SPELL_ROCKET_ARTILLERY_A : SPELL_ROCKET_ARTILLERY_H; - if (me->HasSpellCooldown(spellId)) + if (me->GetSpellHistory()->HasCooldown(spellId)) return; DoCastAOE(spellId, true); - me->_AddCreatureSpellCooldown(spellId, time(NULL) + 9); + me->GetSpellHistory()->AddCooldown(spellId, 0, std::chrono::seconds(9)); } }; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index 60268fc8d87..e908d088554 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -348,7 +348,7 @@ class boss_sindragosa : public CreatureScript events.ScheduleEvent(EVENT_AIR_MOVEMENT, 1); break; case POINT_AIR_PHASE: - me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, RAID_MODE<int32>(2, 5, 2, 6), NULL); + me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, RAID_MODE<int32>(2, 5, 2, 6), NULL, TRIGGERED_FULL_MASK); me->SetFacingTo(float(M_PI)); events.ScheduleEvent(EVENT_AIR_MOVEMENT_FAR, 1); events.ScheduleEvent(EVENT_FROST_BOMB, 9000); @@ -491,7 +491,7 @@ class boss_sindragosa : public CreatureScript if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, FrostBeaconSelector(me))) { Talk(EMOTE_WARN_FROZEN_ORB, target); - DoCast(target, SPELL_ICE_TOMB_DUMMY, true); + me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, 1, nullptr, TRIGGERED_FULL_MASK); } events.ScheduleEvent(EVENT_ICE_TOMB, urand(16000, 23000)); break; @@ -1631,7 +1631,7 @@ void AddSC_boss_sindragosa() new spell_rimefang_icy_blast(); new spell_frostwarden_handler_order_whelp(); new spell_frostwarden_handler_focus_fire(); - new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb", SPELL_ICE_TOMB_DUMMY); + new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb", SPELL_ICE_TOMB_DUMMY, TRIGGERED_IGNORE_SET_FACING); new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb_dummy", SPELL_FROST_BEACON); new at_sindragosa_lair(); new achievement_all_you_can_eat(); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h index 8bf8e5ee6fb..091190b6b4e 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h @@ -524,14 +524,16 @@ enum AreaIds class spell_trigger_spell_from_caster : public SpellScriptLoader { public: - spell_trigger_spell_from_caster(char const* scriptName, uint32 triggerId) : SpellScriptLoader(scriptName), _triggerId(triggerId) { } + spell_trigger_spell_from_caster(char const* scriptName, uint32 triggerId, TriggerCastFlags triggerFlags = TRIGGERED_FULL_MASK) + : SpellScriptLoader(scriptName), _triggerId(triggerId), _triggerFlags(triggerFlags) { } class spell_trigger_spell_from_caster_SpellScript : public SpellScript { PrepareSpellScript(spell_trigger_spell_from_caster_SpellScript); public: - spell_trigger_spell_from_caster_SpellScript(uint32 triggerId) : SpellScript(), _triggerId(triggerId) { } + spell_trigger_spell_from_caster_SpellScript(uint32 triggerId, TriggerCastFlags triggerFlags) + : SpellScript(), _triggerId(triggerId), _triggerFlags(triggerFlags) { } bool Validate(SpellInfo const* /*spell*/) override { @@ -542,7 +544,7 @@ class spell_trigger_spell_from_caster : public SpellScriptLoader void HandleTrigger() { - GetCaster()->CastSpell(GetHitUnit(), _triggerId, true); + GetCaster()->CastSpell(GetHitUnit(), _triggerId, _triggerFlags); } void Register() override @@ -551,15 +553,17 @@ class spell_trigger_spell_from_caster : public SpellScriptLoader } uint32 _triggerId; + TriggerCastFlags _triggerFlags; }; SpellScript* GetSpellScript() const override { - return new spell_trigger_spell_from_caster_SpellScript(_triggerId); + return new spell_trigger_spell_from_caster_SpellScript(_triggerId, _triggerFlags); } private: uint32 _triggerId; + TriggerCastFlags _triggerFlags; }; template<class AI> diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index 6c3b2187325..9c339e596a4 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -128,7 +128,6 @@ enum Spells SPELL_ARCANE_BARRAGE_DAMAGE = 63934, // the actual damage - cast by affected player by script spell // Transition /II-III/ - SPELL_SUMMOM_RED_DRAGON_BUDYY = 56070, SPELL_RIDE_RED_DRAGON_BUDDY = 56071, SPELL_SUMMON_RED_DRAGON_BUDDY_F_CAST = 58846, // After implicitly hit player targets they will force cast 56070 on self SPELL_DESTROY_PLATFORM_CHANNEL = 58842, diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h index b6a0d3f9b62..d9b921b38a1 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h @@ -80,7 +80,8 @@ enum InstanceSpells SPELL_VORTEX_5 = 56263, // damage | used to enter to the vehicle SPELL_PORTAL_OPENED = 61236, SPELL_RIDE_RED_DRAGON_TRIGGERED = 56072, - SPELL_IRIS_OPENED = 61012 // visual when starting encounter + SPELL_IRIS_OPENED = 61012, // visual when starting encounter + SPELL_SUMMOM_RED_DRAGON_BUDDY = 56070 }; #endif diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp index fffdbbc3d1b..7b884f39a41 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp @@ -39,6 +39,12 @@ public: SetBossNumber(MAX_ENCOUNTER); } + void OnPlayerEnter(Player* player) override + { + if (GetBossState(DATA_MALYGOS_EVENT) == DONE) + player->CastSpell(player, SPELL_SUMMOM_RED_DRAGON_BUDDY, true); + } + bool SetBossState(uint32 type, EncounterState state) override { if (!InstanceScript::SetBossState(type, state)) diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp index 23b86737f4c..a04c809f893 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -482,40 +482,47 @@ class boss_flame_leviathan : public CreatureScript if (action && action <= 4) // Tower destruction, debuff leviathan loot and reduce active tower count { if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3 | LOOT_MODE_HARD_MODE_4) && ActiveTowersCount == 4) - { me->RemoveLootMode(LOOT_MODE_HARD_MODE_4); - --ActiveTowersCount; - } + if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3) && ActiveTowersCount == 3) - { me->RemoveLootMode(LOOT_MODE_HARD_MODE_3); - --ActiveTowersCount; - } + if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2) && ActiveTowersCount == 2) - { me->RemoveLootMode(LOOT_MODE_HARD_MODE_2); - --ActiveTowersCount; - } + if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1) && ActiveTowersCount == 1) - { me->RemoveLootMode(LOOT_MODE_HARD_MODE_1); - --ActiveTowersCount; - } } switch (action) { case ACTION_TOWER_OF_STORM_DESTROYED: - towerOfStorms = false; + if (towerOfStorms) + { + towerOfStorms = false; + --ActiveTowersCount; + } break; case ACTION_TOWER_OF_FROST_DESTROYED: - towerOfFrost = false; + if (towerOfFrost) + { + towerOfFrost = false; + --ActiveTowersCount; + } break; case ACTION_TOWER_OF_FLAMES_DESTROYED: - towerOfFlames = false; + if (towerOfFlames) + { + towerOfFlames = false; + --ActiveTowersCount; + } break; case ACTION_TOWER_OF_LIFE_DESTROYED: - towerOfLife = false; + if (towerOfLife) + { + towerOfLife = false; + --ActiveTowersCount; + } break; case ACTION_START_HARD_MODE: // Activate hard-mode enable all towers, apply buffs on leviathan ActiveTowers = true; diff --git a/src/server/scripts/Northrend/zone_dragonblight.cpp b/src/server/scripts/Northrend/zone_dragonblight.cpp index b7efa7c3d3e..dc5b75d425d 100644 --- a/src/server/scripts/Northrend/zone_dragonblight.cpp +++ b/src/server/scripts/Northrend/zone_dragonblight.cpp @@ -174,7 +174,7 @@ class npc_commander_eligor_dawnbringer : public CreatureScript { if (id == 1) { - me->SetFacingTo(PosTalkLocations[talkWing].m_orientation); + me->SetFacingTo(PosTalkLocations[talkWing].GetOrientation()); TurnAudience(); switch (talkWing) diff --git a/src/server/scripts/Northrend/zone_icecrown.cpp b/src/server/scripts/Northrend/zone_icecrown.cpp index 7f29a6621bd..2e426fd77cf 100644 --- a/src/server/scripts/Northrend/zone_icecrown.cpp +++ b/src/server/scripts/Northrend/zone_icecrown.cpp @@ -25,53 +25,6 @@ #include "CombatAI.h" /*###### -## npc_squire_david -######*/ - -enum SquireDavid -{ - QUEST_THE_ASPIRANT_S_CHALLENGE_H = 13680, - QUEST_THE_ASPIRANT_S_CHALLENGE_A = 13679, - - NPC_ARGENT_VALIANT = 33448, - - GOSSIP_TEXTID_SQUIRE = 14407 -}; - -#define GOSSIP_SQUIRE_ITEM_1 "I am ready to fight!" -#define GOSSIP_SQUIRE_ITEM_2 "How do the Argent Crusader raiders fight?" - -class npc_squire_david : public CreatureScript -{ -public: - npc_squire_david() : CreatureScript("npc_squire_david") { } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (player->GetQuestStatus(QUEST_THE_ASPIRANT_S_CHALLENGE_H) == QUEST_STATUS_INCOMPLETE || - player->GetQuestStatus(QUEST_THE_ASPIRANT_S_CHALLENGE_A) == QUEST_STATUS_INCOMPLETE)//We need more info about it. - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SQUIRE_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SQUIRE_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - } - - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_SQUIRE, creature->GetGUID()); - return true; - } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - player->CLOSE_GOSSIP_MENU(); - creature->SummonCreature(NPC_ARGENT_VALIANT, 8575.451f, 952.472f, 547.554f, 0.38f); - } - return true; - } -}; - -/*###### ## npc_argent_valiant ######*/ @@ -837,7 +790,6 @@ class npc_frostbrood_skytalon : public CreatureScript void AddSC_icecrown() { - new npc_squire_david; new npc_argent_valiant; new npc_guardian_pavilion; new npc_tournament_training_dummy; diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp index bb1e88ce158..d5d9f8ae77e 100644 --- a/src/server/scripts/Northrend/zone_storm_peaks.cpp +++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp @@ -19,6 +19,7 @@ #include "ScriptedCreature.h" #include "ScriptedGossip.h" #include "ScriptedEscortAI.h" +#include "SpellHistory.h" #include "SpellScript.h" #include "SpellAuraEffects.h" #include "Vehicle.h" diff --git a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp index 2a568a84a7c..471c776d54b 100644 --- a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp +++ b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp @@ -420,10 +420,483 @@ public: } }; +enum ExorcismSpells +{ + SPELL_JULES_GOES_PRONE = 39283, + SPELL_JULES_THREATENS_AURA = 39284, + SPELL_JULES_GOES_UPRIGHT = 39294, + SPELL_JULES_VOMITS_AURA = 39295, + + SPELL_BARADAS_COMMAND = 39277, + SPELL_BARADA_FALTERS = 39278, +}; + +enum ExorcismTexts +{ + SAY_BARADA_1 = 0, + SAY_BARADA_2 = 1, + SAY_BARADA_3 = 2, + SAY_BARADA_4 = 3, + SAY_BARADA_5 = 4, + SAY_BARADA_6 = 5, + SAY_BARADA_7 = 6, + SAY_BARADA_8 = 7, + + SAY_JULES_1 = 0, + SAY_JULES_2 = 1, + SAY_JULES_3 = 2, + SAY_JULES_4 = 3, + SAY_JULES_5 = 4, +}; + +Position const exorcismPos[11] = +{ + { -707.123f, 2751.686f, 101.592f, 4.577416f }, //Barada Waypoint-1 0 + { -710.731f, 2749.075f, 101.592f, 1.513286f }, //Barada Cast position 1 + { -710.332f, 2754.394f, 102.948f, 3.207566f }, //Jules 2 + { -714.261f, 2747.754f, 103.391f, 0.0f }, //Jules Waypoint-1 3 + { -713.113f, 2750.194f, 103.391f, 0.0f }, //Jules Waypoint-2 4 + { -710.385f, 2750.896f, 103.391f, 0.0f }, //Jules Waypoint-3 5 + { -708.309f, 2750.062f, 103.391f, 0.0f }, //Jules Waypoint-4 6 + { -707.401f, 2747.696f, 103.391f, 0.0f }, //Jules Waypoint-5 7 + { -708.591f, 2745.266f, 103.391f, 0.0f }, //Jules Waypoint-6 8 + { -710.597f, 2744.035f, 103.391f, 0.0f }, //Jules Waypoint-7 9 + { -713.089f, 2745.302f, 103.391f, 0.0f }, //Jules Waypoint-8 10 +}; + +enum ExorcismMisc +{ + NPC_DARKNESS_RELEASED = 22507, + NPC_FOUL_PURGE = 22506, + NPC_COLONEL_JULES = 22432, + + BARADAS_GOSSIP_MESSAGE = 10683, + + QUEST_THE_EXORCISM_OF_COLONEL_JULES = 10935, + + ACTION_START_EVENT = 1, + ACTION_JULES_HOVER = 2, + ACTION_JULES_FLIGHT = 3, + ACTION_JULES_MOVE_HOME = 4, +}; + +enum ExorcismEvents +{ + EVENT_BARADAS_TALK = 1, + + //Colonel Jules + EVENT_SUMMON_SKULL = 1, +}; + +/*###### +## npc_barada +######*/ + +class npc_barada : public CreatureScript +{ +public: + npc_barada() : CreatureScript("npc_barada") { } + + struct npc_baradaAI : public ScriptedAI + { + npc_baradaAI(Creature* creature) : ScriptedAI(creature) + { + Initialize(); + } + + void Initialize() + { + step = 0; + } + + void Reset() override + { + events.Reset(); + Initialize(); + + playerGUID.Clear(); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED); + } + + void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override + { + player->PlayerTalkClass->ClearMenus(); + switch (gossipListId) + { + case 1: + player->PlayerTalkClass->SendCloseGossip(); + me->AI()->Talk(SAY_BARADA_1); + me->AI()->DoAction(ACTION_START_EVENT); + break; + default: + break; + } + } + + void DoAction(int32 action) override + { + if (action == ACTION_START_EVENT) + { + if (Creature* jules = me->FindNearestCreature(NPC_COLONEL_JULES, 20.0f, true)) + { + julesGUID = jules->GetGUID(); + jules->AI()->Talk(SAY_JULES_1); + } + + me->GetMotionMaster()->MovePoint(0, exorcismPos[1]); + Talk(SAY_BARADA_2); + + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED); + } + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE) + return; + + if (id == 0) + me->GetMotionMaster()->MovePoint(1, exorcismPos[1]); + + if (id == 1) + events.ScheduleEvent(EVENT_BARADAS_TALK, 2000); + } + + void JustDied(Unit* /*killer*/) override + { + if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID)) + { + jules->AI()->DoAction(ACTION_JULES_MOVE_HOME); + jules->RemoveAllAuras(); + } + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BARADAS_TALK: + switch (step) + { + case 0: + me->SetFacingTo(1.513286f); + + me->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL); + events.ScheduleEvent(EVENT_BARADAS_TALK, 3000); + step++; + break; + case 1: + DoCast(SPELL_BARADAS_COMMAND); + events.ScheduleEvent(EVENT_BARADAS_TALK, 5000); + step++; + break; + case 2: + Talk(SAY_BARADA_3); + events.ScheduleEvent(EVENT_BARADAS_TALK, 7000); + step++; + break; + case 3: + if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID)) + jules->AI()->Talk(SAY_JULES_2); + + events.ScheduleEvent(EVENT_BARADAS_TALK, 18000); + step++; + break; + case 4: + DoCast(SPELL_BARADA_FALTERS); + me->HandleEmoteCommand(EMOTE_STAND_STATE_NONE); + + if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID)) + jules->AI()->DoAction(ACTION_JULES_HOVER); + + events.ScheduleEvent(EVENT_BARADAS_TALK, 11000); + step++; + break; + case 5: + if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID)) + jules->AI()->Talk(SAY_JULES_3); + + events.ScheduleEvent(EVENT_BARADAS_TALK, 13000); + step++; + break; + case 6: + Talk(SAY_BARADA_4); + events.ScheduleEvent(EVENT_BARADAS_TALK, 5000); + step++; + break; + case 7: + if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID)) + jules->AI()->Talk(SAY_JULES_3); + + events.ScheduleEvent(EVENT_BARADAS_TALK, 13000); + step++; + break; + case 8: + Talk(SAY_BARADA_4); + events.ScheduleEvent(EVENT_BARADAS_TALK, 12000); + step++; + break; + case 9: + if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID)) + jules->AI()->Talk(SAY_JULES_4); + + events.ScheduleEvent(EVENT_BARADAS_TALK, 12000); + step++; + break; + case 10: + Talk(SAY_BARADA_4); + events.ScheduleEvent(EVENT_BARADAS_TALK, 5000); + step++; + break; + case 11: + if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID)) + jules->AI()->DoAction(ACTION_JULES_FLIGHT); + + events.ScheduleEvent(EVENT_BARADAS_TALK, 10000); + step++; + break; + case 12: + if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID)) + jules->AI()->Talk(SAY_JULES_4); + + events.ScheduleEvent(EVENT_BARADAS_TALK, 8000); + step++; + break; + case 13: + Talk(SAY_BARADA_5); + events.ScheduleEvent(EVENT_BARADAS_TALK, 10000); + step++; + break; + case 14: + if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID)) + jules->AI()->Talk(SAY_JULES_4); + + events.ScheduleEvent(EVENT_BARADAS_TALK, 10000); + step++; + break; + case 15: + Talk(SAY_BARADA_6); + events.ScheduleEvent(EVENT_BARADAS_TALK, 10000); + step++; + break; + case 16: + if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID)) + jules->AI()->Talk(SAY_JULES_5); + + events.ScheduleEvent(EVENT_BARADAS_TALK, 10000); + step++; + break; + case 17: + Talk(SAY_BARADA_7); + events.ScheduleEvent(EVENT_BARADAS_TALK, 10000); + step++; + break; + case 18: + if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID)) + jules->AI()->Talk(SAY_JULES_3); + + events.ScheduleEvent(EVENT_BARADAS_TALK, 10000); + step++; + break; + case 19: + Talk(SAY_BARADA_7); + events.ScheduleEvent(EVENT_BARADAS_TALK, 10000); + step++; + break; + case 20: + if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID)) + { + jules->AI()->DoAction(ACTION_JULES_MOVE_HOME); + jules->RemoveAura(SPELL_JULES_VOMITS_AURA); + } + + events.ScheduleEvent(EVENT_BARADAS_TALK, 10000); + step++; + break; + case 21: + //End + if (Player* player = ObjectAccessor::FindPlayer(playerGUID)) + player->KilledMonsterCredit(NPC_COLONEL_JULES, ObjectGuid::Empty); + + if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID)) + jules->RemoveAllAuras(); + + me->RemoveAura(SPELL_BARADAS_COMMAND); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED); + + Talk(SAY_BARADA_8); + me->GetMotionMaster()->MoveTargetedHome(); + EnterEvadeMode(); + break; + } + break; + } + } + } + + private: + EventMap events; + uint8 step; + ObjectGuid julesGUID; + ObjectGuid playerGUID; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_baradaAI(creature); + } +}; + +/*###### +## npc_colonel_jules +######*/ + +class npc_colonel_jules : public CreatureScript +{ +public: + npc_colonel_jules() : CreatureScript("npc_colonel_jules") { } + + struct npc_colonel_julesAI : public ScriptedAI + { + npc_colonel_julesAI(Creature* creature) : ScriptedAI(creature), summons(me) + { + Initialize(); + } + + void Initialize() + { + circleRounds = 0; + point = 0; + } + + void Reset() override + { + events.Reset(); + + summons.DespawnAll(); + circleRounds = 0; + point = 3; + wpreached = false; + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_JULES_HOVER: + me->AddAura(SPELL_JULES_GOES_PRONE, me); + me->AddAura(SPELL_JULES_THREATENS_AURA, me); + + me->SetCanFly(true); + me->SetSpeed(MOVE_RUN, 0.2f); + + me->SetFacingTo(3.207566f); + me->GetMotionMaster()->MoveJump(exorcismPos[2], 2.0f, 2.0f); + + events.ScheduleEvent(EVENT_SUMMON_SKULL, 10000); + break; + case ACTION_JULES_FLIGHT: + circleRounds++; + + me->RemoveAura(SPELL_JULES_GOES_PRONE); + + me->AddAura(SPELL_JULES_GOES_UPRIGHT, me); + me->AddAura(SPELL_JULES_VOMITS_AURA, me); + + wpreached = true; + me->GetMotionMaster()->MovePoint(point, exorcismPos[point]); + break; + case ACTION_JULES_MOVE_HOME: + wpreached = false; + me->SetSpeed(MOVE_RUN, 1.0f); + me->GetMotionMaster()->MovePoint(11, exorcismPos[2]); + + events.CancelEvent(EVENT_SUMMON_SKULL); + break; + } + } + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + summon->GetMotionMaster()->MoveRandom(10.0f); + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE) + return; + + if (id < 10) + wpreached = true; + + if (id == 8) + { + for (uint8 i = 0; i < circleRounds; i++) + DoSummon(NPC_FOUL_PURGE, exorcismPos[8]); + } + + if (id == 10) + { + wpreached = true; + point = 3; + circleRounds++; + } + } + + void UpdateAI(uint32 diff) override + { + if (wpreached) + { + me->GetMotionMaster()->MovePoint(point, exorcismPos[point]); + point++; + wpreached = false; + } + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SUMMON_SKULL: + uint8 summonCount = urand(1,3); + + for (uint8 i = 0; i < summonCount; i++) + me->SummonCreature(NPC_DARKNESS_RELEASED, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 1.5f, 0, TEMPSUMMON_MANUAL_DESPAWN); + + events.ScheduleEvent(EVENT_SUMMON_SKULL, urand(10000, 15000)); + break; + } + } + } + + private: + EventMap events; + SummonList summons; + + uint8 circleRounds; + uint8 point; + + bool wpreached; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_colonel_julesAI(creature); + } +}; + void AddSC_hellfire_peninsula() { new npc_aeranas(); new npc_ancestral_wolf(); new npc_wounded_blood_elf(); new npc_fel_guard_hound(); + new npc_barada(); + new npc_colonel_jules(); } diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 993e64f22dc..68c115f9faf 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -34,6 +34,7 @@ #include "Pet.h" #include "ReputationMgr.h" #include "SkillDiscovery.h" +#include "SpellHistory.h" #include "SpellScript.h" #include "SpellAuraEffects.h" #include "Vehicle.h" @@ -1293,8 +1294,8 @@ class spell_gen_divine_storm_cd_reset : public SpellScriptLoader void HandleScript(SpellEffIndex /*effIndex*/) { Player* caster = GetCaster()->ToPlayer(); - if (caster->HasSpellCooldown(SPELL_DIVINE_STORM)) - caster->RemoveSpellCooldown(SPELL_DIVINE_STORM, true); + if (caster->GetSpellHistory()->HasCooldown(SPELL_DIVINE_STORM)) + caster->GetSpellHistory()->ResetCooldown(SPELL_DIVINE_STORM, true); } void Register() override @@ -3330,7 +3331,7 @@ class spell_pvp_trinket_wotf_shared_cd : public SpellScriptLoader { // This is only needed because spells cast from spell_linked_spell are triggered by default // Spell::SendSpellCooldown() skips all spells with TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD - GetCaster()->ToPlayer()->AddSpellAndCategoryCooldowns(GetSpellInfo(), GetCastItem() ? GetCastItem()->GetEntry() : 0, GetSpell()); + GetCaster()->GetSpellHistory()->StartCooldown(GetSpellInfo(), 0, GetSpell()); } void Register() override diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index 3ee337f81d4..75df264360f 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -27,6 +27,7 @@ #include "CellImpl.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" +#include "SpellHistory.h" #include "SpellScript.h" #include "SpellAuraEffects.h" @@ -246,7 +247,7 @@ class spell_hun_chimera_shot : public SpellScriptLoader if (spellId) caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, true); if (spellId == SPELL_HUNTER_CHIMERA_SHOT_SCORPID && caster->ToPlayer()) // Scorpid Sting - Add 1 minute cooldown - caster->ToPlayer()->AddSpellCooldown(spellId, 0, uint32(time(NULL) + 60)); + caster->GetSpellHistory()->AddCooldown(spellId, 0, std::chrono::minutes(1)); } } @@ -654,24 +655,20 @@ class spell_hun_readiness : public SpellScriptLoader void HandleDummy(SpellEffIndex /*effIndex*/) { - Player* caster = GetCaster()->ToPlayer(); // immediately finishes the cooldown on your other Hunter abilities except Bestial Wrath - const SpellCooldowns& cm = caster->ToPlayer()->GetSpellCooldownMap(); - for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();) + GetCaster()->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); ///! If spellId in cooldown map isn't valid, the above will return a null pointer. - if (spellInfo && - spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && + if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != SPELL_HUNTER_READINESS && spellInfo->Id != SPELL_HUNTER_BESTIAL_WRATH && spellInfo->Id != SPELL_DRAENEI_GIFT_OF_THE_NAARU && spellInfo->GetRecoveryTime() > 0) - caster->RemoveSpellCooldown((itr++)->first, true); - else - ++itr; - } + return true; + return false; + }, true); } void Register() override diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index b290cb75a2b..717382a0e36 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -24,6 +24,7 @@ #include "Player.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellHistory.h" #include "SpellScript.h" #include "SpellAuraEffects.h" #include "SkillDiscovery.h" @@ -1349,7 +1350,7 @@ class spell_item_red_rider_air_rifle : public SpellScriptLoader caster->CastSpell(caster, SPELL_AIR_RIFLE_HOLD_VISUAL, true); // needed because this spell shares GCD with its triggered spells (which must not be cast with triggered flag) if (Player* player = caster->ToPlayer()) - player->GetGlobalCooldownMgr().CancelGlobalCooldown(GetSpellInfo()); + player->GetSpellHistory()->CancelGlobalCooldown(GetSpellInfo()); if (urand(0, 4)) caster->CastSpell(target, SPELL_AIR_RIFLE_SHOOT, false); else @@ -2368,7 +2369,7 @@ class spell_item_rocket_boots : public SpellScriptLoader if (Battleground* bg = caster->GetBattleground()) bg->EventPlayerDroppedFlag(caster); - caster->RemoveSpellCooldown(SPELL_ROCKET_BOOTS_PROC); + caster->GetSpellHistory()->ResetCooldown(SPELL_ROCKET_BOOTS_PROC); caster->CastSpell(caster, SPELL_ROCKET_BOOTS_PROC, true, NULL); } @@ -2548,14 +2549,14 @@ class spell_item_refocus : public SpellScriptLoader if (!caster || caster->getClass() != CLASS_HUNTER) return; - if (caster->HasSpellCooldown(SPELL_AIMED_SHOT)) - caster->RemoveSpellCooldown(SPELL_AIMED_SHOT, true); + if (caster->GetSpellHistory()->HasCooldown(SPELL_AIMED_SHOT)) + caster->GetSpellHistory()->ResetCooldown(SPELL_AIMED_SHOT, true); - if (caster->HasSpellCooldown(SPELL_MULTISHOT)) - caster->RemoveSpellCooldown(SPELL_MULTISHOT, true); + if (caster->GetSpellHistory()->HasCooldown(SPELL_MULTISHOT)) + caster->GetSpellHistory()->ResetCooldown(SPELL_MULTISHOT, true); - if (caster->HasSpellCooldown(SPELL_VOLLEY)) - caster->RemoveSpellCooldown(SPELL_VOLLEY, true); + if (caster->GetSpellHistory()->HasCooldown(SPELL_VOLLEY)) + caster->GetSpellHistory()->ResetCooldown(SPELL_VOLLEY, true); } void Register() override diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index ba9f66d255b..4edbf8822f7 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -23,6 +23,7 @@ #include "Player.h" #include "ScriptMgr.h" +#include "SpellHistory.h" #include "SpellScript.h" #include "SpellAuraEffects.h" @@ -171,22 +172,12 @@ class spell_mage_cold_snap : public SpellScriptLoader void HandleDummy(SpellEffIndex /*effIndex*/) { - Player* caster = GetCaster()->ToPlayer(); - // immediately finishes the cooldown on Frost spells - const SpellCooldowns& cm = caster->GetSpellCooldownMap(); - for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();) + GetCaster()->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool { SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); - - if (spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && - (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) && - spellInfo->Id != SPELL_MAGE_COLD_SNAP && spellInfo->GetRecoveryTime() > 0) - { - caster->RemoveSpellCooldown((itr++)->first, true); - } - else - ++itr; - } + return spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) && + spellInfo->Id != SPELL_MAGE_COLD_SNAP && spellInfo->GetRecoveryTime() > 0; + }, true); } void Register() override diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index cf320a05346..197d55486a8 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -25,6 +25,7 @@ #include "ScriptMgr.h" #include "SpellScript.h" #include "SpellAuraEffects.h" +#include "SpellHistory.h" #include "Group.h" enum PaladinSpells @@ -133,7 +134,7 @@ class spell_pal_ardent_defender : public SpellScriptLoader int32 remainingHealth = victim->GetHealth() - dmgInfo.GetDamage(); uint32 allowedHealth = victim->CountPctFromMaxHealth(35); // If damage kills us - if (remainingHealth <= 0 && !victim->ToPlayer()->HasSpellCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL)) + if (remainingHealth <= 0 && !victim->GetSpellHistory()->HasCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL)) { // Cast healing spell, completely avoid damage absorbAmount = dmgInfo.GetDamage(); @@ -148,7 +149,7 @@ class spell_pal_ardent_defender : public SpellScriptLoader int32 healAmount = int32(victim->CountPctFromMaxHealth(uint32(healPct * pctFromDefense))); victim->CastCustomSpell(victim, PAL_SPELL_ARDENT_DEFENDER_HEAL, &healAmount, NULL, NULL, true, NULL, aurEff); - victim->ToPlayer()->AddSpellCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL, 0, time(NULL) + 120); + victim->GetSpellHistory()->AddCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL, 0, std::chrono::minutes(2)); } else if (remainingHealth < int32(allowedHealth)) { diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index d98ef2ec799..0ec8bfc3a9c 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -208,22 +208,23 @@ class spell_q6124_6129_apply_salve : public SpellScriptLoader if (GetCastItem()) if (Creature* creatureTarget = GetHitCreature()) { - uint32 uiNewEntry = 0; + uint32 newEntry = 0; switch (caster->GetTeam()) { case HORDE: if (creatureTarget->GetEntry() == NPC_SICKLY_GAZELLE) - uiNewEntry = NPC_CURED_GAZELLE; + newEntry = NPC_CURED_GAZELLE; break; case ALLIANCE: if (creatureTarget->GetEntry() == NPC_SICKLY_DEER) - uiNewEntry = NPC_CURED_DEER; + newEntry = NPC_CURED_DEER; break; } - if (uiNewEntry) + if (newEntry) { - creatureTarget->UpdateEntry(uiNewEntry); + creatureTarget->UpdateEntry(newEntry); creatureTarget->DespawnOrUnsummon(DESPAWN_TIME); + caster->KilledMonsterCredit(newEntry); } } } diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index edb5cd5260c..da50f471f1c 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -25,6 +25,7 @@ #include "ScriptMgr.h" #include "SpellScript.h" #include "SpellAuraEffects.h" +#include "SpellHistory.h" #include "Containers.h" enum RogueSpells @@ -139,11 +140,11 @@ class spell_rog_cheat_death : public SpellScriptLoader void Absorb(AuraEffect* /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount) { Player* target = GetTarget()->ToPlayer(); - if (dmgInfo.GetDamage() < target->GetHealth() || target->HasSpellCooldown(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN) || !roll_chance_i(absorbChance)) + if (dmgInfo.GetDamage() < target->GetHealth() || target->GetSpellHistory()->HasCooldown(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN) || !roll_chance_i(absorbChance)) return; target->CastSpell(target, SPELL_ROGUE_CHEAT_DEATH_COOLDOWN, true); - target->AddSpellCooldown(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN, 0, time(NULL) + 60); + target->GetSpellHistory()->AddCooldown(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN, 0, std::chrono::minutes(1)); uint32 health10 = target->CountPctFromMaxHealth(10); @@ -443,35 +444,21 @@ class spell_rog_preparation : public SpellScriptLoader void HandleDummy(SpellEffIndex /*effIndex*/) { - Player* caster = GetCaster()->ToPlayer(); - - //immediately finishes the cooldown on certain Rogue abilities - const SpellCooldowns& cm = caster->GetSpellCooldownMap(); - for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();) + Unit* caster = GetCaster(); + caster->GetSpellHistory()->ResetCooldowns([caster](SpellHistory::CooldownStorageType::iterator itr) -> bool { SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); - - if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE) - { - if (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_COLDB_SHADOWSTEP || // Cold Blood, Shadowstep - spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VAN_EVAS_SPRINT) // Vanish, Evasion, Sprint - caster->RemoveSpellCooldown((itr++)->first, true); - else if (caster->HasAura(SPELL_ROGUE_GLYPH_OF_PREPARATION)) - { - if (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_DISMANTLE || // Dismantle - spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_KICK || // Kick - (spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_BLADE_FLURRY && // Blade Flurry - spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_BLADE_FLURRY)) - caster->RemoveSpellCooldown((itr++)->first, true); - else - ++itr; - } - else - ++itr; - } - else - ++itr; - } + if (spellInfo->SpellFamilyName != SPELLFAMILY_ROGUE) + return false; + + return (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_COLDB_SHADOWSTEP || // Cold Blood, Shadowstep + spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VAN_EVAS_SPRINT) || // Vanish, Evasion, Sprint + (caster->HasAura(SPELL_ROGUE_GLYPH_OF_PREPARATION) && + (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_DISMANTLE || // Dismantle + spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_KICK || // Kick + (spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_BLADE_FLURRY && // Blade Flurry + spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_BLADE_FLURRY))); + }, true); } void Register() override diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 2ee0d5091b5..5564a8275c8 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -25,6 +25,7 @@ #include "ScriptMgr.h" #include "GridNotifiers.h" #include "Unit.h" +#include "SpellHistory.h" #include "SpellScript.h" #include "SpellAuraEffects.h" @@ -338,7 +339,7 @@ class spell_sha_earth_shield : public SpellScriptLoader { //! HACK due to currenct proc system implementation if (Player* player = GetTarget()->ToPlayer()) - if (player->HasSpellCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL)) + if (player->GetSpellHistory()->HasCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL)) return false; return true; } @@ -351,7 +352,7 @@ class spell_sha_earth_shield : public SpellScriptLoader /// @hack: due to currenct proc system implementation if (Player* player = GetTarget()->ToPlayer()) - player->AddSpellCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL, 0, time(NULL) + 3); + player->GetSpellHistory()->AddCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL, 0, std::chrono::seconds(3)); } void Register() override @@ -804,7 +805,7 @@ class spell_sha_item_t10_elemental_2p_bonus : public SpellScriptLoader { PreventDefaultAction(); if (Player* target = GetTarget()->ToPlayer()) - target->ModifySpellCooldown(SPELL_SHAMAN_ELEMENTAL_MASTERY, -aurEff->GetAmount()); + target->GetSpellHistory()->ModifyCooldown(SPELL_SHAMAN_ELEMENTAL_MASTERY, -aurEff->GetAmount()); } void Register() override diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index fa2b323e220..c7839a59608 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -23,6 +23,7 @@ #include "Player.h" #include "ScriptMgr.h" +#include "SpellHistory.h" #include "SpellScript.h" #include "SpellAuraEffects.h" @@ -847,7 +848,7 @@ class spell_warr_vigilance_trigger : public SpellScriptLoader // Remove Taunt cooldown if (Player* target = GetHitPlayer()) - target->RemoveSpellCooldown(SPELL_WARRIOR_TAUNT, true); + target->GetSpellHistory()->ResetCooldown(SPELL_WARRIOR_TAUNT, true); } void Register() override diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 93010f06283..d1d2ddc8a80 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -53,6 +53,7 @@ EndContentData */ #include "GridNotifiersImpl.h" #include "Cell.h" #include "CellImpl.h" +#include "SpellHistory.h" #include "SpellAuras.h" #include "Pet.h" #include "CreatureTextMgr.h" @@ -1214,14 +1215,14 @@ public: if (creature->IsQuestGiver()) player->PrepareQuestMenu(creature->GetGUID()); - if (player->HasSpellCooldown(SPELL_INT) || - player->HasSpellCooldown(SPELL_ARM) || - player->HasSpellCooldown(SPELL_DMG) || - player->HasSpellCooldown(SPELL_RES) || - player->HasSpellCooldown(SPELL_STR) || - player->HasSpellCooldown(SPELL_AGI) || - player->HasSpellCooldown(SPELL_STM) || - player->HasSpellCooldown(SPELL_SPI)) + if (player->GetSpellHistory()->HasCooldown(SPELL_INT) || + player->GetSpellHistory()->HasCooldown(SPELL_ARM) || + player->GetSpellHistory()->HasCooldown(SPELL_DMG) || + player->GetSpellHistory()->HasCooldown(SPELL_RES) || + player->GetSpellHistory()->HasCooldown(SPELL_STR) || + player->GetSpellHistory()->HasCooldown(SPELL_AGI) || + player->GetSpellHistory()->HasCooldown(SPELL_STM) || + player->GetSpellHistory()->HasCooldown(SPELL_SPI)) player->SEND_GOSSIP_MENU(7393, creature->GetGUID()); else { @@ -1281,52 +1282,44 @@ public: bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) override { player->PlayerTalkClass->ClearMenus(); + uint32 spellId = 0; switch (sender) { case GOSSIP_SENDER_MAIN: SendAction(player, creature, action); break; case GOSSIP_SENDER_MAIN + 1: - creature->CastSpell(player, SPELL_DMG, false); - player->AddSpellCooldown(SPELL_DMG, 0, time(NULL) + 7200); - SendAction(player, creature, action); + spellId = SPELL_DMG; break; case GOSSIP_SENDER_MAIN + 2: - creature->CastSpell(player, SPELL_RES, false); - player->AddSpellCooldown(SPELL_RES, 0, time(NULL) + 7200); - SendAction(player, creature, action); + spellId = SPELL_RES; break; case GOSSIP_SENDER_MAIN + 3: - creature->CastSpell(player, SPELL_ARM, false); - player->AddSpellCooldown(SPELL_ARM, 0, time(NULL) + 7200); - SendAction(player, creature, action); + spellId = SPELL_ARM; break; case GOSSIP_SENDER_MAIN + 4: - creature->CastSpell(player, SPELL_SPI, false); - player->AddSpellCooldown(SPELL_SPI, 0, time(NULL) + 7200); - SendAction(player, creature, action); + spellId = SPELL_SPI; break; case GOSSIP_SENDER_MAIN + 5: - creature->CastSpell(player, SPELL_INT, false); - player->AddSpellCooldown(SPELL_INT, 0, time(NULL) + 7200); - SendAction(player, creature, action); + spellId = SPELL_INT; break; case GOSSIP_SENDER_MAIN + 6: - creature->CastSpell(player, SPELL_STM, false); - player->AddSpellCooldown(SPELL_STM, 0, time(NULL) + 7200); - SendAction(player, creature, action); + spellId = SPELL_STM; break; case GOSSIP_SENDER_MAIN + 7: - creature->CastSpell(player, SPELL_STR, false); - player->AddSpellCooldown(SPELL_STR, 0, time(NULL) + 7200); - SendAction(player, creature, action); + spellId = SPELL_STR; break; case GOSSIP_SENDER_MAIN + 8: - creature->CastSpell(player, SPELL_AGI, false); - player->AddSpellCooldown(SPELL_AGI, 0, time(NULL) + 7200); - SendAction(player, creature, action); + spellId = SPELL_AGI; break; } + + if (spellId) + { + creature->CastSpell(player, spellId, false); + player->GetSpellHistory()->AddCooldown(spellId, 0, std::chrono::hours(2)); + SendAction(player, creature, action); + } return true; } }; diff --git a/src/server/shared/Database/Field.h b/src/server/shared/Database/Field.h index b88fb56cb06..1bbd264482f 100644 --- a/src/server/shared/Database/Field.h +++ b/src/server/shared/Database/Field.h @@ -255,11 +255,7 @@ class Field Field(); ~Field(); - #if defined(__GNUC__) - #pragma pack(1) - #else #pragma pack(push, 1) - #endif struct { uint32 length; // Length (prepared strings only) @@ -267,11 +263,7 @@ class Field enum_field_types type; // Field type bool raw; // Raw bytes? (Prepared statement or ad hoc) } data; - #if defined(__GNUC__) - #pragma pack() - #else #pragma pack(pop) - #endif void SetByteValue(void const* newValue, size_t const newSize, enum_field_types newType, uint32 length); void SetStructuredValue(char* newValue, enum_field_types newType); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index c8632b8a3c2..1ca01501d01 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -105,7 +105,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_MAIL_COUNT, "SELECT COUNT(*) FROM mail WHERE receiver = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHARACTER_SOCIALLIST, "SELECT friend, flags, note FROM character_social JOIN characters ON characters.guid = character_social.friend WHERE character_social.guid = ? AND deleteinfos_name IS NULL LIMIT 255", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ FROM character_homebind WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, "SELECT spell, item, time FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, "SELECT spell, item, time FROM character_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_GUILD_MEMBER, "SELECT guildid, rank FROM guild_member WHERE guid = ?", CONNECTION_BOTH); PrepareStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED, "SELECT g.guildid, g.name, gr.rname, gr.rid, gm.pnote, gm.offnote " @@ -497,7 +497,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_CHAR_REP_FACTION_CHANGE, "UPDATE character_reputation SET faction = ?, standing = ? WHERE faction = ? AND guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_TITLES_FACTION_CHANGE, "UPDATE characters SET knownTitles = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_RES_CHAR_TITLES_FACTION_CHANGE, "UPDATE characters SET chosenTitle = 0 WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN, "DELETE FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_SPELL_COOLDOWNS, "DELETE FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_SPELL_COOLDOWN, "INSERT INTO character_spell_cooldown (guid, spell, item, time) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHARACTER, "DELETE FROM characters WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_ACTION, "DELETE FROM character_action WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_AURA, "DELETE FROM character_aura WHERE guid = ?", CONNECTION_ASYNC); @@ -577,7 +578,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_INS_CHAR_PET_DECLINEDNAME, "INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_PET_AURA, "SELECT caster_guid, spell, effect_mask, recalculate_mask, stackcount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, maxduration, remaintime, remaincharges FROM pet_aura WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_PET_SPELL, "SELECT spell, active FROM pet_spell WHERE guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_PET_SPELL_COOLDOWN, "SELECT spell, time FROM pet_spell_cooldown WHERE guid = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_PET_SPELL_COOLDOWN, "SELECT spell, time FROM pet_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_PET_DECLINED_NAME, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_pet_declinedname WHERE owner = ? AND id = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_PET_AURAS, "DELETE FROM pet_aura WHERE guid = ?", CONNECTION_BOTH); PrepareStatement(CHAR_DEL_PET_SPELLS, "DELETE FROM pet_spell WHERE guid = ?", CONNECTION_ASYNC); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index e56a24d6865..f88a912e022 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -436,7 +436,8 @@ enum CharacterDatabaseStatements CHAR_UPD_CHAR_REP_FACTION_CHANGE, CHAR_UPD_CHAR_TITLES_FACTION_CHANGE, CHAR_RES_CHAR_TITLES_FACTION_CHANGE, - CHAR_DEL_CHAR_SPELL_COOLDOWN, + CHAR_DEL_CHAR_SPELL_COOLDOWNS, + CHAR_INS_CHAR_SPELL_COOLDOWN, CHAR_DEL_CHARACTER, CHAR_DEL_CHAR_ACTION, CHAR_DEL_CHAR_AURA, diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp index f8f641a9ea7..e50cf42e439 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.cpp +++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp @@ -61,6 +61,7 @@ HANDLE WheatyExceptionReport::m_hDumpFile; HANDLE WheatyExceptionReport::m_hProcess; SymbolPairs WheatyExceptionReport::symbols; std::stack<SymbolDetail> WheatyExceptionReport::symbolDetails; +bool WheatyExceptionReport::stackOverflowException; // Declare global instance of class WheatyExceptionReport g_WheatyExceptionReport; @@ -72,6 +73,7 @@ WheatyExceptionReport::WheatyExceptionReport() // Constructor // Install the unhandled exception filter function m_previousFilter = SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter); m_hProcess = GetCurrentProcess(); + stackOverflowException = false; if (!IsDebuggerPresent()) { _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); @@ -97,6 +99,9 @@ WheatyExceptionReport::~WheatyExceptionReport() LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter( PEXCEPTION_POINTERS pExceptionInfo) { + if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) + stackOverflowException = true; + TCHAR module_folder_name[MAX_PATH]; GetModuleFileName(0, module_folder_name, MAX_PATH); TCHAR* pos = _tcsrchr(module_folder_name, '\\'); @@ -419,107 +424,114 @@ void WheatyExceptionReport::printTracesForAllThreads(bool bWriteVariables) void WheatyExceptionReport::GenerateExceptionReport( PEXCEPTION_POINTERS pExceptionInfo) { - SYSTEMTIME systime; - GetLocalTime(&systime); - - // Start out with a banner - _tprintf(_T("Revision: %s\r\n"), _FULLVERSION); - _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute); - PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord; - - PrintSystemInfo(); - // First print information about the type of fault - _tprintf(_T("\r\n//=====================================================\r\n")); - _tprintf(_T("Exception code: %08X %s\r\n"), - pExceptionRecord->ExceptionCode, - GetExceptionString(pExceptionRecord->ExceptionCode)); - - // Now print information about where the fault occured - TCHAR szFaultingModule[MAX_PATH]; - DWORD section; - DWORD_PTR offset; - GetLogicalAddress(pExceptionRecord->ExceptionAddress, - szFaultingModule, - sizeof(szFaultingModule), - section, offset); + __try + { + SYSTEMTIME systime; + GetLocalTime(&systime); + + // Start out with a banner + _tprintf(_T("Revision: %s\r\n"), _FULLVERSION); + _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute); + PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord; + + PrintSystemInfo(); + // First print information about the type of fault + _tprintf(_T("\r\n//=====================================================\r\n")); + _tprintf(_T("Exception code: %08X %s\r\n"), + pExceptionRecord->ExceptionCode, + GetExceptionString(pExceptionRecord->ExceptionCode)); + + // Now print information about where the fault occured + TCHAR szFaultingModule[MAX_PATH]; + DWORD section; + DWORD_PTR offset; + GetLogicalAddress(pExceptionRecord->ExceptionAddress, + szFaultingModule, + sizeof(szFaultingModule), + section, offset); #ifdef _M_IX86 - _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"), - pExceptionRecord->ExceptionAddress, - section, offset, szFaultingModule); + _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"), + pExceptionRecord->ExceptionAddress, + section, offset, szFaultingModule); #endif #ifdef _M_X64 - _tprintf(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"), - pExceptionRecord->ExceptionAddress, - section, offset, szFaultingModule); + _tprintf(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"), + pExceptionRecord->ExceptionAddress, + section, offset, szFaultingModule); #endif - PCONTEXT pCtx = pExceptionInfo->ContextRecord; + PCONTEXT pCtx = pExceptionInfo->ContextRecord; - // Show the registers - #ifdef _M_IX86 // X86 Only! - _tprintf(_T("\r\nRegisters:\r\n")); + // Show the registers +#ifdef _M_IX86 // X86 Only! + _tprintf(_T("\r\nRegisters:\r\n")); - _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n") - , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx, - pCtx->Esi, pCtx->Edi); + _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n") + , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx, + pCtx->Esi, pCtx->Edi); - _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip); - _tprintf(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"), - pCtx->SegSs, pCtx->Esp, pCtx->Ebp); - _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), - pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); - _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); - #endif + _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip); + _tprintf(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"), + pCtx->SegSs, pCtx->Esp, pCtx->Ebp); + _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), + pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); + _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); +#endif - #ifdef _M_X64 - _tprintf(_T("\r\nRegisters:\r\n")); - _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n") - _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n") - , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx, - pCtx->Rsi, pCtx->Rdi, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15); - _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip); - _tprintf(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"), - pCtx->SegSs, pCtx->Rsp, pCtx->Rbp); - _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), - pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); - _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); - #endif +#ifdef _M_X64 + _tprintf(_T("\r\nRegisters:\r\n")); + _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n") + _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n") + , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx, + pCtx->Rsi, pCtx->Rdi, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15); + _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip); + _tprintf(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"), + pCtx->SegSs, pCtx->Rsp, pCtx->Rbp); + _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), + pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); + _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); +#endif - SymSetOptions(SYMOPT_DEFERRED_LOADS); + SymSetOptions(SYMOPT_DEFERRED_LOADS); - // Initialize DbgHelp - if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) - { - _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"), - ErrorMessage(GetLastError())); - } + // Initialize DbgHelp + if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) + { + _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"), + ErrorMessage(GetLastError())); + } - CONTEXT trashableContext = *pCtx; + CONTEXT trashableContext = *pCtx; - WriteStackDetails(&trashableContext, false, NULL); - printTracesForAllThreads(false); + WriteStackDetails(&trashableContext, false, NULL); + printTracesForAllThreads(false); -// #ifdef _M_IX86 // X86 Only! + // #ifdef _M_IX86 // X86 Only! - _tprintf(_T("========================\r\n")); - _tprintf(_T("Local Variables And Parameters\r\n")); + _tprintf(_T("========================\r\n")); + _tprintf(_T("Local Variables And Parameters\r\n")); - trashableContext = *pCtx; - WriteStackDetails(&trashableContext, true, NULL); - printTracesForAllThreads(true); + trashableContext = *pCtx; + WriteStackDetails(&trashableContext, true, NULL); + printTracesForAllThreads(true); - /*_tprintf(_T("========================\r\n")); - _tprintf(_T("Global Variables\r\n")); + /*_tprintf(_T("========================\r\n")); + _tprintf(_T("Global Variables\r\n")); - SymEnumSymbols(GetCurrentProcess(), + SymEnumSymbols(GetCurrentProcess(), (UINT_PTR)GetModuleHandle(szFaultingModule), 0, EnumerateSymbolsCallback, 0);*/ - // #endif // X86 Only! + // #endif // X86 Only! - SymCleanup(GetCurrentProcess()); + SymCleanup(GetCurrentProcess()); - _tprintf(_T("\r\n")); + _tprintf(_T("\r\n")); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + _tprintf(_T("Error writing the crash log\r\n")); + } } //====================================================================== @@ -1313,16 +1325,43 @@ DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer(DWORD_PTR address) //============================================================================ int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...) { - TCHAR szBuff[WER_LARGE_BUFFER_SIZE]; int retValue; - DWORD cbWritten; va_list argptr; - va_start(argptr, format); + if (stackOverflowException) + { + retValue = heapprintf(format, argptr); + va_end(argptr); + } + else + { + retValue = stackprintf(format, argptr); + va_end(argptr); + } + + return retValue; +} + +int __cdecl WheatyExceptionReport::stackprintf(const TCHAR * format, va_list argptr) +{ + int retValue; + DWORD cbWritten; + + TCHAR szBuff[WER_LARGE_BUFFER_SIZE]; retValue = vsprintf(szBuff, format, argptr); - va_end(argptr); + WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0); + return retValue; +} + +int __cdecl WheatyExceptionReport::heapprintf(const TCHAR * format, va_list argptr) +{ + int retValue; + DWORD cbWritten; + TCHAR* szBuff = (TCHAR*)malloc(sizeof(TCHAR) * WER_LARGE_BUFFER_SIZE); + retValue = vsprintf(szBuff, format, argptr); WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0); + free(szBuff); return retValue; } diff --git a/src/server/shared/Debugging/WheatyExceptionReport.h b/src/server/shared/Debugging/WheatyExceptionReport.h index b7731daaa2b..101b6187f2b 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.h +++ b/src/server/shared/Debugging/WheatyExceptionReport.h @@ -178,6 +178,8 @@ class WheatyExceptionReport static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address); static int __cdecl _tprintf(const TCHAR * format, ...); + static int __cdecl stackprintf(const TCHAR * format, va_list argptr); + static int __cdecl heapprintf(const TCHAR * format, va_list argptr); static bool StoreSymbol(DWORD type , DWORD_PTR offset); static void ClearSymbols(); @@ -191,6 +193,7 @@ class WheatyExceptionReport static HANDLE m_hProcess; static SymbolPairs symbols; static std::stack<SymbolDetail> symbolDetails; + static bool stackOverflowException; static char* PushSymbolDetail(char* pszCurrBuffer); static char* PopSymbolDetail(char* pszCurrBuffer); diff --git a/src/server/shared/Networking/MessageBuffer.h b/src/server/shared/Networking/MessageBuffer.h index 90afaf35796..95e26974626 100644 --- a/src/server/shared/Networking/MessageBuffer.h +++ b/src/server/shared/Networking/MessageBuffer.h @@ -55,9 +55,9 @@ public: uint8* GetBasePointer() { return _storage.data(); } - uint8* GetReadPointer() { return &_storage[_rpos]; } + uint8* GetReadPointer() { return GetBasePointer() + _rpos; } - uint8* GetWritePointer() { return &_storage[_wpos]; } + uint8* GetWritePointer() { return GetBasePointer() + _wpos; } void ReadCompleted(size_type bytes) { _rpos += bytes; } |