aboutsummaryrefslogtreecommitdiff
path: root/src/server/game
diff options
context:
space:
mode:
authorShocker <shocker@freakz.ro>2013-02-10 20:21:18 +0200
committerShocker <shocker@freakz.ro>2013-02-10 20:21:18 +0200
commita0cb102538dae7fa2d173b4d1990a4aef8e5d55c (patch)
tree65d0903a31cae86467f7551653ef6f1c743cde9e /src/server/game
parent82f7b337b2dafd16506033cdbfecc979bc6f7119 (diff)
parent984e1feadfae97c7616c54f9ac731cc6db4f2e15 (diff)
Merge branch '4.3.4' of https://github.com/TrinityCore/TrinityCore into 4.3.4
Diffstat (limited to 'src/server/game')
-rw-r--r--src/server/game/AI/CoreAI/PetAI.cpp35
-rw-r--r--src/server/game/AI/CoreAI/ReactorAI.cpp23
-rw-r--r--src/server/game/AI/CoreAI/ReactorAI.h4
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.cpp11
-rw-r--r--src/server/game/AI/CreatureAIImpl.h330
-rw-r--r--src/server/game/AI/CreatureAISelector.cpp6
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.cpp19
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.h18
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp11
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp122
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h8
-rw-r--r--src/server/game/Accounts/AccountMgr.cpp225
-rw-r--r--src/server/game/Accounts/AccountMgr.h27
-rw-r--r--src/server/game/Accounts/RBAC.cpp336
-rw-r--r--src/server/game/Accounts/RBAC.h410
-rw-r--r--src/server/game/Achievements/AchievementMgr.cpp6
-rw-r--r--src/server/game/Battlefield/Battlefield.cpp13
-rw-r--r--src/server/game/Battlefield/Battlefield.h2
-rw-r--r--src/server/game/Battlegrounds/ArenaTeam.cpp58
-rw-r--r--src/server/game/Battlegrounds/ArenaTeam.h56
-rw-r--r--src/server/game/Battlegrounds/BattlegroundMgr.cpp25
-rw-r--r--src/server/game/CMakeLists.txt2
-rw-r--r--src/server/game/Chat/Chat.cpp26
-rw-r--r--src/server/game/Combat/ThreatManager.cpp19
-rw-r--r--src/server/game/Conditions/ConditionMgr.cpp2
-rw-r--r--src/server/game/Conditions/DisableMgr.cpp31
-rw-r--r--src/server/game/Conditions/DisableMgr.h8
-rw-r--r--src/server/game/DataStores/DBCStores.cpp7
-rw-r--r--src/server/game/DungeonFinding/LFG.cpp108
-rw-r--r--src/server/game/DungeonFinding/LFG.h9
-rw-r--r--src/server/game/DungeonFinding/LFGGroupData.cpp5
-rw-r--r--src/server/game/DungeonFinding/LFGGroupData.h5
-rw-r--r--src/server/game/DungeonFinding/LFGMgr.cpp173
-rw-r--r--src/server/game/DungeonFinding/LFGMgr.h173
-rw-r--r--src/server/game/DungeonFinding/LFGPlayerData.cpp5
-rw-r--r--src/server/game/DungeonFinding/LFGPlayerData.h5
-rw-r--r--src/server/game/DungeonFinding/LFGQueue.cpp11
-rw-r--r--src/server/game/DungeonFinding/LFGQueue.h5
-rw-r--r--src/server/game/DungeonFinding/LFGScripts.cpp23
-rw-r--r--src/server/game/DungeonFinding/LFGScripts.h6
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp10
-rw-r--r--src/server/game/Entities/Creature/Creature.h1
-rw-r--r--src/server/game/Entities/Creature/GossipDef.cpp35
-rw-r--r--src/server/game/Entities/Creature/GossipDef.h2
-rw-r--r--src/server/game/Entities/Object/Object.cpp126
-rw-r--r--src/server/game/Entities/Object/Object.h9
-rw-r--r--src/server/game/Entities/Player/Player.cpp351
-rw-r--r--src/server/game/Entities/Player/Player.h81
-rw-r--r--src/server/game/Entities/Transport/Transport.cpp6
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp601
-rw-r--r--src/server/game/Entities/Unit/Unit.h46
-rwxr-xr-x[-rw-r--r--]src/server/game/Entities/Vehicle/Vehicle.cpp3
-rw-r--r--src/server/game/Entities/Vehicle/VehicleDefines.h2
-rw-r--r--src/server/game/Events/GameEventMgr.cpp1
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp155
-rw-r--r--src/server/game/Globals/ObjectMgr.h14
-rw-r--r--src/server/game/Groups/Group.cpp4
-rw-r--r--src/server/game/Guilds/Guild.cpp16
-rw-r--r--src/server/game/Handlers/AddonHandler.cpp28
-rw-r--r--src/server/game/Handlers/BattleGroundHandler.cpp6
-rw-r--r--src/server/game/Handlers/ChatHandler.cpp6
-rw-r--r--src/server/game/Handlers/ItemHandler.cpp4
-rw-r--r--src/server/game/Handlers/LFGHandler.cpp127
-rw-r--r--src/server/game/Handlers/MailHandler.cpp9
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp6
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp2
-rw-r--r--src/server/game/Handlers/PetHandler.cpp7
-rw-r--r--src/server/game/Handlers/TicketHandler.cpp2
-rw-r--r--src/server/game/Handlers/TradeHandler.cpp15
-rw-r--r--src/server/game/Loot/LootMgr.cpp426
-rw-r--r--src/server/game/Loot/LootMgr.h14
-rw-r--r--src/server/game/Maps/Map.cpp49
-rw-r--r--src/server/game/Maps/Map.h3
-rw-r--r--src/server/game/Maps/MapInstanced.cpp2
-rw-r--r--src/server/game/Miscellaneous/Language.h71
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h55
-rw-r--r--src/server/game/Movement/FollowerRefManager.h1
-rw-r--r--src/server/game/Movement/FollowerReference.cpp1
-rw-r--r--src/server/game/Movement/FollowerReference.h1
-rw-r--r--src/server/game/Movement/MotionMaster.cpp72
-rw-r--r--src/server/game/Movement/MotionMaster.h7
-rwxr-xr-x[-rw-r--r--]src/server/game/Movement/MovementGenerator.h31
-rw-r--r--src/server/game/Movement/MovementGeneratorImpl.h1
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp150
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h15
-rw-r--r--[-rwxr-xr-x]src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp387
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h29
-rw-r--r--src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp47
-rw-r--r--src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h11
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp55
-rwxr-xr-x[-rw-r--r--]src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h27
-rwxr-xr-x[-rw-r--r--]src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp107
-rw-r--r--src/server/game/Movement/MovementGenerators/PointMovementGenerator.h30
-rw-r--r--src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp52
-rw-r--r--src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h13
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp302
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h63
-rwxr-xr-x[-rw-r--r--]src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp426
-rwxr-xr-x[-rw-r--r--]src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h33
-rw-r--r--src/server/game/Movement/PathGenerator.cpp803
-rw-r--r--src/server/game/Movement/PathGenerator.h135
-rw-r--r--src/server/game/Movement/Spline/MoveSpline.h3
-rw-r--r--src/server/game/Movement/Spline/MoveSplineInit.cpp87
-rw-r--r--src/server/game/Movement/Spline/MoveSplineInit.h21
-rw-r--r--src/server/game/Movement/Spline/MovementPacketBuilder.cpp2
-rw-r--r--src/server/game/Movement/Waypoints/Path.h25
-rw-r--r--src/server/game/Movement/Waypoints/WaypointManager.cpp2
-rw-r--r--src/server/game/Movement/Waypoints/WaypointManager.h1
-rw-r--r--src/server/game/Scripting/ScriptLoader.cpp4
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp2
-rw-r--r--src/server/game/Scripting/ScriptMgr.h3
-rw-r--r--src/server/game/Server/Protocol/PacketLog.cpp2
-rw-r--r--src/server/game/Server/WorldSession.cpp31
-rw-r--r--src/server/game/Server/WorldSession.h29
-rw-r--r--src/server/game/Server/WorldSocket.cpp19
-rw-r--r--src/server/game/Skills/SkillDiscovery.cpp2
-rw-r--r--src/server/game/Skills/SkillExtraItems.cpp10
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp311
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp15
-rw-r--r--src/server/game/Spells/Spell.cpp34
-rw-r--r--src/server/game/Spells/Spell.h2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp237
-rw-r--r--src/server/game/Spells/SpellInfo.cpp33
-rw-r--r--src/server/game/Spells/SpellMgr.cpp2
-rw-r--r--src/server/game/Spells/SpellScript.cpp2
-rw-r--r--src/server/game/Tickets/TicketMgr.cpp2
-rw-r--r--src/server/game/Tools/CharacterDatabaseCleaner.cpp1
-rw-r--r--src/server/game/Warden/Warden.cpp2
-rw-r--r--src/server/game/Warden/WardenCheckMgr.cpp10
-rw-r--r--src/server/game/Warden/WardenMac.cpp2
-rw-r--r--src/server/game/Warden/WardenWin.cpp2
-rw-r--r--src/server/game/Weather/WeatherMgr.cpp2
-rw-r--r--src/server/game/World/World.cpp53
-rw-r--r--src/server/game/World/World.h3
136 files changed, 4724 insertions, 3696 deletions
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp
index a8d2a2248ad..2792f68004f 100644
--- a/src/server/game/AI/CoreAI/PetAI.cpp
+++ b/src/server/game/AI/CoreAI/PetAI.cpp
@@ -432,29 +432,23 @@ void PetAI::HandleReturnMovement()
if (!me->GetCharmInfo()->IsAtStay() && !me->GetCharmInfo()->IsReturning())
{
// Return to previous position where stay was clicked
- if (!me->GetCharmInfo()->IsCommandAttack())
- {
- float x, y, z;
+ float x, y, z;
- me->GetCharmInfo()->GetStayPosition(x, y, z);
- ClearCharmInfoFlags();
- me->GetCharmInfo()->SetIsReturning(true);
- me->GetMotionMaster()->Clear();
- me->GetMotionMaster()->MovePoint(me->GetGUIDLow(), x, y, z);
- }
+ me->GetCharmInfo()->GetStayPosition(x, y, z);
+ ClearCharmInfoFlags();
+ me->GetCharmInfo()->SetIsReturning(true);
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MovePoint(me->GetGUIDLow(), x, y, z);
}
}
else // COMMAND_FOLLOW
{
if (!me->GetCharmInfo()->IsFollowing() && !me->GetCharmInfo()->IsReturning())
{
- if (!me->GetCharmInfo()->IsCommandAttack())
- {
- ClearCharmInfoFlags();
- me->GetCharmInfo()->SetIsReturning(true);
- me->GetMotionMaster()->Clear();
- me->GetMotionMaster()->MoveFollow(me->GetCharmerOrOwner(), PET_FOLLOW_DIST, me->GetFollowAngle());
- }
+ ClearCharmInfoFlags();
+ me->GetCharmInfo()->SetIsReturning(true);
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveFollow(me->GetCharmerOrOwner(), PET_FOLLOW_DIST, me->GetFollowAngle());
}
}
}
@@ -473,12 +467,13 @@ void PetAI::DoAttack(Unit* target, bool chase)
if (me->HasReactState(REACT_AGGRESSIVE) && !me->GetCharmInfo()->IsCommandAttack())
me->SendPetAIReaction(me->GetGUID());
-
if (chase)
{
- ClearCharmInfoFlags();
- me->GetMotionMaster()->Clear();
- me->GetMotionMaster()->MoveChase(target);
+ bool oldCmdAttack = me->GetCharmInfo()->IsCommandAttack(); // This needs to be reset after other flags are cleared
+ ClearCharmInfoFlags();
+ me->GetCharmInfo()->SetIsCommandAttack(oldCmdAttack); // For passive pets commanded to attack so they will use spells
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveChase(target);
}
else // (Stay && ((Aggressive || Defensive) && In Melee Range)))
{
diff --git a/src/server/game/AI/CoreAI/ReactorAI.cpp b/src/server/game/AI/CoreAI/ReactorAI.cpp
index 31b9a82c534..b9c235176bc 100644
--- a/src/server/game/AI/CoreAI/ReactorAI.cpp
+++ b/src/server/game/AI/CoreAI/ReactorAI.cpp
@@ -23,10 +23,7 @@
#include "ObjectAccessor.h"
#include "CreatureAIImpl.h"
-#define REACTOR_VISIBLE_RANGE (26.46f)
-
-int
-ReactorAI::Permissible(const Creature* creature)
+int ReactorAI::Permissible(const Creature* creature)
{
if (creature->isCivilian() || creature->IsNeutralToAll())
return PERMIT_BASE_REACTIVE;
@@ -34,24 +31,10 @@ ReactorAI::Permissible(const Creature* creature)
return PERMIT_BASE_NO;
}
-void
-ReactorAI::MoveInLineOfSight(Unit*)
-{
-}
-
-void
-ReactorAI::UpdateAI(const uint32 /*time_diff*/)
+void ReactorAI::UpdateAI(uint32 const /*diff*/)
{
- // update i_victimGuid if me->getVictim() !=0 and changed
if (!UpdateVictim())
return;
- if (me->isAttackReady())
- {
- if (me->IsWithinMeleeRange(me->getVictim()))
- {
- me->AttackerStateUpdate(me->getVictim());
- me->resetAttackTimer();
- }
- }
+ DoMeleeAttackIfReady();
}
diff --git a/src/server/game/AI/CoreAI/ReactorAI.h b/src/server/game/AI/CoreAI/ReactorAI.h
index 39af09c4a9d..f7de3b99565 100644
--- a/src/server/game/AI/CoreAI/ReactorAI.h
+++ b/src/server/game/AI/CoreAI/ReactorAI.h
@@ -29,9 +29,9 @@ class ReactorAI : public CreatureAI
explicit ReactorAI(Creature* c) : CreatureAI(c) {}
- void MoveInLineOfSight(Unit*);
+ void MoveInLineOfSight(Unit*) {}
+ void UpdateAI(uint32 const diff);
- void UpdateAI(const uint32);
static int Permissible(const Creature*);
};
#endif
diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp
index 09ba2cc19b1..7f0d387c2f1 100644
--- a/src/server/game/AI/CoreAI/UnitAI.cpp
+++ b/src/server/game/AI/CoreAI/UnitAI.cpp
@@ -103,8 +103,7 @@ void UnitAI::DoAddAuraToAllHostilePlayers(uint32 spellid)
if (unit->GetTypeId() == TYPEID_PLAYER)
me->AddAura(spellid, unit);
}
- }else
- return;
+ }
}
void UnitAI::DoCastToAllHostilePlayers(uint32 spellid, bool triggered)
@@ -118,8 +117,7 @@ void UnitAI::DoCastToAllHostilePlayers(uint32 spellid, bool triggered)
if (unit->GetTypeId() == TYPEID_PLAYER)
me->CastSpell(unit, spellid, triggered);
}
- }else
- return;
+ }
}
void UnitAI::DoCast(uint32 spellId)
@@ -240,7 +238,10 @@ void UnitAI::FillAISpellInfo()
}
//Enable PlayerAI when charmed
-void PlayerAI::OnCharmed(bool apply) { me->IsAIEnabled = apply; }
+void PlayerAI::OnCharmed(bool apply)
+{
+ me->IsAIEnabled = apply;
+}
void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/)
{
diff --git a/src/server/game/AI/CreatureAIImpl.h b/src/server/game/AI/CreatureAIImpl.h
index 559240c4a3f..6c5cb5622b3 100644
--- a/src/server/game/AI/CreatureAIImpl.h
+++ b/src/server/game/AI/CreatureAIImpl.h
@@ -313,96 +313,177 @@ const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, c
class EventMap
{
- typedef std::map<uint32, uint32> StorageType;
+ /**
+ * Internal storage type.
+ * Key: Time as uint32 when the event should occur.
+ * Value: The event data as uint32.
+ *
+ * Structure of event data:
+ * - Bit 0 - 15: Event Id.
+ * - Bit 16 - 23: Group
+ * - Bit 24 - 31: Phase
+ * - Pattern: 0xPPGGEEEE
+ */
+ typedef std::multimap<uint32, uint32> EventStore;
public:
EventMap() : _time(0), _phase(0) {}
- // Returns current timer value, does not represent real dates/times
- uint32 GetTimer() const { return _time; }
-
- // Removes all events and clears phase
+ /**
+ * @name Reset
+ * @brief Removes all scheduled events and resets time and phase.
+ */
void Reset()
{
- _eventMap.clear(); _time = 0; _phase = 0;
+ _eventMap.clear();
+ _time = 0;
+ _phase = 0;
+ }
+
+ /**
+ * @name Update
+ * @brief Updates the timer of the event map.
+ * @param time Value to be added to time.
+ */
+ void Update(uint32 time)
+ {
+ _time += time;
}
- void Update(uint32 time) { _time += time; }
+ /**
+ * @name GetTimer
+ * @return Current timer value.
+ */
+ uint32 GetTimer() const
+ {
+ return _time;
+ }
- uint32 GetPhaseMask() const { return (_phase >> 24) & 0xFF; }
+ /**
+ * @name GetPhaseMask
+ * @return Active phases as mask.
+ */
+ uint8 GetPhaseMask() const
+ {
+ return _phase;
+ }
- bool Empty() const { return _eventMap.empty(); }
+ /**
+ * @name Empty
+ * @return True, if there are no events scheduled.
+ */
+ bool Empty() const
+ {
+ return _eventMap.empty();
+ }
- // Sets event phase, must be in range 1 - 8
- void SetPhase(uint32 phase)
+ /**
+ * @name SetPhase
+ * @brief Sets the phase of the map (absolute).
+ * @param phase Phase which should be set. Values: 1 - 8. 0 resets phase.
+ */
+ void SetPhase(uint8 phase)
{
- if (phase && phase < 8)
- _phase = (1 << (phase + 24));
- else if (!phase)
+ if (!phase)
_phase = 0;
+ else if (phase <= 8)
+ _phase = (1 << (phase - 1));
}
- // Creates new event entry in map with given id, time, group if given (1 - 8) and phase if given (1 - 8)
- // 0 for group/phase means it belongs to no group or runs in all phases
- void ScheduleEvent(uint32 eventId, uint32 time, uint32 groupId = 0, uint32 phase = 0)
+ /**
+ * @name AddPhase
+ * @brief Activates the given phase (bitwise).
+ * @param phase Phase which should be activated. Values: 1 - 8
+ */
+ void AddPhase(uint8 phase)
{
- time += _time;
- if (groupId && groupId < 9)
- eventId |= (1 << (groupId + 16));
- if (phase && phase < 8)
- eventId |= (1 << (phase + 24));
- StorageType::const_iterator itr = _eventMap.find(time);
- while (itr != _eventMap.end())
- {
- ++time;
- itr = _eventMap.find(time);
- }
+ if (phase && phase <= 8)
+ _phase |= (1 << (phase - 1));
+ }
- _eventMap.insert(StorageType::value_type(time, eventId));
+ /**
+ * @name RemovePhase
+ * @brief Deactivates the given phase (bitwise).
+ * @param phase Phase which should be deactivated. Values: 1 - 8.
+ */
+ void RemovePhase(uint8 phase)
+ {
+ if (phase && phase <= 8)
+ _phase &= ~(1 << (phase - 1));
}
- // Removes event with specified id and creates new entry for it
- void RescheduleEvent(uint32 eventId, uint32 time, uint32 groupId = 0, uint32 phase = 0)
+ /**
+ * @name ScheduleEvent
+ * @brief Creates new event entry in map.
+ * @param eventId The id of the new event.
+ * @param time The time in milliseconds until the event occurs.
+ * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
+ * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
+ */
+ void ScheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0)
+ {
+ if (group && group <= 8)
+ eventId |= (1 << (group + 15));
+
+ if (phase && phase <= 8)
+ eventId |= (1 << (phase + 23));
+
+ _eventMap.insert(EventStore::value_type(_time + time, eventId));
+ }
+
+ /**
+ * @name RescheduleEvent
+ * @brief Cancels the given event and reschedules it.
+ * @param eventId The id of the event.
+ * @param time The time in milliseconds until the event occurs.
+ * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
+ * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
+ */
+ void RescheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0)
{
CancelEvent(eventId);
- ScheduleEvent(eventId, time, groupId, phase);
+ ScheduleEvent(eventId, time, group, phase);
}
- // Reschedules closest event
+ /**
+ * @name RepeatEvent
+ * @brief Cancels the closest event and reschedules it.
+ * @param time Time until the event occurs.
+ */
void RepeatEvent(uint32 time)
{
- if (_eventMap.empty())
+ if (Empty())
return;
uint32 eventId = _eventMap.begin()->second;
_eventMap.erase(_eventMap.begin());
- time += _time;
- StorageType::const_iterator itr = _eventMap.find(time);
- while (itr != _eventMap.end())
- {
- ++time;
- itr = _eventMap.find(time);
- }
-
- _eventMap.insert(StorageType::value_type(time, eventId));
+ ScheduleEvent(eventId, time);
}
- // Removes first event
+ /**
+ * @name PopEvent
+ * @brief Remove the first event in the map.
+ */
void PopEvent()
{
- if (!_eventMap.empty())
+ if (!Empty())
_eventMap.erase(_eventMap.begin());
}
- // Gets next event id to execute and removes it from map
+ /**
+ * @name ExecuteEvent
+ * @brief Returns the next event to execute and removes it from map.
+ * @return Id of the event to execute.
+ */
uint32 ExecuteEvent()
{
- while (!_eventMap.empty())
+ while (!Empty())
{
- StorageType::iterator itr = _eventMap.begin();
+ EventStore::iterator itr = _eventMap.begin();
+
if (itr->first > _time)
return 0;
- else if (_phase && (itr->second & 0xFF000000) && !(itr->second & _phase))
+ else if (_phase && (itr->second & 0xFF000000) && !((itr->second >> 24) & _phase))
_eventMap.erase(itr);
else
{
@@ -411,18 +492,24 @@ class EventMap
return eventId;
}
}
+
return 0;
}
- // Gets next event id to execute
+ /**
+ * @name GetEvent
+ * @brief Returns the next event to execute.
+ * @return Id of the event to execute.
+ */
uint32 GetEvent()
{
- while (!_eventMap.empty())
+ while (!Empty())
{
- StorageType::iterator itr = _eventMap.begin();
+ EventStore::iterator itr = _eventMap.begin();
+
if (itr->first > _time)
return 0;
- else if (_phase && (itr->second & 0xFF000000) && !(itr->second & _phase))
+ else if (_phase && (itr->second & 0xFF000000) && !(itr->second & (_phase << 24)))
_eventMap.erase(itr);
else
return (itr->second & 0x0000FFFF);
@@ -431,81 +518,150 @@ class EventMap
return 0;
}
- // Delay all events
+ /**
+ * @name DelayEvents
+ * @brief Delays all events in the map. If delay is greater than or equal internal timer, delay will be 0.
+ * @param delay Amount of delay.
+ */
void DelayEvents(uint32 delay)
{
- if (delay < _time)
- _time -= delay;
- else
- _time = 0;
+ _time = delay < _time ? _time - delay : 0;
}
- // Delay all events having the specified Group
- void DelayEvents(uint32 delay, uint32 groupId)
+ /**
+ * @name DelayEvents
+ * @brief Delay all events of the same group.
+ * @param delay Amount of delay.
+ * @param group Group of the events.
+ */
+ void DelayEvents(uint32 delay, uint32 group)
{
- uint32 nextTime = _time + delay;
- uint32 groupMask = (1 << (groupId + 16));
- for (StorageType::iterator itr = _eventMap.begin(); itr != _eventMap.end() && itr->first < nextTime;)
+ if (!group || group > 8 || Empty())
+ return;
+
+ EventStore delayed;
+
+ for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
{
- if (itr->second & groupMask)
+ if (itr->second & (1 << (group + 15)))
{
- ScheduleEvent(itr->second, itr->first - _time + delay);
- _eventMap.erase(itr);
- itr = _eventMap.begin();
+ delayed.insert(EventStore::value_type(itr->first + delay, itr->second));
+ _eventMap.erase(itr++);
}
else
++itr;
}
+
+ _eventMap.insert(delayed.begin(), delayed.end());
}
- // Cancel events with specified id
+ /**
+ * @name CancelEvent
+ * @brief Cancels all events of the specified id.
+ * @param eventId Event id to cancel.
+ */
void CancelEvent(uint32 eventId)
{
- for (StorageType::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
+ if (Empty())
+ return;
+
+ for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
{
if (eventId == (itr->second & 0x0000FFFF))
- {
- _eventMap.erase(itr);
- itr = _eventMap.begin();
- }
+ _eventMap.erase(itr++);
else
++itr;
}
}
- // Cancel events belonging to specified group
- void CancelEventGroup(uint32 groupId)
+ /**
+ * @name CancelEventGroup
+ * @brief Cancel events belonging to specified group.
+ * @param group Group to cancel.
+ */
+ void CancelEventGroup(uint32 group)
{
- uint32 groupMask = (1 << (groupId + 16));
+ if (!group || group > 8 || Empty())
+ return;
- for (StorageType::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
+ for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
{
- if (itr->second & groupMask)
- {
- _eventMap.erase(itr);
- itr = _eventMap.begin();
- }
+ if (itr->second & (1 << (group + 15)))
+ _eventMap.erase(itr++);
else
++itr;
}
}
- // Returns time of next event to execute
- // To get how much time remains substract _time
+ /**
+ * @name GetNextEventTime
+ * @brief Returns closest occurence of specified event.
+ * @param eventId Wanted event id.
+ * @return Time of found event.
+ */
uint32 GetNextEventTime(uint32 eventId) const
{
- for (StorageType::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
+ if (Empty())
+ return 0;
+
+ for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
if (eventId == (itr->second & 0x0000FFFF))
return itr->first;
return 0;
}
+ /**
+ * @name GetNextEventTime
+ * @return Time of next event.
+ */
+ uint32 GetNextEventTime() const
+ {
+ return Empty() ? 0 : _eventMap.begin()->first;
+ }
+
+ /**
+ * @name IsInPhase
+ * @brief Returns wether event map is in specified phase or not.
+ * @param phase Wanted phase.
+ * @return True, if phase of event map contains specified phase.
+ */
+ bool IsInPhase(uint8 phase)
+ {
+ return phase <= 8 && (!phase || _phase & (1 << (phase - 1)));
+ }
+
private:
+ /**
+ * @name _time
+ * @brief Internal timer.
+ *
+ * This does not represent the real date/time value.
+ * It's more like a stopwatch: It can run, it can be stopped,
+ * it can be resetted and so on. Events occur when this timer
+ * has reached their time value. Its value is changed in the
+ * Update method.
+ */
uint32 _time;
- uint32 _phase;
- StorageType _eventMap;
+ /**
+ * @name _phase
+ * @brief Phase mask of the event map.
+ *
+ * Contains the phases the event map is in. Multiple
+ * phases from 1 to 8 can be set with SetPhase or
+ * AddPhase. RemovePhase deactives a phase.
+ */
+ uint8 _phase;
+
+ /**
+ * @name _eventMap
+ * @brief Internal event storage map. Contains the scheduled events.
+ *
+ * See typedef at the beginning of the class for more
+ * details.
+ */
+ EventStore _eventMap;
};
enum AITarget
diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp
index 920c1c25533..a09feb6e00f 100644
--- a/src/server/game/AI/CreatureAISelector.cpp
+++ b/src/server/game/AI/CreatureAISelector.cpp
@@ -132,16 +132,12 @@ namespace FactorySelector
const GameObjectAICreator* ai_factory = NULL;
GameObjectAIRegistry& ai_registry(*GameObjectAIRepository::instance());
+ // scriptname in db
if (GameObjectAI* scriptedAI = sScriptMgr->GetGameObjectAI(go))
return scriptedAI;
ai_factory = ai_registry.GetRegistryItem(go->GetAIName());
- // scriptname in db
- if (!ai_factory)
- if (GameObjectAI* scriptedAI = sScriptMgr->GetGameObjectAI(go))
- return scriptedAI;
-
//future goAI types go here
std::string ainame = (ai_factory == NULL || go->GetScriptId()) ? "NullGameObjectAI" : ai_factory->key();
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
index 72f4d011948..23620bf1174 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
@@ -104,10 +104,18 @@ void ScriptedAI::AttackStartNoMove(Unit* who)
if (!who)
return;
- if (me->Attack(who, false))
+ if (me->Attack(who, true))
DoStartNoMovement(who);
}
+void ScriptedAI::AttackStart(Unit* who)
+{
+ if (IsCombatMovementAllowed())
+ CreatureAI::AttackStart(who);
+ else
+ AttackStartNoMove(who);
+}
+
void ScriptedAI::UpdateAI(uint32 const /*diff*/)
{
//Check if we have a current target
@@ -439,15 +447,6 @@ bool ScriptedAI::EnterEvadeIfOutOfCombatArea(uint32 const diff)
return true;
}
-void Scripted_NoMovementAI::AttackStart(Unit* target)
-{
- if (!target)
- return;
-
- if (me->Attack(target, true))
- DoStartNoMovement(target);
-}
-
// BossAI - for instanced bosses
BossAI::BossAI(Creature* creature, uint32 bossId) : ScriptedAI(creature),
instance(creature->GetInstanceScript()),
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
index f3a13060ad8..a9da02fda38 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
@@ -136,6 +136,9 @@ struct ScriptedAI : public CreatureAI
//Called at creature aggro either by MoveInLOS or Attack Start
void EnterCombat(Unit* /*victim*/) {}
+ // Called before EnterCombat even before the creature is in combat.
+ void AttackStart(Unit* /*target*/);
+
// *************
//AI Helper Functions
// *************
@@ -191,7 +194,11 @@ struct ScriptedAI : public CreatureAI
void SetEquipmentSlots(bool loadDefault, int32 mainHand = EQUIP_NO_CHANGE, int32 offHand = EQUIP_NO_CHANGE, int32 ranged = EQUIP_NO_CHANGE);
- //Generally used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims
+ // Used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims
+ // NOTE: If you use SetCombatMovement while the creature is in combat, it will do NOTHING - This only affects AttackStart
+ // You should make the necessary to make it happen so.
+ // Remember that if you modified _isCombatMovementAllowed (e.g: using SetCombatMovement) it will not be reset at Reset().
+ // It will keep the last value you set.
void SetCombatMovement(bool allowMovement);
bool IsCombatMovementAllowed() const { return _isCombatMovementAllowed; }
@@ -269,15 +276,6 @@ struct ScriptedAI : public CreatureAI
bool _isHeroic;
};
-struct Scripted_NoMovementAI : public ScriptedAI
-{
- Scripted_NoMovementAI(Creature* creature) : ScriptedAI(creature) {}
- virtual ~Scripted_NoMovementAI() {}
-
- //Called at each attack of me by any victim
- void AttackStart(Unit* target);
-};
-
class BossAI : public ScriptedAI
{
public:
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index e568a36abc4..501bc35b77a 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -430,13 +430,14 @@ void SmartAI::MovementInform(uint32 MovementType, uint32 Data)
void SmartAI::RemoveAuras()
{
- // Only loop throught the applied auras, because here is where all auras on the current unit are stored
- Unit::AuraApplicationMap appliedAuras = me->GetAppliedAuras();
- for (Unit::AuraApplicationMap::iterator iter = appliedAuras.begin(); iter != appliedAuras.end(); ++iter)
+ Unit::AuraApplicationMap& appliedAuras = me->GetAppliedAuras();
+ for (Unit::AuraApplicationMap::iterator iter = appliedAuras.begin(); iter != appliedAuras.end();)
{
Aura const* aura = iter->second->GetBase();
- if (!aura->GetSpellInfo()->IsPassive() && !aura->GetSpellInfo()->HasAura(SPELL_AURA_CONTROL_VEHICLE) && aura->GetCaster() != me)
- me->RemoveAurasDueToSpell(aura->GetId());
+ if (!aura->IsPassive() && !aura->HasEffectType(SPELL_AURA_CONTROL_VEHICLE) && aura->GetCasterGUID() != me->GetGUID())
+ me->RemoveAura(iter);
+ else
+ ++iter;
}
}
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 84c9dffabd2..e37b9e777d8 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -1893,12 +1893,19 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
case SMART_ACTION_JUMP_TO_POS:
{
- if (!me)
+ ObjectList* targets = GetTargets(e, unit);
+ if (!targets)
break;
- me->GetMotionMaster()->Clear();
- me->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz);
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ if (Creature* creature = (*itr)->ToCreature())
+ {
+ creature->GetMotionMaster()->Clear();
+ creature->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz);
+ }
// TODO: Resume path when reached jump location
+
+ delete targets;
break;
}
case SMART_ACTION_GO_SET_LOOT_STATE:
@@ -1977,23 +1984,48 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
case SMART_ACTION_SET_HOME_POS:
{
- if (!me)
+ ObjectList* targets = GetTargets(e, unit);
+ if (!targets)
break;
- if (e.GetTargetType() == SMART_TARGET_SELF)
- me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
- else if (e.GetTargetType() == SMART_TARGET_POSITION)
- me->SetHomePosition(e.target.x, e.target.y, e.target.z, e.target.o);
- else
- sLog->outError(LOG_FILTER_SQL, "SmartScript: Action target for SMART_ACTION_SET_HOME_POS is not using SMART_TARGET_SELF or SMART_TARGET_POSITION, skipping");
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ if (IsCreature(*itr))
+ {
+ if (e.GetTargetType() == SMART_TARGET_SELF)
+ (*itr)->ToCreature()->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
+ else if (e.GetTargetType() == SMART_TARGET_POSITION)
+ (*itr)->ToCreature()->SetHomePosition(e.target.x, e.target.y, e.target.z, e.target.o);
+ else
+ sLog->outError(LOG_FILTER_SQL, "SmartScript: Action target for SMART_ACTION_SET_HOME_POS is not using SMART_TARGET_SELF or SMART_TARGET_POSITION, skipping");
+ }
- break;
+ delete targets;
+ break;
}
case SMART_ACTION_SET_HEALTH_REGEN:
{
- if (!me || me->GetTypeId() != TYPEID_UNIT)
+ ObjectList* targets = GetTargets(e, unit);
+ if (!targets)
+ break;
+
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ if (IsCreature(*itr))
+ (*itr)->ToCreature()->setRegeneratingHealth(e.action.setHealthRegen.regenHealth ? true : false);
+
+ delete targets;
+ break;
+ }
+ case SMART_ACTION_SET_ROOT:
+ {
+ ObjectList* targets = GetTargets(e, unit);
+ if (!targets)
break;
- me->setRegeneratingHealth(e.action.setHealthRegen.regenHealth ? true : false);
+
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ if (IsCreature(*itr))
+ (*itr)->ToCreature()->SetControlled(e.action.setRoot.root ? true : false, UNIT_STATE_ROOT);
+
+ delete targets;
break;
}
default:
@@ -2011,6 +2043,17 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
}
+void SmartScript::ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit, uint32 var0, uint32 var1, bool bvar, const SpellInfo* spell, GameObject* gob)
+{
+ ConditionList const conds = sConditionMgr->GetConditionsForSmartEvent(e.entryOrGuid, e.event_id, e.source_type);
+ ConditionSourceInfo info = ConditionSourceInfo(unit, GetBaseObject());
+
+ if (sConditionMgr->IsObjectMeetToConditions(info, conds))
+ ProcessAction(e, unit, var0, var1, bvar, spell, gob);
+
+ RecalcTimer(e, min, max);
+}
+
void SmartScript::InstallTemplate(SmartScriptHolder const& e)
{
if (!GetBaseObject())
@@ -2409,20 +2452,17 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
break;
//called from Update tick
case SMART_EVENT_UPDATE:
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- ProcessAction(e);
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
break;
case SMART_EVENT_UPDATE_OOC:
if (me && me->isInCombat())
return;
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- ProcessAction(e);
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
break;
case SMART_EVENT_UPDATE_IC:
if (!me || !me->isInCombat())
return;
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- ProcessAction(e);
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
break;
case SMART_EVENT_HEALT_PCT:
{
@@ -2431,8 +2471,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
uint32 perc = (uint32)me->GetHealthPct();
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
return;
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- ProcessAction(e);
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
break;
}
case SMART_EVENT_TARGET_HEALTH_PCT:
@@ -2442,8 +2481,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
uint32 perc = (uint32)me->getVictim()->GetHealthPct();
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
return;
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- ProcessAction(e, me->getVictim());
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->getVictim());
break;
}
case SMART_EVENT_MANA_PCT:
@@ -2453,8 +2491,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
uint32 perc = uint32(100.0f * me->GetPower(POWER_MANA) / me->GetMaxPower(POWER_MANA));
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
return;
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- ProcessAction(e);
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
break;
}
case SMART_EVENT_TARGET_MANA_PCT:
@@ -2464,8 +2501,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
uint32 perc = uint32(100.0f * me->getVictim()->GetPower(POWER_MANA) / me->getVictim()->GetMaxPower(POWER_MANA));
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
return;
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- ProcessAction(e, me->getVictim());
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->getVictim());
break;
}
case SMART_EVENT_RANGE:
@@ -2474,18 +2510,15 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
return;
if (me->IsInRange(me->getVictim(), (float)e.event.minMaxRepeat.min, (float)e.event.minMaxRepeat.max))
- {
- ProcessAction(e, me->getVictim());
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- }
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->getVictim());
break;
}
case SMART_EVENT_TARGET_CASTING:
{
if (!me || !me->isInCombat() || !me->getVictim() || !me->getVictim()->IsNonMeleeSpellCasted(false, false, true))
return;
- ProcessAction(e, me->getVictim());
- RecalcTimer(e, e.event.minMax.repeatMin, e.event.minMax.repeatMax);
+
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->getVictim());
}
case SMART_EVENT_FRIENDLY_HEALTH:
{
@@ -2495,8 +2528,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
Unit* target = DoSelectLowestHpFriendly((float)e.event.friendlyHealt.radius, e.event.friendlyHealt.hpDeficit);
if (!target)
return;
- ProcessAction(e, target);
- RecalcTimer(e, e.event.friendlyHealt.repeatMin, e.event.friendlyHealt.repeatMax);
+ ProcessTimedAction(e, e.event.friendlyHealt.repeatMin, e.event.friendlyHealt.repeatMax, target);
break;
}
case SMART_EVENT_FRIENDLY_IS_CC:
@@ -2508,8 +2540,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
DoFindFriendlyCC(pList, (float)e.event.friendlyCC.radius);
if (pList.empty())
return;
- ProcessAction(e, *(pList.begin()));
- RecalcTimer(e, e.event.friendlyCC.repeatMin, e.event.friendlyCC.repeatMax);
+ ProcessTimedAction(e, e.event.friendlyCC.repeatMin, e.event.friendlyCC.repeatMax, *pList.begin());
break;
}
case SMART_EVENT_FRIENDLY_MISSING_BUFF:
@@ -2519,8 +2550,8 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
if (pList.empty())
return;
- ProcessAction(e, *(pList.begin()));
- RecalcTimer(e, e.event.missingBuff.repeatMin, e.event.missingBuff.repeatMax);
+
+ ProcessTimedAction(e, e.event.missingBuff.repeatMin, e.event.missingBuff.repeatMax, *pList.begin());
break;
}
case SMART_EVENT_HAS_AURA:
@@ -2529,10 +2560,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
return;
uint32 count = me->GetAuraCount(e.event.aura.spell);
if ((!e.event.aura.count && !count) || (e.event.aura.count && count >= e.event.aura.count))
- {
- ProcessAction(e);
- RecalcTimer(e, e.event.aura.repeatMin, e.event.aura.repeatMax);
- }
+ ProcessTimedAction(e, e.event.aura.repeatMin, e.event.aura.repeatMax);
break;
}
case SMART_EVENT_TARGET_BUFFED:
@@ -2542,8 +2570,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
uint32 count = me->getVictim()->GetAuraCount(e.event.aura.spell);
if (count < e.event.aura.count)
return;
- ProcessAction(e);
- RecalcTimer(e, e.event.aura.repeatMin, e.event.aura.repeatMax);
+ ProcessTimedAction(e, e.event.aura.repeatMin, e.event.aura.repeatMax);
break;
}
//no params
@@ -2578,10 +2605,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
if (Unit* victim = me->getVictim())
{
if (!victim->HasInArc(static_cast<float>(M_PI), me))
- {
- ProcessAction(e, victim);
- RecalcTimer(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax);
- }
+ ProcessTimedAction(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax, victim);
}
break;
}
diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h
index d0d0221493f..28b328a2947 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.h
+++ b/src/server/game/AI/SmartScripts/SmartScript.h
@@ -45,6 +45,7 @@ class SmartScript
void UpdateTimer(SmartScriptHolder& e, uint32 const diff);
void InitTimer(SmartScriptHolder& e);
void ProcessAction(SmartScriptHolder& e, Unit* unit = NULL, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellInfo* spell = NULL, GameObject* gob = NULL);
+ void ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit = NULL, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellInfo* spell = NULL, GameObject* gob = NULL);
ObjectList* GetTargets(SmartScriptHolder const& e, Unit* invoker = NULL);
ObjectList* GetWorldObjectsInDist(float dist);
void InstallTemplate(SmartScriptHolder const& e);
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 76fcb7bad00..69902954fde 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -906,6 +906,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_SEND_TARGET_TO_TARGET:
case SMART_ACTION_SET_HOME_POS:
case SMART_ACTION_SET_HEALTH_REGEN:
+ case SMART_ACTION_SET_ROOT:
break;
default:
sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index a909cb56098..a3420071f5e 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -487,8 +487,9 @@ enum SMART_ACTION
SMART_ACTION_SEND_TARGET_TO_TARGET = 100, // id
SMART_ACTION_SET_HOME_POS = 101, // none
SMART_ACTION_SET_HEALTH_REGEN = 102, // 0/1
+ SMART_ACTION_SET_ROOT = 103, // off/on
- SMART_ACTION_END = 103
+ SMART_ACTION_END = 104
};
struct SmartAction
@@ -920,6 +921,11 @@ struct SmartAction
uint32 regenHealth;
} setHealthRegen;
+ struct
+ {
+ uint32 root;
+ } setRoot;
+
//! Note for any new future actions
//! All parameters must have type uint32
diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp
index 3c3eded1f68..b1d0087c32c 100644
--- a/src/server/game/Accounts/AccountMgr.cpp
+++ b/src/server/game/Accounts/AccountMgr.cpp
@@ -17,6 +17,7 @@
*/
#include "AccountMgr.h"
+#include "Config.h"
#include "DatabaseEnv.h"
#include "ObjectAccessor.h"
#include "Player.h"
@@ -26,6 +27,7 @@
AccountMgr::AccountMgr()
{
+
}
AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password)
@@ -44,12 +46,22 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass
stmt->setString(0, username);
stmt->setString(1, CalculateShaPassHash(username, password));
- LoginDatabase.Execute(stmt);
+ LoginDatabase.DirectExecute(stmt); // Enforce saving, otherwise AddGroup can fail
stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS_INIT);
LoginDatabase.Execute(stmt);
+ // Add default rbac groups for that security level
+ RBACData* rbac = new RBACData(GetId(username), username, -1);
+ // No need to Load From DB, as it's new data
+
+ RBACGroupContainer const& groupsToAdd = _defaultGroups[0]; // 0: Default sec level
+ for (RBACGroupContainer::const_iterator it = groupsToAdd.begin(); it != groupsToAdd.end(); ++it)
+ rbac->AddGroup(*it, -1);
+
+ delete rbac;
+
return AOR_OK; // everything's fine
}
@@ -175,6 +187,14 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass
LoginDatabase.Execute(stmt);
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS);
+
+ stmt->setString(0, "");
+ stmt->setString(1, "");
+ stmt->setString(2, username);
+
+ LoginDatabase.Execute(stmt);
+
return AOR_OK;
}
@@ -303,3 +323,206 @@ bool AccountMgr::IsConsoleAccount(uint32 gmlevel)
{
return gmlevel == SEC_CONSOLE;
}
+
+void AccountMgr::LoadRBAC()
+{
+ uint32 oldMSTime = getMSTime();
+ uint32 count1 = 0;
+ uint32 count2 = 0;
+ uint32 count3 = 0;
+
+ QueryResult result = LoginDatabase.Query("SELECT id, name FROM rbac_permissions");
+ if (!result)
+ {
+ sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account permission definitions. DB table `rbac_permissions` is empty.");
+ return;
+ }
+
+ do
+ {
+ Field* field = result->Fetch();
+ uint32 id = field[0].GetUInt32();
+ _permissions[id] = new RBACPermission(id, field[1].GetString());
+ ++count1;
+ }
+ while (result->NextRow());
+
+ result = LoginDatabase.Query("SELECT id, name FROM rbac_roles");
+ if (!result)
+ {
+ sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account role definitions. DB table `rbac_roles` is empty.");
+ return;
+ }
+
+ do
+ {
+ Field* field = result->Fetch();
+ uint32 id = field[0].GetUInt32();
+ _roles[id] = new RBACRole(id, field[1].GetString());
+ ++count2;
+ }
+ while (result->NextRow());
+
+ result = LoginDatabase.Query("SELECT roleId, permissionId FROM rbac_role_permissions");
+ if (!result)
+ {
+ sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account role-permission definitions. DB table `rbac_role_permissions` is empty.");
+ return;
+ }
+
+ do
+ {
+ Field* field = result->Fetch();
+ uint32 id = field[0].GetUInt32();
+ RBACRole* role = _roles[id];
+ role->GrantPermission(field[1].GetUInt32());
+ }
+ while (result->NextRow());
+
+ result = LoginDatabase.Query("SELECT id, name FROM rbac_groups");
+ if (!result)
+ {
+ sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account group definitions. DB table `rbac_groups` is empty.");
+ return;
+ }
+
+ do
+ {
+ Field* field = result->Fetch();
+ uint32 id = field[0].GetUInt32();
+ _groups[id] = new RBACGroup(id, field[1].GetString());
+ ++count3;
+ }
+ while (result->NextRow());
+
+ result = LoginDatabase.Query("SELECT groupId, roleId FROM rbac_group_roles");
+ if (!result)
+ {
+ sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account group-role definitions. DB table `rbac_group_roles` is empty.");
+ return;
+ }
+
+ do
+ {
+ Field* field = result->Fetch();
+ uint32 id = field[0].GetUInt32();
+ RBACGroup* group = _groups[id];
+ group->GrantRole(field[1].GetUInt32());
+ }
+ while (result->NextRow());
+
+ result = LoginDatabase.Query("SELECT secId, groupId FROM rbac_security_level_groups ORDER by secId ASC");
+ if (!result)
+ {
+ sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account default groups for security levels definitions. DB table `rbac_security_level_groups` is empty.");
+ return;
+ }
+
+ uint8 lastSecId = 255;
+ RBACGroupContainer* groups = NULL;
+ do
+ {
+ Field* field = result->Fetch();
+ uint8 secId = field[0].GetUInt8();
+
+ if (lastSecId != secId)
+ groups = &_defaultGroups[secId];
+
+ groups->insert(field[1].GetUInt32());
+ }
+ while (result->NextRow());
+
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u permission definitions, %u role definitions and %u group definitions in %u ms", count1, count2, count3, GetMSTimeDiffToNow(oldMSTime));
+}
+
+void AccountMgr::UpdateAccountAccess(RBACData* rbac, uint32 accountId, uint8 securityLevel, int32 realmId)
+{
+ int32 serverRealmId = realmId != -1 ? realmId : ConfigMgr::GetIntDefault("RealmID", 0);
+ bool needDelete = false;
+ if (!rbac)
+ {
+ needDelete = true;
+ rbac = new RBACData(accountId, "", serverRealmId);
+ rbac->LoadFromDB();
+ }
+
+ // Get max security level and realm (checking current realm and -1)
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS_BY_ID);
+ stmt->setUInt32(0, accountId);
+ stmt->setInt32(1, serverRealmId);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+ if (result)
+ {
+ do
+ {
+ Field* field = result->Fetch();
+ uint8 secLevel = field[0].GetUInt8();
+ int32 realmId = field[1].GetUInt32();
+
+ RBACGroupContainer const& groupsToRemove = _defaultGroups[secLevel];
+ for (RBACGroupContainer::const_iterator it = groupsToRemove.begin(); it != groupsToRemove.end(); ++it)
+ rbac->RemoveGroup(*it, realmId);
+ }
+ while (result->NextRow());
+ }
+
+ // Add new groups depending on the new security Level
+ RBACGroupContainer const& groupsToAdd = _defaultGroups[securityLevel];
+ for (RBACGroupContainer::const_iterator it = groupsToAdd.begin(); it != groupsToAdd.end(); ++it)
+ rbac->AddGroup(*it, realmId);
+
+ if (needDelete)
+ delete rbac;
+
+ // Delete old security level from DB
+ if (realmId == -1)
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS);
+ stmt->setUInt32(0, accountId);
+ LoginDatabase.Execute(stmt);
+ }
+ else
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS_BY_REALM);
+ stmt->setUInt32(0, accountId);
+ stmt->setUInt32(1, realmId);
+ LoginDatabase.Execute(stmt);
+ }
+
+ // Add new security level
+ if (securityLevel)
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_ACCESS);
+ stmt->setUInt32(0, accountId);
+ stmt->setUInt8(1, securityLevel);
+ stmt->setInt32(2, realmId);
+ LoginDatabase.Execute(stmt);
+ }
+}
+
+RBACGroup const* AccountMgr::GetRBACGroup(uint32 group) const
+{
+ RBACGroupsContainer::const_iterator it = _groups.find(group);
+ if (it != _groups.end())
+ return it->second;
+
+ return NULL;
+}
+
+RBACRole const* AccountMgr::GetRBACRole(uint32 role) const
+{
+ RBACRolesContainer::const_iterator it = _roles.find(role);
+ if (it != _roles.end())
+ return it->second;
+
+ return NULL;
+}
+
+RBACPermission const* AccountMgr::GetRBACPermission(uint32 permission) const
+{
+ RBACPermissionsContainer::const_iterator it = _permissions.find(permission);
+ if (it != _permissions.end())
+ return it->second;
+
+ return NULL;
+}
diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h
index c8de5688e73..90c533ca5fa 100644
--- a/src/server/game/Accounts/AccountMgr.h
+++ b/src/server/game/Accounts/AccountMgr.h
@@ -19,8 +19,7 @@
#ifndef _ACCMGR_H
#define _ACCMGR_H
-#include "Define.h"
-#include <string>
+#include "RBAC.h"
#include <ace/Singleton.h>
enum AccountOpResult
@@ -35,6 +34,11 @@ enum AccountOpResult
#define MAX_ACCOUNT_STR 16
+typedef std::map<uint32, RBACPermission*> RBACPermissionsContainer;
+typedef std::map<uint32, RBACRole*> RBACRolesContainer;
+typedef std::map<uint32, RBACGroup*> RBACGroupsContainer;
+typedef std::map<uint32, RBACGroupContainer> RBACDefaultSecurityGroupContainer;
+
class AccountMgr
{
friend class ACE_Singleton<AccountMgr, ACE_Null_Mutex>;
@@ -43,7 +47,7 @@ class AccountMgr
AccountMgr();
public:
- static AccountOpResult CreateAccount(std::string username, std::string password);
+ AccountOpResult CreateAccount(std::string username, std::string password);
static AccountOpResult DeleteAccount(uint32 accountId);
static AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword);
static AccountOpResult ChangePassword(uint32 accountId, std::string newPassword);
@@ -62,6 +66,23 @@ class AccountMgr
static bool IsGMAccount(uint32 gmlevel);
static bool IsAdminAccount(uint32 gmlevel);
static bool IsConsoleAccount(uint32 gmlevel);
+
+ void UpdateAccountAccess(RBACData* rbac, uint32 accountId, uint8 securityLevel, int32 realmId);
+
+ void LoadRBAC();
+ RBACGroup const* GetRBACGroup(uint32 group) const;
+ RBACRole const* GetRBACRole(uint32 role) const;
+ RBACPermission const* GetRBACPermission(uint32 permission) const;
+
+ RBACGroupsContainer const& GetRBACGroupList() const { return _groups; }
+ RBACRolesContainer const& GetRBACRoleList() const { return _roles; }
+ RBACPermissionsContainer const& GetRBACPermissionList() const { return _permissions; }
+
+ private:
+ RBACPermissionsContainer _permissions;
+ RBACRolesContainer _roles;
+ RBACGroupsContainer _groups;
+ RBACDefaultSecurityGroupContainer _defaultGroups;
};
#define sAccountMgr ACE_Singleton<AccountMgr, ACE_Null_Mutex>::instance()
diff --git a/src/server/game/Accounts/RBAC.cpp b/src/server/game/Accounts/RBAC.cpp
new file mode 100644
index 00000000000..4a069df05cd
--- /dev/null
+++ b/src/server/game/Accounts/RBAC.cpp
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2008-2013 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 "RBAC.h"
+#include "AccountMgr.h"
+#include "DatabaseEnv.h"
+
+RBACCommandResult RBACData::AddGroup(uint32 groupId, int32 realmId /* = 0 */)
+{
+ // Check if group Id exists
+ RBACGroup const* group = sAccountMgr->GetRBACGroup(groupId);
+ if (!group)
+ return RBAC_ID_DOES_NOT_EXISTS;
+
+ // Already added?
+ std::pair<std::set<uint32>::iterator, bool> ret = _groups.insert(groupId);
+ if (!ret.second)
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_GROUP);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, groupId);
+ stmt->setInt32(2, realmId);
+ LoginDatabase.Execute(stmt);
+
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::RemoveGroup(uint32 groupId, int32 realmId /* = 0 */)
+{
+ // could remove it?
+ if (!_groups.erase(groupId))
+ return RBAC_CANT_REVOKE_NOT_IN_LIST;
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_GROUP);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, groupId);
+ stmt->setInt32(2, realmId);
+ LoginDatabase.Execute(stmt);
+
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::GrantRole(uint32 roleId, int32 realmId /* = 0*/)
+{
+ // Check if role Id exists
+ RBACRole const* role = sAccountMgr->GetRBACRole(roleId);
+ if (!role)
+ return RBAC_ID_DOES_NOT_EXISTS;
+
+ // Check if already added in denied list
+ if (_deniedRoles.find(roleId) != _deniedRoles.end())
+ return RBAC_IN_DENIED_LIST;
+
+ // Already added?
+ std::pair<std::set<uint32>::iterator, bool> ret = _grantedRoles.insert(roleId);
+ if (!ret.second)
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ SaveRole(roleId, true, realmId);
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::DenyRole(uint32 roleId, int32 realmId /* = 0*/)
+{
+ // Check if role Id exists
+ RBACRole const* role = sAccountMgr->GetRBACRole(roleId);
+ if (!role)
+ return RBAC_ID_DOES_NOT_EXISTS;
+
+ // Check if already added in granted list
+ if (_grantedRoles.find(roleId) != _grantedRoles.end())
+ return RBAC_IN_GRANTED_LIST;
+
+ // Already added?
+ std::pair<std::set<uint32>::iterator, bool> ret = _deniedRoles.insert(roleId);
+ if (!ret.second)
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ SaveRole(roleId, false, realmId);
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+void RBACData::SaveRole(uint32 roleId, bool granted, int32 realmId)
+{
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_ROLE);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, roleId);
+ stmt->setBool(2, granted);
+ stmt->setInt32(3, realmId);
+ LoginDatabase.Execute(stmt);
+}
+
+RBACCommandResult RBACData::RevokeRole(uint32 roleId, int32 realmId /* = 0*/)
+{
+ uint8 revoked = _grantedRoles.erase(roleId) + _deniedRoles.erase(roleId);
+
+ // could remove it?
+ if (!revoked)
+ return RBAC_CANT_REVOKE_NOT_IN_LIST;
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_ROLE);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, roleId);
+ stmt->setInt32(2, realmId);
+ LoginDatabase.Execute(stmt);
+
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::GrantPermission(uint32 permissionId, int32 realmId /* = 0*/)
+{
+ // Check if permission Id exists
+ RBACPermission const* perm = sAccountMgr->GetRBACPermission(permissionId);
+ if (!perm)
+ return RBAC_ID_DOES_NOT_EXISTS;
+
+ // Check if already added in denied list
+ if (_deniedPerms.test(permissionId))
+ return RBAC_IN_DENIED_LIST;
+
+ // Already added?
+ if (_grantedPerms.test(permissionId))
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+
+ _grantedPerms.set(permissionId);
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ SavePermission(permissionId, true, realmId);
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::DenyPermission(uint32 permissionId, int32 realmId /* = 0*/)
+{
+ // Check if permission Id exists
+ RBACPermission const* perm = sAccountMgr->GetRBACPermission(permissionId);
+ if (!perm)
+ return RBAC_ID_DOES_NOT_EXISTS;
+
+ // Check if already added in granted list
+ if (_grantedPerms.test(permissionId))
+ return RBAC_IN_GRANTED_LIST;
+
+ // Already added?
+ if (_deniedPerms.test(permissionId))
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+
+ _deniedPerms.set(permissionId);
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ SavePermission(permissionId, false, realmId);
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+void RBACData::SavePermission(uint32 permission, bool granted, int32 realmId)
+{
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, permission);
+ stmt->setBool(2, granted);
+ stmt->setInt32(3, realmId);
+ LoginDatabase.Execute(stmt);
+}
+
+RBACCommandResult RBACData::RevokePermission(uint32 permission, int32 realmId /* = 0*/)
+{
+ // Check if it's present in any list
+ if (!_grantedPerms.test(permission) && !_deniedPerms.test(permission))
+ return RBAC_CANT_REVOKE_NOT_IN_LIST;
+
+ _grantedPerms.reset(permission);
+ _deniedPerms.reset(permission);
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, permission);
+ stmt->setInt32(2, realmId);
+ LoginDatabase.Execute(stmt);
+
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+void RBACData::LoadFromDB()
+{
+ // Load account group that affect current realm
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_GROUPS);
+ stmt->setUInt32(0, GetId());
+ stmt->setInt32(1, GetRealmId());
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ AddGroup(fields[0].GetUInt32());
+ }
+ while (result->NextRow());
+ }
+
+ // Load account roles (granted and denied) that affect current realm
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_ROLES);
+ stmt->setUInt32(0, GetId());
+ stmt->setInt32(1, GetRealmId());
+ result = LoginDatabase.Query(stmt);
+
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ if (fields[1].GetBool())
+ GrantRole(fields[0].GetUInt32());
+ else
+ DenyRole(fields[0].GetUInt32());
+ }
+ while (result->NextRow());
+ }
+
+ // Load account permissions (granted and denied) that affect current realm
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS);
+ stmt->setUInt32(0, GetId());
+ stmt->setInt32(1, GetRealmId());
+
+ result = LoginDatabase.Query(stmt);
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ if (fields[1].GetBool())
+ GrantPermission(fields[0].GetUInt32());
+ else
+ DenyPermission(fields[0].GetUInt32());
+ }
+ while (result->NextRow());
+ }
+
+ // Force calculation of permissions, it wasn't performed at load time
+ // while adding groups, roles and permissions
+ CalculateNewPermissions();
+}
+
+void RBACData::CalculateNewPermissions()
+{
+ // Get the list of directly granted roles
+ RBACRoleContainer tempGrantedRoles = GetGrantedRoles();
+
+ // Add those roles inherited from groups
+ for (RBACGroupContainer::const_iterator itGroup = _groups.begin(); itGroup != _groups.end(); ++itGroup)
+ {
+ RBACGroup const* group = sAccountMgr->GetRBACGroup(*itGroup);
+ if (!group) // Should never happen due to foreign keys in DB
+ continue;
+
+ RBACRoleContainer const& roles = group->GetRoles();
+ for (RBACRoleContainer::const_iterator it = roles.begin(); it != roles.end(); ++it)
+ tempGrantedRoles.insert(*it);
+ }
+
+ // Get the list of granted permissions
+ _globalPerms = GetGrantedPermissions();
+
+ // Add those permissions inherited from roles granted
+ for (RBACRoleContainer::const_iterator it = tempGrantedRoles.begin(); it != tempGrantedRoles.end(); ++it)
+ if (RBACRole const* role = sAccountMgr->GetRBACRole(*it))
+ _globalPerms |= role->GetPermissions();
+
+ // Remove denied permissions from the list
+ _globalPerms &= ~GetDeniedPermissions();
+
+ // Remove those permissions inherited from denied roles
+ for (RBACRoleContainer::const_iterator it = _deniedRoles.begin(); it != _deniedRoles.end(); ++it)
+ if (RBACRole const* role = sAccountMgr->GetRBACRole(*it))
+ _globalPerms &= ~role->GetPermissions();
+}
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
new file mode 100644
index 00000000000..d2c76b71801
--- /dev/null
+++ b/src/server/game/Accounts/RBAC.h
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2008-2013 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/>.
+ */
+
+/**
+* @file RBAC.h
+* @brief Role Based Access Control related classes definition
+*
+* This file contains all the classes and enums used to implement
+* Role Based Access Control
+*
+* RBAC Rules:
+* - Pemission: Defines an autorization to perform certain operation.
+* - Role: Set of permissions.
+* - Group: Set of roles.
+* - An Account can have multiple groups, roles and permissions.
+* - Account Groups can only be granted or revoked
+* - Account Roles and Permissions can be granted, denied or revoked
+* - Grant: Assignment of the object (role/permission) and allow it
+* - Deny: Assignment of the object (role/permission) and deny it
+* - Revoke: Removal of the object (role/permission) no matter if it was granted or denied
+* - Global Permissions are computed as:
+* Group Grants + Role Grants + User Grans - Role Grants - User Grants
+* - Groups, Roles and Permissions can be assigned by realm
+*/
+
+#ifndef _RBAC_H
+#define _RBAC_H
+
+#include "Define.h"
+#include <string>
+#include <bitset>
+#include <set>
+#include <map>
+
+enum RBACPermissions
+{
+ RBAC_PERM_INSTANT_LOGOUT = 1,
+ RBAC_PERM_SKIP_QUEUE,
+ RBAC_PERM_JOIN_NORMAL_BG,
+ RBAC_PERM_JOIN_RANDOM_BG,
+ RBAC_PERM_JOIN_ARENAS,
+ RBAC_PERM_JOIN_DUNGEON_FINDER,
+ RBAC_PERM_PLAYER_COMMANDS,
+ RBAC_PERM_MODERATOR_COMMANDS,
+ RBAC_PERM_GAMEMASTER_COMMANDS,
+ RBAC_PERM_ADMINISTRATOR_COMMANDS,
+ RBAC_PERM_MAX
+};
+
+enum RBACCommandResult
+{
+ RBAC_OK,
+ RBAC_CANT_ADD_ALREADY_ADDED,
+ RBAC_CANT_REVOKE_NOT_IN_LIST,
+ RBAC_IN_GRANTED_LIST,
+ RBAC_IN_DENIED_LIST,
+ RBAC_ID_DOES_NOT_EXISTS
+};
+
+typedef std::bitset<RBAC_PERM_MAX> RBACPermissionContainer;
+typedef std::set<uint32> RBACRoleContainer;
+typedef std::set<uint32> RBACGroupContainer;
+
+class RBACObject
+{
+ public:
+ RBACObject(uint32 id = 0, std::string const& name = ""):
+ _id(id), _name(name) { }
+
+ /// Gets the Name of the Object
+ std::string const& GetName() const { return _name; }
+ /// Gets the Id of the Object
+ uint32 GetId() const { return _id; }
+
+ private:
+ uint32 _id; ///> id of the object
+ std::string _name; ///> name of the object
+};
+
+/// Permission: Defines an autorization to perform certain operation
+class RBACPermission: public RBACObject
+{
+ public:
+ RBACPermission(uint32 id = 0, std::string const& name = ""):
+ RBACObject(id, name) { }
+};
+
+/// Set of Permissions
+class RBACRole: public RBACObject
+{
+ public:
+ RBACRole(uint32 id = 0, std::string const& name = ""):
+ RBACObject(id, name) { }
+
+ /// Gets the Permissions assigned to this role
+ RBACPermissionContainer const& GetPermissions() const { return _perms; }
+ /// Grants a Permission (Adds)
+ void GrantPermission(uint32 id) { _perms.set(id); }
+ /// Revokes a Permission (Removes)
+ void RevokePermission(uint32 id) { _perms.reset(id); }
+
+ private:
+ RBACPermissionContainer _perms; ///> Set of permissions
+};
+
+/// Set of Roles
+class RBACGroup: public RBACObject
+{
+ public:
+ RBACGroup(uint32 id = 0, std::string const& name = ""):
+ RBACObject(id, name) { }
+
+ /// Gets the Roles assigned to this group
+ RBACRoleContainer const& GetRoles() const { return _roles; }
+ /// Grants a Role (Adds)
+ void GrantRole(uint32 role) { _roles.insert(role); }
+ /// Revokes a Role (Removes)
+ void RevokeRole(uint32 role) { _roles.erase(role); }
+
+ private:
+ RBACRoleContainer _roles; ///> Set of Roles
+};
+
+/*
+ * @name RBACData
+ * @brief Contains all needed information about the acccount
+ *
+ * This class contains all the data needed to calculate the account permissions.
+ * RBACDAta is formed by group permissions and user permissions through:
+ * - Granted Groups, which contains roles, which contains permissions: Set of granted permissions
+ * - Granted Roles, which contains permissions: Set of granted permissions
+ * - Denied Roles, which contains permissions: Set of denied permissions
+ * - Granted Permissions
+ * - Denied Permissions
+ *
+ * Calculation of current Permissions: Granted permissions - Denied permissions
+ * - Granted permissions: through groups, through roles and directly assigned
+ * - Denied permissions: through roles and directly assigned
+ */
+class RBACData: public RBACObject
+{
+ public:
+ RBACData(uint32 id, std::string const& name, int32 realmId):
+ RBACObject(id, name), _realmId(realmId) { }
+
+ /**
+ * @name HasPermission
+ * @brief Checks if certain action is allowed
+ *
+ * Checks if certain action can be performed.
+ *
+ * @return grant or deny action
+ *
+ * Example Usage:
+ * @code
+ * bool Player::CanJoinArena(Battleground* bg)
+ * {
+ * return bg->isArena() && HasPermission(RBAC_PERM_JOIN_ARENA);
+ * }
+ * @endcode
+ */
+ bool HasPermission(uint32 permission) { return _globalPerms.test(permission); }
+
+ // Functions enabled to be used by command system
+ /// Returns all the granted permissions (after computation)
+ RBACPermissionContainer const& GetPermissions() const { return _globalPerms; }
+ /// Returns all the granted permissions
+ RBACPermissionContainer const& GetGrantedPermissions() const { return _grantedPerms; }
+ /// Returns all the denied permissions
+ RBACPermissionContainer const& GetDeniedPermissions() const { return _deniedPerms; }
+ /// Returns all the granted roles
+ RBACRoleContainer const& GetGrantedRoles() const { return _grantedRoles; }
+ /// Returns all the denied roles
+ RBACRoleContainer const& GetDeniedRoles() const { return _deniedRoles; }
+ /// Returns all the granted groups
+ RBACGroupContainer const& GetGroups() const { return _groups; }
+
+ /**
+ * @name AddGroup
+ * @brief Adds new group
+ *
+ * Add a new group to the account. If realm is 0 or the group can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if group Id does not exists or group already present
+ *
+ * @param groupId group to be added
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to add the group
+ *
+ * Example Usage:
+ * @code
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 groupId = 2;
+ * if (rbac->AddGroup(groupId) == RBAC_OK)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Group %u succesfully added", groupId);
+ * @endcode
+ */
+ RBACCommandResult AddGroup(uint32 groupId, int32 realmId = 0);
+
+ /**
+ * @name RemoveGroup
+ * @brief Removes a group
+ *
+ * Removes a group from the account. If realm is 0 or the group can not be removed
+ * No save to db action will be performed. Any delete operation will always affect
+ * "all realms (-1)" in addition to the realm specified
+ *
+ * Fails if group not present
+ *
+ * @param groupId group to be removed
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to remove the group
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 groupId = 2;
+ * if (rbac->RemoveGroup(groupId) == RBAC_OK)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Group %u succesfully removed", groupId);
+ * @endcode
+ */
+ RBACCommandResult RemoveGroup(uint32 groupId, int32 realmId = 0);
+
+ /**
+ * @name GrantRole
+ * @brief Grants a role
+ *
+ * Grants a role to the account. If realm is 0 or the role can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if role Id does not exists or role already granted or denied
+ *
+ * @param roleId role to be granted
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to grant the role
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 roleId = 2;
+ * if (rbac->GrantRole(roleId) == RBAC_IN_DENIED_LIST)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Failed to grant role %u, already denied", roleId);
+ * @endcode
+ */
+ RBACCommandResult GrantRole(uint32 roleId, int32 realmId = 0);
+
+ /**
+ * @name DenyRole
+ * @brief Denies a role
+ *
+ * Denied a role to the account. If realm is 0 or the role can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if role Id does not exists or role already granted or denied
+ *
+ * @param roleId role to be denied
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to deny the role
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 roleId = 2;
+ * if (rbac->DenyRole(roleId) == RBAC_ID_DOES_NOT_EXISTS)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Role Id %u does not exists", roleId);
+ * @endcode
+ */
+ RBACCommandResult DenyRole(uint32 roleId, int32 realmId = 0);
+
+ /**
+ * @name RevokeRole
+ * @brief Removes a role
+ *
+ * Removes a role from the account. If realm is 0 or the role can not be removed
+ * No save to db action will be performed. Any delete operation will always affect
+ * "all realms (-1)" in addition to the realm specified
+ *
+ * Fails if role not present
+ *
+ * @param roleId role to be removed
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to remove the role
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 roleId = 2;
+ * if (rbac->RevokeRole(roleId) == RBAC_OK)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Role %u succesfully removed", roleId);
+ * @endcode
+ */
+ RBACCommandResult RevokeRole(uint32 roleId, int32 realmId = 0);
+
+ /**
+ * @name GrantRole
+ * @brief Grants a permission
+ *
+ * Grants a permission to the account. If realm is 0 or the permission can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if permission Id does not exists or permission already granted or denied
+ *
+ * @param permissionId permission to be granted
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to grant the permission
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 permissionId = 2;
+ * if (rbac->GrantRole(permissionId) == RBAC_IN_DENIED_LIST)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Failed to grant permission %u, already denied", permissionId);
+ * @endcode
+ */
+ RBACCommandResult GrantPermission(uint32 permissionId, int32 realmId = 0);
+
+ /**
+ * @name DenyPermission
+ * @brief Denies a permission
+ *
+ * Denied a permission to the account. If realm is 0 or the permission can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if permission Id does not exists or permission already granted or denied
+ *
+ * @param permissionId permission to be denied
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to deny the permission
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 permissionId = 2;
+ * if (rbac->DenyRole(permissionId) == RBAC_ID_DOES_NOT_EXISTS)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Role Id %u does not exists", permissionId);
+ * @endcode
+ */
+ RBACCommandResult DenyPermission(uint32 permissionId, int32 realmId = 0);
+
+ /**
+ * @name RevokePermission
+ * @brief Removes a permission
+ *
+ * Removes a permission from the account. If realm is 0 or the permission can not be removed
+ * No save to db action will be performed. Any delete operation will always affect
+ * "all realms (-1)" in addition to the realm specified
+ *
+ * Fails if permission not present
+ *
+ * @param permissionId permission to be removed
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to remove the permission
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 permissionId = 2;
+ * if (rbac->RevokeRole(permissionId) == RBAC_OK)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Permission %u succesfully removed", permissionId);
+ * @endcode
+ */
+ RBACCommandResult RevokePermission(uint32 permissionId, int32 realmId = 0);
+
+ /// Loads all permissions, groups and roles assigned to current account
+ void LoadFromDB();
+ private:
+ /// Saves a role to DB, Granted or Denied
+ void SaveRole(uint32 role, bool granted, int32 realm);
+ /// Saves a permission to DB, Granted or Denied
+ void SavePermission(uint32 role, bool granted, int32 realm);
+
+ /**
+ * @name CalculateNewPermissions
+ * @brief Calculates new permissions
+ *
+ * Calculates new permissions after some change in groups, roles or permissions.
+ * The calculation is done Granted - Denied:
+ * - Granted permissions: through groups, through roles and directly assigned
+ * - Denied permissions: through roles and directly assigned
+ */
+ void CalculateNewPermissions();
+
+ int32 GetRealmId() { return _realmId; }
+
+ int32 _realmId; ///> RealmId Affected
+ RBACGroupContainer _groups; ///> Granted groups
+ RBACRoleContainer _grantedRoles; ///> Granted roles
+ RBACRoleContainer _deniedRoles; ///> Denied roles
+ RBACPermissionContainer _grantedPerms; ///> Granted permissions
+ RBACPermissionContainer _deniedPerms; ///> Denied permissions
+ RBACPermissionContainer _globalPerms; ///> Calculated permissions
+};
+
+#endif
diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp
index d754ef967e6..c71b85b2d27 100644
--- a/src/server/game/Achievements/AchievementMgr.cpp
+++ b/src/server/game/Achievements/AchievementMgr.cpp
@@ -3151,14 +3151,14 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
}
uint32 dataType = fields[1].GetUInt8();
- const char* scriptName = fields[4].GetCString();
+ std::string scriptName = fields[4].GetString();
uint32 scriptId = 0;
- if (strcmp(scriptName, "")) // not empty
+ if (scriptName.length()) // not empty
{
if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT)
sLog->outError(LOG_FILTER_SQL, "Table `achievement_criteria_data` has ScriptName set for non-scripted data type (Entry: %u, type %u), useless data.", criteria_id, dataType);
else
- scriptId = sObjectMgr->GetScriptId(scriptName);
+ scriptId = sObjectMgr->GetScriptId(scriptName.c_str());
}
AchievementCriteriaData data(dataType, fields[2].GetUInt32(), fields[3].GetUInt32(), scriptId);
diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp
index ec118b44f59..393206f4202 100644
--- a/src/server/game/Battlefield/Battlefield.cpp
+++ b/src/server/game/Battlefield/Battlefield.cpp
@@ -162,16 +162,17 @@ bool Battlefield::Update(uint32 diff)
// Kick players who chose not to accept invitation to the battle
if (m_uiKickDontAcceptTimer <= diff)
{
+ time_t now = time(NULL);
for (int team = 0; team < 2; team++)
for (PlayerTimerMap::iterator itr = m_InvitedPlayers[team].begin(); itr != m_InvitedPlayers[team].end(); ++itr)
- if ((*itr).second <= time(NULL))
- KickPlayerFromBattlefield((*itr).first);
+ if (itr->second <= now)
+ KickPlayerFromBattlefield(itr->first);
InvitePlayersInZoneToWar();
for (int team = 0; team < 2; team++)
for (PlayerTimerMap::iterator itr = m_PlayersWillBeKick[team].begin(); itr != m_PlayersWillBeKick[team].end(); ++itr)
- if ((*itr).second <= time(NULL))
- KickPlayerFromBattlefield((*itr).first);
+ if (itr->second <= now)
+ KickPlayerFromBattlefield(itr->first);
m_uiKickDontAcceptTimer = 1000;
}
@@ -819,7 +820,7 @@ Creature* Battlefield::SpawnCreature(uint32 entry, Position pos, TeamId team)
Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, float o, TeamId team)
{
//Get map object
- Map* map = const_cast<Map*>(sMapMgr->CreateBaseMap(m_MapId));
+ Map* map = sMapMgr->CreateBaseMap(m_MapId);
if (!map)
{
sLog->outError(LOG_FILTER_BATTLEFIELD, "Battlefield::SpawnCreature: Can't create creature entry: %u map not found", entry);
@@ -857,7 +858,7 @@ Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, fl
GameObject* Battlefield::SpawnGameObject(uint32 entry, float x, float y, float z, float o)
{
// Get map object
- Map* map = const_cast<Map*>(sMapMgr->CreateBaseMap(571)); // *vomits*
+ Map* map = sMapMgr->CreateBaseMap(571); // *vomits*
if (!map)
return 0;
diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h
index fea5ee2e7db..9b3542fca65 100644
--- a/src/server/game/Battlefield/Battlefield.h
+++ b/src/server/game/Battlefield/Battlefield.h
@@ -72,7 +72,7 @@ class BfGraveyard;
typedef std::set<uint64> GuidSet;
typedef std::vector<BfGraveyard*> GraveyardVect;
-typedef std::map<uint64, uint32> PlayerTimerMap;
+typedef std::map<uint64, time_t> PlayerTimerMap;
class BfCapturePoint
{
diff --git a/src/server/game/Battlegrounds/ArenaTeam.cpp b/src/server/game/Battlegrounds/ArenaTeam.cpp
index 1d99b5fd5fe..4fe00ff123c 100644
--- a/src/server/game/Battlegrounds/ArenaTeam.cpp
+++ b/src/server/game/Battlegrounds/ArenaTeam.cpp
@@ -41,14 +41,16 @@ ArenaTeam::ArenaTeam()
ArenaTeam::~ArenaTeam()
{ }
-bool ArenaTeam::Create(uint64 captainGuid, uint8 type, std::string const& teamName, uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor, uint8 borderStyle, uint32 borderColor)
+bool ArenaTeam::Create(uint64 captainGuid, uint8 type, std::string const& arenaTeamName,
+ uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor,
+ uint8 borderStyle, uint32 borderColor)
{
// Check if captain is present
if (!ObjectAccessor::FindPlayer(captainGuid))
return false;
// Check if arena team name is already taken
- if (sArenaTeamMgr->GetArenaTeamByName(teamName))
+ if (sArenaTeamMgr->GetArenaTeamByName(arenaTeamName))
return false;
// Generate new arena team id
@@ -57,7 +59,7 @@ bool ArenaTeam::Create(uint64 captainGuid, uint8 type, std::string const& teamNa
// Assign member variables
CaptainGuid = captainGuid;
Type = type;
- TeamName = teamName;
+ TeamName = arenaTeamName;
BackgroundColor = backgroundColor;
EmblemStyle = emblemStyle;
EmblemColor = emblemColor;
@@ -82,7 +84,7 @@ bool ArenaTeam::Create(uint64 captainGuid, uint8 type, std::string const& teamNa
// Add captain as member
AddMember(CaptainGuid);
- sLog->outInfo(LOG_FILTER_ARENAS, "New ArenaTeam created [Id: %u] [Type: %u] [Captain low GUID: %u]", GetId(), GetType(), captainLowGuid);
+ sLog->outDebug(LOG_FILTER_ARENAS, "New ArenaTeam created [Id: %u] [Type: %u] [Captain low GUID: %u]", GetId(), GetType(), captainLowGuid);
return true;
}
@@ -179,7 +181,7 @@ bool ArenaTeam::AddMember(uint64 playerGuid)
player->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_MEMBER, 1);
}
- sLog->outInfo(LOG_FILTER_ARENAS, "Player: %s [GUID: %u] joined arena team type: %u [Id: %u, Name: %s].", playerName.c_str(), GUID_LOPART(playerGuid), GetType(), GetId(), GetName().c_str());
+ sLog->outDebug(LOG_FILTER_ARENAS, "Player: %s [GUID: %u] joined arena team type: %u [Id: %u, Name: %s].", playerName.c_str(), GUID_LOPART(playerGuid), GetType(), GetId(), GetName().c_str());
return true;
}
@@ -291,7 +293,7 @@ void ArenaTeam::SetCaptain(uint64 guid)
newCaptain->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_MEMBER, 0);
if (oldCaptain)
{
- sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Player: %s [GUID: %u] promoted player: %s [GUID: %u] to leader of arena team [Id: %u] [Type: %u].",
+ sLog->outDebug(LOG_FILTER_ARENAS, "Player: %s [GUID: %u] promoted player: %s [GUID: %u] to leader of arena team [Id: %u] [Type: %u].",
oldCaptain->GetName().c_str(), oldCaptain->GetGUIDLow(), newCaptain->GetName().c_str(),
newCaptain->GetGUIDLow(), GetId(), GetType());
}
@@ -308,10 +310,9 @@ void ArenaTeam::DelMember(uint64 guid, bool cleanDb)
break;
}
- // Inform player and remove arena team info from player data
+ // Remove arena team info from player data
if (Player* player = ObjectAccessor::FindPlayer(guid))
{
- player->GetSession()->SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, GetName(), "", 0);
// delete all info regarding this team
for (uint32 i = 0; i < ARENA_TEAM_END; ++i)
player->SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType(i), 0);
@@ -330,19 +331,18 @@ void ArenaTeam::DelMember(uint64 guid, bool cleanDb)
void ArenaTeam::Disband(WorldSession* session)
{
- // Remove all members from arena team
- while (!Members.empty())
- DelMember(Members.front().Guid, false);
-
// Broadcast update
if (session)
{
BroadcastEvent(ERR_ARENA_TEAM_DISBANDED_S, 0, 2, session->GetPlayerName(), GetName(), "");
-
if (Player* player = session->GetPlayer())
sLog->outDebug(LOG_FILTER_ARENAS, "Player: %s [GUID: %u] disbanded arena team type: %u [Id: %u].", player->GetName().c_str(), player->GetGUIDLow(), GetType(), GetId());
}
+ // Remove all members from arena team
+ while (!Members.empty())
+ DelMember(Members.front().Guid, false);
+
// Update database
SQLTransaction trans = CharacterDatabase.BeginTransaction();
@@ -580,7 +580,7 @@ uint32 ArenaTeam::GetAverageMMR(Group* group) const
if (!ObjectAccessor::FindPlayer(itr->Guid))
continue;
- // Skip if player is not member of group
+ // Skip if player is not a member of group
if (!group->IsMember(itr->Guid))
continue;
@@ -604,7 +604,7 @@ float ArenaTeam::GetChanceAgainst(uint32 ownRating, uint32 opponentRating)
return 1.0f / (1.0f + exp(log(10.0f) * (float)((float)opponentRating - (float)ownRating) / 650.0f));
}
-int32 ArenaTeam::GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating, bool won /*, float& confidence_factor*/)
+int32 ArenaTeam::GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating, bool won)
{
// 'Chance' calculation - to beat the opponent
// This is a simulation. Not much info on how it really works
@@ -683,17 +683,17 @@ void ArenaTeam::FinishGame(int32 mod)
}
}
-int32 ArenaTeam::WonAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change)
+int32 ArenaTeam::WonAgainst(uint32 ownMMRating, uint32 opponentMMRating, int32& ratingChange)
{
// Called when the team has won
// Change in Matchmaker rating
- int32 mod = GetMatchmakerRatingMod(Own_MMRating, Opponent_MMRating, true);
+ int32 mod = GetMatchmakerRatingMod(ownMMRating, opponentMMRating, true);
// Change in Team Rating
- rating_change = GetRatingMod(Stats.Rating, Opponent_MMRating, true);
+ ratingChange = GetRatingMod(Stats.Rating, opponentMMRating, true);
// Modify the team stats accordingly
- FinishGame(rating_change);
+ FinishGame(ratingChange);
// Update number of wins per season and week
Stats.WeekWins += 1;
@@ -703,23 +703,23 @@ int32 ArenaTeam::WonAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32
return mod;
}
-int32 ArenaTeam::LostAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change)
+int32 ArenaTeam::LostAgainst(uint32 ownMMRating, uint32 opponentMMRating, int32& ratingChange)
{
// Called when the team has lost
// Change in Matchmaker Rating
- int32 mod = GetMatchmakerRatingMod(Own_MMRating, Opponent_MMRating, false);
+ int32 mod = GetMatchmakerRatingMod(ownMMRating, opponentMMRating, false);
// Change in Team Rating
- rating_change = GetRatingMod(Stats.Rating, Opponent_MMRating, false);
+ ratingChange = GetRatingMod(Stats.Rating, opponentMMRating, false);
// Modify the team stats accordingly
- FinishGame(rating_change);
+ FinishGame(ratingChange);
// return the rating change, used to display it on the results screen
return mod;
}
-void ArenaTeam::MemberLost(Player* player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange)
+void ArenaTeam::MemberLost(Player* player, uint32 againstMatchmakerRating, int32 matchmakerRatingChange)
{
// Called for each participant of a match after losing
for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
@@ -731,7 +731,7 @@ void ArenaTeam::MemberLost(Player* player, uint32 againstMatchmakerRating, int32
itr->ModifyPersonalRating(player, mod, GetType());
// Update matchmaker rating
- itr->ModifyMatchmakerRating(MatchmakerRatingChange, GetSlot());
+ itr->ModifyMatchmakerRating(matchmakerRatingChange, GetSlot());
// Update personal played stats
itr->WeekGames +=1;
@@ -745,7 +745,7 @@ void ArenaTeam::MemberLost(Player* player, uint32 againstMatchmakerRating, int32
}
}
-void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange)
+void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, int32 matchmakerRatingChange)
{
// Called for offline player after ending rated arena match!
for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
@@ -757,7 +757,7 @@ void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, i
itr->ModifyPersonalRating(NULL, mod, GetType());
// update matchmaker rating
- itr->ModifyMatchmakerRating(MatchmakerRatingChange, GetSlot());
+ itr->ModifyMatchmakerRating(matchmakerRatingChange, GetSlot());
// update personal played stats
itr->WeekGames += 1;
@@ -767,7 +767,7 @@ void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, i
}
}
-void ArenaTeam::MemberWon(Player* player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange)
+void ArenaTeam::MemberWon(Player* player, uint32 againstMatchmakerRating, int32 matchmakerRatingChange)
{
// called for each participant after winning a match
for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
@@ -779,7 +779,7 @@ void ArenaTeam::MemberWon(Player* player, uint32 againstMatchmakerRating, int32
itr->ModifyPersonalRating(player, mod, GetType());
// update matchmaker rating
- itr->ModifyMatchmakerRating(MatchmakerRatingChange, GetSlot());
+ itr->ModifyMatchmakerRating(matchmakerRatingChange, GetSlot());
// update personal stats
itr->WeekGames +=1;
diff --git a/src/server/game/Battlegrounds/ArenaTeam.h b/src/server/game/Battlegrounds/ArenaTeam.h
index dc75ff64575..59b1275a549 100644
--- a/src/server/game/Battlegrounds/ArenaTeam.h
+++ b/src/server/game/Battlegrounds/ArenaTeam.h
@@ -19,9 +19,10 @@
#ifndef TRINITYCORE_ARENATEAM_H
#define TRINITYCORE_ARENATEAM_H
+#include "Define.h"
#include "QueryResult.h"
-#include <ace/Singleton.h>
#include <list>
+#include <string>
#include <map>
class WorldSession;
@@ -72,14 +73,6 @@ enum ArenaTeamEvents
ERR_ARENA_TEAM_DISBANDED_S = 8 // captain name + arena team name
};
-/*
-need info how to send these ones:
-ERR_ARENA_TEAM_YOU_JOIN_S - client show it automatically when accept invite
-ERR_ARENA_TEAM_TARGET_TOO_LOW_S
-ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S
-ERR_ARENA_TEAM_LEVEL_TOO_LOW_I
-*/
-
enum ArenaTeamTypes
{
ARENA_TEAM_2v2 = 2,
@@ -121,18 +114,20 @@ class ArenaTeam
ArenaTeam();
~ArenaTeam();
- bool Create(uint64 captainGuid, uint8 type, std::string const& teamName, uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor, uint8 borderStyle, uint32 borderColor);
+ bool Create(uint64 captainGuid, uint8 type, std::string const& teamName,
+ uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor,
+ uint8 borderStyle, uint32 borderColor);
void Disband(WorldSession* session);
typedef std::list<ArenaTeamMember> MemberList;
- uint32 GetId() const { return TeamId; }
- uint32 GetType() const { return Type; }
- uint8 GetSlot() const { return GetSlotByType(GetType()); }
+ uint32 GetId() const { return TeamId; }
+ uint32 GetType() const { return Type; }
+ uint8 GetSlot() const { return GetSlotByType(GetType()); }
static uint8 GetSlotByType(uint32 type);
static uint8 GetTypeBySlot(uint8 slot);
- uint64 GetCaptain() const { return CaptainGuid; }
- std::string const& GetName() const { return TeamName; }
+ uint64 GetCaptain() const { return CaptainGuid; }
+ std::string const& GetName() const { return TeamName; }
const ArenaTeamStats& GetStats() const { return Stats; }
uint32 GetRating() const { return Stats.Rating; }
@@ -140,15 +135,10 @@ class ArenaTeam
void SetCaptain(uint64 guid);
bool AddMember(uint64 PlayerGuid);
-
- // Shouldn't be uint64 ed, because than can reference guid from members on Disband
- // and this method removes given record from list. So invalid reference can happen.
void DelMember(uint64 guid, bool cleanDb);
size_t GetMembersSize() const { return Members.size(); }
bool Empty() const { return Members.empty(); }
- MemberList::iterator m_membersBegin() { return Members.begin(); }
- MemberList::iterator m_membersEnd() { return Members.end(); }
bool IsMember(uint64 guid) const;
ArenaTeamMember* GetMember(uint64 guid);
@@ -172,24 +162,26 @@ class ArenaTeam
void SendStats(WorldSession* session);
void Inspect(WorldSession* session, uint64 guid);
- int32 GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating, bool won);
- int32 GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won);
- float GetChanceAgainst(uint32 ownRating, uint32 opponentRating);
- int32 WonAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change);
- void MemberWon(Player* player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange);
- int32 LostAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change);
- void MemberLost(Player* player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange = -12);
- void OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange = -12);
+ static int32 GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating, bool won);
+ static int32 GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won);
+ static float GetChanceAgainst(uint32 ownRating, uint32 opponentRating);
+
+ int32 WonAgainst(uint32 ownMMRating, uint32 opponentMMRating, int32& rating_change);
+ void MemberWon(Player* player, uint32 againstMatchmakerRating, int32 matchmakerRatingChange = 12);
+
+ int32 LostAgainst(uint32 ownMMRating, uint32 opponentMMRating, int32& rating_change);
+ void MemberLost(Player* player, uint32 againstMatchmakerRating, int32 matchmakerRatingChange = -12);
+ void OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, int32 matchmakerRatingChange = -12);
void FinishWeek();
void FinishGame(int32 mod);
protected:
- uint32 TeamId;
- uint8 Type;
+ uint32 TeamId;
+ uint8 Type;
std::string TeamName;
- uint64 CaptainGuid;
+ uint64 CaptainGuid;
uint32 BackgroundColor; // ARGB format
uint8 EmblemStyle; // icon id
@@ -197,7 +189,7 @@ class ArenaTeam
uint8 BorderStyle; // border image id
uint32 BorderColor; // ARGB format
- MemberList Members;
+ MemberList Members;
ArenaTeamStats Stats;
};
#endif
diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp
index c370b3a26ce..1061f8aadba 100644
--- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp
+++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp
@@ -891,6 +891,27 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId original
bg->SetRandom(isRandom);
bg->SetGuid(MAKE_NEW_GUID(bgTypeId, 0, HIGHGUID_BATTLEGROUND));
+ // Set up correct min/max player counts for scoreboards
+ if (bg->isArena())
+ {
+ uint32 maxPlayersPerTeam = 0;
+ switch (arenaType)
+ {
+ case ARENA_TYPE_2v2:
+ maxPlayersPerTeam = 2;
+ break;
+ case ARENA_TYPE_3v3:
+ maxPlayersPerTeam = 3;
+ break;
+ case ARENA_TYPE_5v5:
+ maxPlayersPerTeam = 5;
+ break;
+ }
+
+ bg->SetMaxPlayersPerTeam(maxPlayersPerTeam);
+ bg->SetMaxPlayers(maxPlayersPerTeam * 2);
+ }
+
return bg;
}
@@ -957,8 +978,8 @@ bool BattlegroundMgr::CreateBattleground(CreateBattlegroundData& data)
bg->SetArenaorBGType(data.IsArena);
bg->SetMinPlayersPerTeam(data.MinPlayersPerTeam);
bg->SetMaxPlayersPerTeam(data.MaxPlayersPerTeam);
- bg->SetMinPlayers(data.MinPlayersPerTeam* 2);
- bg->SetMaxPlayers(data.MaxPlayersPerTeam* 2);
+ bg->SetMinPlayers(data.MinPlayersPerTeam * 2);
+ bg->SetMaxPlayers(data.MaxPlayersPerTeam * 2);
bg->SetName(data.BattlegroundName);
bg->SetTeamStartLoc(ALLIANCE, data.Team1StartLocX, data.Team1StartLocY, data.Team1StartLocZ, data.Team1StartLocO);
bg->SetTeamStartLoc(HORDE, data.Team2StartLocX, data.Team2StartLocY, data.Team2StartLocZ, data.Team2StartLocO);
diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt
index 12de44ac57f..be3997243e4 100644
--- a/src/server/game/CMakeLists.txt
+++ b/src/server/game/CMakeLists.txt
@@ -102,6 +102,8 @@ set(game_STAT_SRCS
include_directories(
${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/dep/zlib
diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp
index 1cbea4df7ed..12a98126dbf 100644
--- a/src/server/game/Chat/Chat.cpp
+++ b/src/server/game/Chat/Chat.cpp
@@ -122,8 +122,28 @@ const char *ChatHandler::GetTrinityString(int32 entry) const
bool ChatHandler::isAvailable(ChatCommand const& cmd) const
{
- // check security level only for simple command (without child commands)
- return m_session->GetSecurity() >= AccountTypes(cmd.SecurityLevel);
+ uint32 permission = 0;
+
+ ///@Workaround:: Fast adaptation to RBAC system till all commands are moved to permissions
+ switch (AccountTypes(cmd.SecurityLevel))
+ {
+ case SEC_ADMINISTRATOR:
+ permission = RBAC_PERM_ADMINISTRATOR_COMMANDS;
+ break;
+ case SEC_GAMEMASTER:
+ permission = RBAC_PERM_GAMEMASTER_COMMANDS;
+ break;
+ case SEC_MODERATOR:
+ permission = RBAC_PERM_MODERATOR_COMMANDS;
+ break;
+ case SEC_PLAYER:
+ permission = RBAC_PERM_PLAYER_COMMANDS;
+ break;
+ default: // Allow custom security levels for commands
+ return m_session->GetSecurity() >= AccountTypes(cmd.SecurityLevel);
+ }
+
+ return m_session->HasPermission(permission);
}
bool ChatHandler::HasLowerSecurity(Player* target, uint64 guid, bool strong)
@@ -431,7 +451,7 @@ bool ChatHandler::ParseCommands(char const* text)
std::string fullcmd = text;
- if (m_session && AccountMgr::IsPlayerAccount(m_session->GetSecurity()) && !sWorld->getBoolConfig(CONFIG_ALLOW_PLAYER_COMMANDS))
+ if (m_session && !m_session->HasPermission(RBAC_PERM_PLAYER_COMMANDS))
return false;
/// chat case (.command or !command format)
diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp
index bedc167b711..249c1696348 100644
--- a/src/server/game/Combat/ThreatManager.cpp
+++ b/src/server/game/Combat/ThreatManager.cpp
@@ -416,20 +416,17 @@ void ThreatManager::addThreat(Unit* victim, float threat, SpellSchoolMask school
void ThreatManager::doAddThreat(Unit* victim, float threat)
{
- uint32 reducedThreadPercent = victim->GetReducedThreatPercent();
+ uint32 redirectThreadPct = victim->GetRedirectThreatPercent();
// must check > 0.0f, otherwise dead loop
- if (threat > 0.0f && reducedThreadPercent)
+ if (threat > 0.0f && redirectThreadPct)
{
- Unit* redirectTarget = victim->GetMisdirectionTarget();
- if (redirectTarget)
- if (Aura* glyphAura = redirectTarget->GetAura(63326)) // Glyph of Vigilance
- reducedThreadPercent += glyphAura->GetSpellInfo()->Effects[0].CalcValue(glyphAura->GetCaster());
-
- float reducedThreat = threat * reducedThreadPercent / 100.0f;
- threat -= reducedThreat;
- if (redirectTarget)
- _addThreat(redirectTarget, reducedThreat);
+ if (Unit* redirectTarget = victim->GetRedirectThreatTarget())
+ {
+ float redirectThreat = CalculatePct(threat, redirectThreadPct);
+ threat -= redirectThreat;
+ _addThreat(redirectTarget, redirectThreat);
+ }
}
_addThreat(victim, threat);
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index 06c7cd17492..bc1fd27e093 100644
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -794,7 +794,7 @@ void ConditionMgr::LoadConditions(bool isReload)
if (!result)
{
- sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 conditions. DB table `conditions` is empty!");
+ sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 conditions. DB table `conditions` is empty!");
return;
}
diff --git a/src/server/game/Conditions/DisableMgr.cpp b/src/server/game/Conditions/DisableMgr.cpp
index fefb51323c4..7e379fdaded 100644
--- a/src/server/game/Conditions/DisableMgr.cpp
+++ b/src/server/game/Conditions/DisableMgr.cpp
@@ -42,7 +42,7 @@ namespace
DisableMap m_DisableMap;
- uint8 MAX_DISABLE_TYPES = 7;
+ uint8 MAX_DISABLE_TYPES = 8;
}
void LoadDisables()
@@ -222,6 +222,34 @@ void LoadDisables()
}
break;
}
+ case DISABLE_TYPE_MMAP:
+ {
+ MapEntry const* mapEntry = sMapStore.LookupEntry(entry);
+ if (!mapEntry)
+ {
+ sLog->outError(LOG_FILTER_SQL, "Map entry %u from `disables` doesn't exist in dbc, skipped.", entry);
+ continue;
+ }
+ switch (mapEntry->map_type)
+ {
+ case MAP_COMMON:
+ sLog->outInfo(LOG_FILTER_GENERAL, "Pathfinding disabled for world map %u.", entry);
+ break;
+ case MAP_INSTANCE:
+ case MAP_RAID:
+ sLog->outInfo(LOG_FILTER_GENERAL, "Pathfinding disabled for instance map %u.", entry);
+ break;
+ case MAP_BATTLEGROUND:
+ sLog->outInfo(LOG_FILTER_GENERAL, "Pathfinding disabled for battleground map %u.", entry);
+ break;
+ case MAP_ARENA:
+ sLog->outInfo(LOG_FILTER_GENERAL, "Pathfinding disabled for arena map %u.", entry);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
default:
break;
}
@@ -350,6 +378,7 @@ bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags
case DISABLE_TYPE_BATTLEGROUND:
case DISABLE_TYPE_OUTDOORPVP:
case DISABLE_TYPE_ACHIEVEMENT_CRITERIA:
+ case DISABLE_TYPE_MMAP:
return true;
case DISABLE_TYPE_VMAP:
return flags & itr->second.flags;
diff --git a/src/server/game/Conditions/DisableMgr.h b/src/server/game/Conditions/DisableMgr.h
index 89761931048..38751b8a89f 100644
--- a/src/server/game/Conditions/DisableMgr.h
+++ b/src/server/game/Conditions/DisableMgr.h
@@ -31,7 +31,8 @@ enum DisableType
DISABLE_TYPE_BATTLEGROUND = 3,
DISABLE_TYPE_ACHIEVEMENT_CRITERIA = 4,
DISABLE_TYPE_OUTDOORPVP = 5,
- DISABLE_TYPE_VMAP = 6
+ DISABLE_TYPE_VMAP = 6,
+ DISABLE_TYPE_MMAP = 7
};
enum SpellDisableTypes
@@ -56,6 +57,11 @@ enum VmapDisableTypes
VMAP_DISABLE_LIQUIDSTATUS = 0x8
};
+enum MMapDisableTypes
+{
+ MMAP_DISABLE_PATHFINDING = 0x0
+};
+
namespace DisableMgr
{
void LoadDisables();
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index c168f0e1acf..de05fd200b3 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -288,9 +288,10 @@ inline void LoadDBC(uint32& availableDbcLocales, StoreProblemList& errors, DBCSt
// sort problematic dbc to (1) non compatible and (2) non-existed
if (FILE* f = fopen(dbcFilename.c_str(), "rb"))
{
- char buf[100];
- snprintf(buf, 100, " exists, and has %u field(s) (expected " SIZEFMTD "). Extracted file might be from wrong client version or a database-update has been forgotten.", storage.GetFieldCount(), strlen(storage.GetFormat()));
- errors.push_back(dbcFilename + buf);
+ std::ostringstream stream;
+ stream << dbcFilename << " exists, and has " << storage.GetFieldCount() << " field(s) (expected " << strlen(storage.GetFormat()) << "). Extracted file might be from wrong client version or a database-update has been forgotten.";
+ std::string buf = stream.str();
+ errors.push_back(buf);
fclose(f);
}
else
diff --git a/src/server/game/DungeonFinding/LFG.cpp b/src/server/game/DungeonFinding/LFG.cpp
new file mode 100644
index 00000000000..ce16ad5533e
--- /dev/null
+++ b/src/server/game/DungeonFinding/LFG.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2008-2013 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 "LFG.h"
+#include "Language.h"
+#include "ObjectMgr.h"
+
+namespace lfg
+{
+
+std::string ConcatenateDungeons(LfgDungeonSet const& dungeons)
+{
+ std::string dungeonstr = "";
+ if (!dungeons.empty())
+ {
+ std::ostringstream o;
+ LfgDungeonSet::const_iterator it = dungeons.begin();
+ o << (*it);
+ for (++it; it != dungeons.end(); ++it)
+ o << ", " << uint32(*it);
+ dungeonstr = o.str();
+ }
+ return dungeonstr;
+}
+
+std::string GetRolesString(uint8 roles)
+{
+ std::string rolesstr = "";
+
+ if (roles & PLAYER_ROLE_TANK)
+ rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_TANK));
+
+ if (roles & PLAYER_ROLE_HEALER)
+ {
+ if (!rolesstr.empty())
+ rolesstr.append(", ");
+ rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_HEALER));
+ }
+
+ if (roles & PLAYER_ROLE_DAMAGE)
+ {
+ if (!rolesstr.empty())
+ rolesstr.append(", ");
+ rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_DAMAGE));
+ }
+
+ if (roles & PLAYER_ROLE_LEADER)
+ {
+ if (!rolesstr.empty())
+ rolesstr.append(", ");
+ rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_LEADER));
+ }
+
+ if (rolesstr.empty())
+ rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_NONE));
+
+ return rolesstr;
+}
+
+std::string GetStateString(LfgState state)
+{
+ int32 entry = LANG_LFG_ERROR;
+ switch (state)
+ {
+ case LFG_STATE_NONE:
+ entry = LANG_LFG_STATE_NONE;
+ break;
+ case LFG_STATE_ROLECHECK:
+ entry = LANG_LFG_STATE_ROLECHECK;
+ break;
+ case LFG_STATE_QUEUED:
+ entry = LANG_LFG_STATE_QUEUED;
+ break;
+ case LFG_STATE_PROPOSAL:
+ entry = LANG_LFG_STATE_PROPOSAL;
+ break;
+ case LFG_STATE_DUNGEON:
+ entry = LANG_LFG_STATE_DUNGEON;
+ break;
+ case LFG_STATE_BOOT:
+ entry = LANG_LFG_STATE_BOOT;
+ break;
+ case LFG_STATE_FINISHED_DUNGEON:
+ entry = LANG_LFG_STATE_FINISHED_DUNGEON;
+ break;
+ case LFG_STATE_RAIDBROWSER:
+ entry = LANG_LFG_STATE_RAIDBROWSER;
+ break;
+ }
+
+ return std::string(sObjectMgr->GetTrinityStringForDBCLocale(entry));
+}
+
+} // namespace lfg
diff --git a/src/server/game/DungeonFinding/LFG.h b/src/server/game/DungeonFinding/LFG.h
index ebbcfb1d71a..541e4d6bd43 100644
--- a/src/server/game/DungeonFinding/LFG.h
+++ b/src/server/game/DungeonFinding/LFG.h
@@ -20,6 +20,9 @@
#include "Common.h"
+namespace lfg
+{
+
enum LFGEnum
{
LFG_TANKS_NEEDED = 1,
@@ -99,4 +102,10 @@ typedef std::list<uint64> LfgGuidList;
typedef std::map<uint64, uint8> LfgRolesMap;
typedef std::map<uint64, uint64> LfgGroupsMap;
+std::string ConcatenateDungeons(LfgDungeonSet const& dungeons);
+std::string GetRolesString(uint8 roles);
+std::string GetStateString(LfgState state);
+
+} // namespace lfg
+
#endif
diff --git a/src/server/game/DungeonFinding/LFGGroupData.cpp b/src/server/game/DungeonFinding/LFGGroupData.cpp
index 427225bf323..f711514e26d 100644
--- a/src/server/game/DungeonFinding/LFGGroupData.cpp
+++ b/src/server/game/DungeonFinding/LFGGroupData.cpp
@@ -18,6 +18,9 @@
#include "LFG.h"
#include "LFGGroupData.h"
+namespace lfg
+{
+
LfgGroupData::LfgGroupData(): m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE),
m_Leader(0), m_Dungeon(0), m_KicksLeft(LFG_GROUP_MAX_KICKS)
{ }
@@ -122,3 +125,5 @@ uint8 LfgGroupData::GetKicksLeft() const
{
return m_KicksLeft;
}
+
+} // namespace lfg
diff --git a/src/server/game/DungeonFinding/LFGGroupData.h b/src/server/game/DungeonFinding/LFGGroupData.h
index 2ad020d3bc1..47e562c37aa 100644
--- a/src/server/game/DungeonFinding/LFGGroupData.h
+++ b/src/server/game/DungeonFinding/LFGGroupData.h
@@ -20,6 +20,9 @@
#include "LFG.h"
+namespace lfg
+{
+
enum LfgGroupEnum
{
LFG_GROUP_MAX_KICKS = 3,
@@ -75,4 +78,6 @@ class LfgGroupData
uint8 m_KicksLeft; ///< Number of kicks left
};
+} // namespace lfg
+
#endif
diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp
index a931d61f740..9bb65b63557 100644
--- a/src/server/game/DungeonFinding/LFGMgr.cpp
+++ b/src/server/game/DungeonFinding/LFGMgr.cpp
@@ -33,6 +33,9 @@
#include "GameEventMgr.h"
#include "WorldSession.h"
+namespace lfg
+{
+
LFGMgr::LFGMgr(): m_QueueTimer(0), m_lfgProposalId(1),
m_options(sWorld->getIntConfig(CONFIG_LFG_OPTIONSMASK))
{
@@ -95,89 +98,6 @@ void LFGMgr::_SaveToDB(uint64 guid, uint32 db_guid)
CharacterDatabase.Execute(stmt);
}
-std::string LFGMgr::ConcatenateDungeons(LfgDungeonSet const& dungeons)
-{
- std::string dungeonstr = "";
- if (!dungeons.empty())
- {
- std::ostringstream o;
- LfgDungeonSet::const_iterator it = dungeons.begin();
- o << (*it);
- for (++it; it != dungeons.end(); ++it)
- o << ", " << uint32(*it);
- dungeonstr = o.str();
- }
- return dungeonstr;
-}
-
-std::string LFGMgr::GetRolesString(uint8 roles)
-{
- std::string rolesstr = "";
-
- if (roles & PLAYER_ROLE_TANK)
- rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_TANK));
-
- if (roles & PLAYER_ROLE_HEALER)
- {
- if (!rolesstr.empty())
- rolesstr.append(", ");
- rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_HEALER));
- }
-
- if (roles & PLAYER_ROLE_DAMAGE)
- {
- if (!rolesstr.empty())
- rolesstr.append(", ");
- rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_DAMAGE));
- }
-
- if (roles & PLAYER_ROLE_LEADER)
- {
- if (!rolesstr.empty())
- rolesstr.append(", ");
- rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_LEADER));
- }
-
- if (rolesstr.empty())
- rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_NONE));
-
- return rolesstr;
-}
-
-std::string LFGMgr::GetStateString(LfgState state)
-{
- int32 entry = LANG_LFG_ERROR;
- switch (state)
- {
- case LFG_STATE_NONE:
- entry = LANG_LFG_STATE_NONE;
- break;
- case LFG_STATE_ROLECHECK:
- entry = LANG_LFG_STATE_ROLECHECK;
- break;
- case LFG_STATE_QUEUED:
- entry = LANG_LFG_STATE_QUEUED;
- break;
- case LFG_STATE_PROPOSAL:
- entry = LANG_LFG_STATE_PROPOSAL;
- break;
- case LFG_STATE_DUNGEON:
- entry = LANG_LFG_STATE_DUNGEON;
- break;
- case LFG_STATE_BOOT:
- entry = LANG_LFG_STATE_BOOT;
- break;
- case LFG_STATE_FINISHED_DUNGEON:
- entry = LANG_LFG_STATE_FINISHED_DUNGEON;
- break;
- case LFG_STATE_RAIDBROWSER:
- entry = LANG_LFG_STATE_RAIDBROWSER;
- break;
- }
-
- return std::string(sObjectMgr->GetTrinityStringForDBCLocale(entry));
-}
-
/// Load rewards for completing dungeons
void LFGMgr::LoadRewards()
{
@@ -207,7 +127,7 @@ void LFGMgr::LoadRewards()
uint32 firstQuestId = fields[2].GetUInt32();
uint32 otherQuestId = fields[3].GetUInt32();
- if (!GetLFGDungeon(dungeonId))
+ if (!GetLFGDungeonEntry(dungeonId))
{
sLog->outError(LOG_FILTER_SQL, "Dungeon %u specified in table `lfg_dungeon_rewards` does not exist!", dungeonId);
continue;
@@ -248,11 +168,6 @@ LFGDungeonData const* LFGMgr::GetLFGDungeon(uint32 id)
return NULL;
}
-LFGDungeonContainer & LFGMgr::GetLFGDungeonMap()
-{
- return LfgDungeonStore;
-}
-
void LFGMgr::LoadLFGDungeons(bool reload /* = false */)
{
uint32 oldMSTime = getMSTime();
@@ -282,7 +197,7 @@ void LFGMgr::LoadLFGDungeons(bool reload /* = false */)
if (!result)
{
- sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 lfg entrance positions. DB table `lfg_entrances` is empty!");
+ sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 lfg entrance positions. DB table `lfg_entrances` is empty!");
return;
}
@@ -464,6 +379,7 @@ void LFGMgr::InitializeLockedDungeons(Player* player, uint8 level /* = 0 */)
uint8 expansion = player->GetSession()->Expansion();
LfgDungeonSet const& dungeons = GetDungeonsByRandom(0);
LfgLockMap lock;
+ bool denyJoin = !player->GetSession()->HasPermission(RBAC_PERM_JOIN_DUNGEON_FINDER);
for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end(); ++it)
{
@@ -472,7 +388,9 @@ void LFGMgr::InitializeLockedDungeons(Player* player, uint8 level /* = 0 */)
continue;
uint32 lockData = 0;
- if (dungeon->expansion > expansion)
+ if (denyJoin)
+ lockData = LFG_LOCKSTATUS_RAID_LOCKED;
+ else if (dungeon->expansion > expansion)
lockData = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION;
else if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player))
lockData = LFG_LOCKSTATUS_RAID_LOCKED;
@@ -554,7 +472,9 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const
}
// Check player or group member restrictions
- if (player->InBattleground() || player->InArena() || player->InBattlegroundQueue())
+ if (!player->GetSession()->HasPermission(RBAC_PERM_JOIN_DUNGEON_FINDER))
+ joinData.result = LFG_JOIN_NOT_MEET_REQS;
+ else if (player->InBattleground() || player->InArena() || player->InBattlegroundQueue())
joinData.result = LFG_JOIN_USING_BG_SYSTEM;
else if (player->HasAura(LFG_SPELL_DUNGEON_DESERTER))
joinData.result = LFG_JOIN_DESERTER;
@@ -573,6 +493,8 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const
{
if (Player* plrg = itr->getSource())
{
+ if (!plrg->GetSession()->HasPermission(RBAC_PERM_JOIN_DUNGEON_FINDER))
+ joinData.result = LFG_JOIN_PARTY_NOT_MEET_REQS;
if (plrg->HasAura(LFG_SPELL_DUNGEON_DESERTER))
joinData.result = LFG_JOIN_PARTY_DESERTER;
else if (plrg->HasAura(LFG_SPELL_DUNGEON_COOLDOWN))
@@ -1163,7 +1085,6 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept)
break;
}
- teleportStore.push_back(pguid);
SetState(pguid, LFG_STATE_DUNGEON);
}
@@ -1398,10 +1319,7 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
sLog->outDebug(LOG_FILTER_LFG, "TeleportPlayer: Player %s is being teleported out. Current Map %u - Expected Map %u",
player->GetName().c_str(), player->GetMapId(), uint32(dungeon->map));
if (player->GetMapId() == uint32(dungeon->map))
- {
- player->RemoveAurasDueToSpell(LFG_SPELL_LUCK_OF_THE_DRAW);
player->TeleportToBGEntryPoint();
- }
return;
}
@@ -1675,16 +1593,6 @@ const std::string& LFGMgr::GetComment(uint64 guid)
return PlayersStore[guid].GetComment();
}
-bool LFGMgr::IsTeleported(uint64 pguid)
-{
- if (std::find(teleportStore.begin(), teleportStore.end(), pguid) != teleportStore.end())
- {
- teleportStore.remove(pguid);
- return true;
- }
- return false;
-}
-
LfgDungeonSet const& LFGMgr::GetSelectedDungeons(uint64 guid)
{
sLog->outTrace(LOG_FILTER_LFG, "LFGMgr::GetSelectedDungeons: [" UI64FMTD "]", guid);
@@ -2039,3 +1947,56 @@ void LFGMgr::SetupGroupMember(uint64 guid, uint64 gguid)
SetGroup(guid, gguid);
AddPlayerToGroup(gguid, guid);
}
+
+bool LFGMgr::selectedRandomLfgDungeon(uint64 guid)
+{
+ if (GetState(guid) != LFG_STATE_NONE)
+ {
+ LfgDungeonSet const& dungeons = GetSelectedDungeons(guid);
+ if (!dungeons.empty())
+ {
+ LFGDungeonData const* dungeon = GetLFGDungeon(*dungeons.begin());
+ if (dungeon && (dungeon->type == LFG_TYPE_RANDOM || dungeon->seasonal))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool LFGMgr::inLfgDungeonMap(uint64 guid, uint32 map, Difficulty difficulty)
+{
+ if (!IS_GROUP_GUID(guid))
+ guid = GetGroup(guid);
+
+ if (uint32 dungeonId = GetDungeon(guid, true))
+ if (LFGDungeonData const* dungeon = GetLFGDungeon(dungeonId))
+ if (uint32(dungeon->map) == map && dungeon->difficulty == difficulty)
+ return true;
+
+ return false;
+}
+
+uint32 LFGMgr::GetLFGDungeonEntry(uint32 id)
+{
+ if (id)
+ if (LFGDungeonData const* dungeon = GetLFGDungeon(id))
+ return dungeon->Entry();
+
+ return 0;
+}
+
+LfgDungeonSet LFGMgr::GetRandomAndSeasonalDungeons(uint8 level, uint8 expansion)
+{
+ LfgDungeonSet randomDungeons;
+ for (lfg::LFGDungeonContainer::const_iterator itr = LfgDungeonStore.begin(); itr != LfgDungeonStore.end(); ++itr)
+ {
+ lfg::LFGDungeonData const& dungeon = itr->second;
+ if ((dungeon.type == lfg::LFG_TYPE_RANDOM || (dungeon.seasonal && sLFGMgr->IsSeasonActive(dungeon.id)))
+ && dungeon.expansion <= expansion && dungeon.minlevel <= level && level <= dungeon.maxlevel)
+ randomDungeons.insert(dungeon.Entry());
+ }
+ return randomDungeons;
+}
+
+} // namespace lfg
diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h
index 6f6e770a5bd..0795e6e22d5 100644
--- a/src/server/game/DungeonFinding/LFGMgr.h
+++ b/src/server/game/DungeonFinding/LFGMgr.h
@@ -30,6 +30,9 @@ class Group;
class Player;
class Quest;
+namespace lfg
+{
+
enum LfgOptions
{
LFG_OPTION_ENABLE_DUNGEON_FINDER = 0x01,
@@ -296,91 +299,123 @@ class LFGMgr
~LFGMgr();
public:
+ // Functions used outside lfg namespace
void Update(uint32 diff);
- // Reward
- void LoadRewards();
+ // World.cpp
+ /// Finish the dungeon for the given group. All check are performed using internal lfg data
void FinishDungeon(uint64 gguid, uint32 dungeonId);
- LfgReward const* GetRandomDungeonReward(uint32 dungeon, uint8 level);
-
- // Queue
- void JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, std::string const& comment);
- void LeaveLfg(uint64 guid);
-
- // Role Check
- void UpdateRoleCheck(uint64 gguid, uint64 guid = 0, uint8 roles = PLAYER_ROLE_NONE);
-
- // Group Matching
- static bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true);
- void GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap);
-
- // Proposals
- uint32 AddProposal(LfgProposal& proposal);
- void UpdateProposal(uint32 proposalId, uint64 guid, bool accept);
+ /// Loads rewards for random dungeons
+ void LoadRewards();
+ /// Loads dungeons from dbc and adds teleport coords
+ void LoadLFGDungeons(bool reload = false);
- // Teleportation
- void TeleportPlayer(Player* player, bool out, bool fromOpcode = false);
+ // Multiple files
+ /// Check if given guid applied for random dungeon
+ bool selectedRandomLfgDungeon(uint64 guid);
+ /// Check if given guid applied for given map and difficulty. Used to know
+ bool inLfgDungeonMap(uint64 guid, uint32 map, Difficulty difficulty);
+ /// Get selected dungeons
+ LfgDungeonSet const& GetSelectedDungeons(uint64 guid);
+ /// Get current lfg state
+ LfgState GetState(uint64 guid);
+ /// Get current dungeon
+ uint32 GetDungeon(uint64 guid, bool asId = true);
+ /// Get the map id of the current dungeon
+ uint32 GetDungeonMapId(uint64 guid);
+ /// Get kicks left in current group
+ uint8 GetKicksLeft(uint64 gguid);
+ /// Load Lfg group info from DB
+ void _LoadFromDB(Field* fields, uint64 guid);
+ /// Initializes player data after loading group data from DB
+ void SetupGroupMember(uint64 guid, uint64 gguid);
+ /// Return Lfg dungeon entry for given dungeon id
+ uint32 GetLFGDungeonEntry(uint32 id);
- // Vote kick
- void InitBoot(uint64 gguid, uint64 kguid, uint64 vguid, std::string const& reason);
- void UpdateBoot(uint64 guid, bool accept);
+ // cs_lfg
+ /// Get current player roles
+ uint8 GetRoles(uint64 guid);
+ /// Get current player comment (used for LFR)
+ std::string const& GetComment(uint64 gguid);
+ /// Gets current lfg options
+ uint32 GetOptions();
+ /// Sets new lfg options
+ void SetOptions(uint32 options);
+ /// Checks if given lfg option is enabled
+ bool isOptionEnabled(uint32 option);
+ /// Clears queue - Only for internal testing
+ void Clean();
+ /// Dumps the state of the queue - Only for internal testing
+ std::string DumpQueueInfo(bool full = false);
+ // LFGScripts
+ /// Get leader of the group (using internal data)
+ uint64 GetLeader(uint64 guid);
+ /// Initializes locked dungeons for given player (called at login or level change)
void InitializeLockedDungeons(Player* player, uint8 level = 0);
-
- void SetRoles(uint64 guid, uint8 roles);
- void SetComment(uint64 guid, std::string const& comment);
+ /// Sets player team
void SetTeam(uint64 guid, uint8 team);
+ /// Sets player group
void SetGroup(uint64 guid, uint64 group);
+ /// Gets player group
+ uint64 GetGroup(uint64 guid);
+ /// Sets the leader of the group
void SetLeader(uint64 gguid, uint64 leader);
- void SetState(uint64 guid, LfgState state);
-
- void _LoadFromDB(Field* fields, uint64 guid);
- void _SaveToDB(uint64 guid, uint32 db_guid);
-
- void RemovePlayerData(uint64 guid);
+ /// Removes saved group data
void RemoveGroupData(uint64 guid);
+ /// Removes a player from a group
uint8 RemovePlayerFromGroup(uint64 gguid, uint64 guid);
+ /// Adds player to group
void AddPlayerToGroup(uint64 gguid, uint64 guid);
+ // LFGHandler
+ /// Get locked dungeons
LfgLockMap const& GetLockedDungeons(uint64 guid);
- LfgDungeonSet const& GetSelectedDungeons(uint64 guid);
- uint32 GetDungeon(uint64 guid, bool asId = true);
- uint32 GetDungeonMapId(uint64 guid);
- LfgState GetState(uint64 guid);
+ /// Returns current lfg status
+ LfgUpdateData GetLfgStatus(uint64 guid);
+ /// Checks if Seasonal dungeon is active
+ bool IsSeasonActive(uint32 dungeonId);
+ /// Gets the random dungeon reward corresponding to given dungeon and player level
+ LfgReward const* GetRandomDungeonReward(uint32 dungeon, uint8 level);
+ /// Returns all random and seasonal dungeons for given level and expansion
+ LfgDungeonSet GetRandomAndSeasonalDungeons(uint8 level, uint8 expansion);
+ /// Teleport a player to/from selected dungeon
+ void TeleportPlayer(Player* player, bool out, bool fromOpcode = false);
+ /// Inits new proposal to boot a player
+ void InitBoot(uint64 gguid, uint64 kguid, uint64 vguid, std::string const& reason);
+ /// Updates player boot proposal with new player answer
+ void UpdateBoot(uint64 guid, bool accept);
+ /// Updates proposal to join dungeon with player answer
+ void UpdateProposal(uint32 proposalId, uint64 guid, bool accept);
+ /// Updates the role check with player answer
+ void UpdateRoleCheck(uint64 gguid, uint64 guid = 0, uint8 roles = PLAYER_ROLE_NONE);
+ /// Sets player lfg roles
+ void SetRoles(uint64 guid, uint8 roles);
+ /// Sets player lfr comment
+ void SetComment(uint64 guid, std::string const& comment);
+ /// Join Lfg with selected roles, dungeons and comment
+ void JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, std::string const& comment);
+ /// Leaves lfg
+ void LeaveLfg(uint64 guid);
+
+ // LfgQueue
+ /// Get last lfg state (NONE, DUNGEON or FINISHED_DUNGEON)
LfgState GetOldState(uint64 guid);
- uint8 GetKicksLeft(uint64 gguid);
- uint64 GetLeader(uint64 guid);
+ /// Check if given group guid is lfg
bool IsLfgGroup(uint64 guid);
- uint8 GetRoles(uint64 guid);
- std::string const& GetComment(uint64 gguid);
- LfgGuidSet const& GetPlayers(uint64 guid);
+ /// Gets the player count of given group
uint8 GetPlayerCount(uint64 guid);
-
- bool IsTeleported(uint64 guid);
-
+ /// Add a new Proposal
+ uint32 AddProposal(LfgProposal& proposal);
+ /// Checks if all players are queued
bool AllQueued(LfgGuidList const& check);
- void Clean();
-
+ /// Checks if given roles match, modifies given roles map with new roles
+ static bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true);
+ /// Checks if given players are ignoring each other
static bool HasIgnore(uint64 guid1, uint64 guid2);
+ /// Sends queue status to player
static void SendLfgQueueStatus(uint64 guid, LfgQueueStatusData const& data);
- bool isOptionEnabled(uint32 option);
- uint32 GetOptions();
- void SetOptions(uint32 options);
- LfgUpdateData GetLfgStatus(uint64 guid);
- bool IsSeasonActive(uint32 dungeonId);
-
- std::string DumpQueueInfo(bool full = false);
- static std::string ConcatenateDungeons(LfgDungeonSet const& dungeons);
- static std::string GetRolesString(uint8 roles);
- static std::string GetStateString(LfgState state);
-
- void LoadLFGDungeons(bool reload = false);
- LFGDungeonData const* GetLFGDungeon(uint32 id);
- LFGDungeonContainer& GetLFGDungeonMap();
- void SetupGroupMember(uint64 guid, uint64 gguid);
- uint64 GetGroup(uint64 guid);
-
private:
uint8 GetTeam(uint64 guid);
void RestoreState(uint64 guid, char const* debugMsg);
@@ -389,6 +424,11 @@ class LFGMgr
void SetSelectedDungeons(uint64 guid, LfgDungeonSet const& dungeons);
void SetLockedDungeons(uint64 guid, LfgLockMap const& lock);
void DecreaseKicksLeft(uint64 guid);
+ void SetState(uint64 guid, LfgState state);
+ void RemovePlayerData(uint64 guid);
+ void GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap);
+ void _SaveToDB(uint64 guid, uint32 db_guid);
+ LFGDungeonData const* GetLFGDungeon(uint32 id);
// Proposals
void RemoveProposal(LfgProposalContainer::iterator itProposal, LfgUpdateType type);
@@ -407,6 +447,8 @@ class LFGMgr
void SendLfgUpdatePlayer(uint64 guid, LfgUpdateData const& data);
void SendLfgUpdateProposal(uint64 guid, LfgProposal const& proposal);
+ LfgGuidSet const& GetPlayers(uint64 guid);
+
// General variables
uint32 m_QueueTimer; ///< used to check interval of update
uint32 m_lfgProposalId; ///< used as internal counter for proposals
@@ -423,8 +465,9 @@ class LFGMgr
LfgPlayerBootContainer BootsStore; ///< Current player kicks
LfgPlayerDataContainer PlayersStore; ///< Player data
LfgGroupDataContainer GroupsStore; ///< Group data
- LfgGuidList teleportStore; ///< Players being teleported
};
-#define sLFGMgr ACE_Singleton<LFGMgr, ACE_Null_Mutex>::instance()
+} // namespace lfg
+
+#define sLFGMgr ACE_Singleton<lfg::LFGMgr, ACE_Null_Mutex>::instance()
#endif
diff --git a/src/server/game/DungeonFinding/LFGPlayerData.cpp b/src/server/game/DungeonFinding/LFGPlayerData.cpp
index 410076f7e75..e8ef430bc1f 100644
--- a/src/server/game/DungeonFinding/LFGPlayerData.cpp
+++ b/src/server/game/DungeonFinding/LFGPlayerData.cpp
@@ -17,6 +17,9 @@
#include "LFGPlayerData.h"
+namespace lfg
+{
+
LfgPlayerData::LfgPlayerData(): m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE),
m_Team(0), m_Group(0), m_Roles(0), m_Comment("")
{}
@@ -122,3 +125,5 @@ LfgDungeonSet const& LfgPlayerData::GetSelectedDungeons() const
{
return m_SelectedDungeons;
}
+
+} // namespace lfg
diff --git a/src/server/game/DungeonFinding/LFGPlayerData.h b/src/server/game/DungeonFinding/LFGPlayerData.h
index 055924fd364..a425ce77bad 100644
--- a/src/server/game/DungeonFinding/LFGPlayerData.h
+++ b/src/server/game/DungeonFinding/LFGPlayerData.h
@@ -20,6 +20,9 @@
#include "LFG.h"
+namespace lfg
+{
+
/**
Stores all lfg data needed about the player.
*/
@@ -68,4 +71,6 @@ class LfgPlayerData
LfgDungeonSet m_SelectedDungeons; ///< Selected Dungeons when joined LFG
};
+} // namespace lfg
+
#endif
diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp
index f1d2dbb313d..6a98fccecdc 100644
--- a/src/server/game/DungeonFinding/LFGQueue.cpp
+++ b/src/server/game/DungeonFinding/LFGQueue.cpp
@@ -27,6 +27,9 @@
#include "World.h"
#include "GroupMgr.h"
+namespace lfg
+{
+
/**
Given a list of guids returns the concatenation using | as delimiter
@@ -431,7 +434,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(LfgGuidList check)
{
std::ostringstream o;
for (LfgRolesMap::const_iterator it = debugRoles.begin(); it != debugRoles.end(); ++it)
- o << ", " << it->first << ": " << sLFGMgr->GetRolesString(it->second);
+ o << ", " << it->first << ": " << GetRolesString(it->second);
sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) Roles not compatible%s", strGuids.c_str(), o.str().c_str());
SetCompatibles(strGuids, LFG_INCOMPATIBLES_NO_ROLES);
@@ -441,12 +444,12 @@ LfgCompatibility LFGQueue::CheckCompatibility(LfgGuidList check)
LfgGuidList::iterator itguid = check.begin();
proposalDungeons = QueueDataStore[*itguid].dungeons;
std::ostringstream o;
- o << ", " << *itguid << ": (" << sLFGMgr->ConcatenateDungeons(proposalDungeons) << ")";
+ o << ", " << *itguid << ": (" << ConcatenateDungeons(proposalDungeons) << ")";
for (++itguid; itguid != check.end(); ++itguid)
{
LfgDungeonSet temporal;
LfgDungeonSet &dungeons = QueueDataStore[*itguid].dungeons;
- o << ", " << *itguid << ": (" << sLFGMgr->ConcatenateDungeons(dungeons) << ")";
+ o << ", " << *itguid << ": (" << ConcatenateDungeons(dungeons) << ")";
std::set_intersection(proposalDungeons.begin(), proposalDungeons.end(), dungeons.begin(), dungeons.end(), std::inserter(temporal, temporal.begin()));
proposalDungeons = temporal;
}
@@ -671,3 +674,5 @@ void LFGQueue::UpdateBestCompatibleInQueue(LfgQueueDataContainer::iterator itrQu
--queueData.dps;
}
}
+
+} // namespace lfg
diff --git a/src/server/game/DungeonFinding/LFGQueue.h b/src/server/game/DungeonFinding/LFGQueue.h
index acb78d2c0f2..db7e7bbf318 100644
--- a/src/server/game/DungeonFinding/LFGQueue.h
+++ b/src/server/game/DungeonFinding/LFGQueue.h
@@ -20,6 +20,9 @@
#include "LFG.h"
+namespace lfg
+{
+
enum LfgCompatibility
{
LFG_COMPATIBILITY_PENDING,
@@ -140,4 +143,6 @@ class LFGQueue
LfgGuidList newToQueueStore; ///< New groups to add to queue
};
+} // namespace lfg
+
#endif
diff --git a/src/server/game/DungeonFinding/LFGScripts.cpp b/src/server/game/DungeonFinding/LFGScripts.cpp
index 568b61eef2f..a4716de9524 100644
--- a/src/server/game/DungeonFinding/LFGScripts.cpp
+++ b/src/server/game/DungeonFinding/LFGScripts.cpp
@@ -29,6 +29,9 @@
#include "ObjectAccessor.h"
#include "WorldSession.h"
+namespace lfg
+{
+
LFGPlayerScript::LFGPlayerScript() : PlayerScript("LFGPlayerScript")
{
}
@@ -85,6 +88,24 @@ void LFGPlayerScript::OnBindToInstance(Player* player, Difficulty difficulty, ui
sLFGMgr->InitializeLockedDungeons(player);
}
+void LFGPlayerScript::OnMapChanged(Player* player)
+{
+ Map const* map = player->GetMap();
+
+ if (sLFGMgr->inLfgDungeonMap(player->GetGUID(), map->GetId(), map->GetDifficulty()))
+ {
+ Group* group = player->GetGroup();
+ for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
+ if (Player* member = itr->getSource())
+ player->GetSession()->SendNameQueryOpcode(member->GetGUID());
+
+ if (sLFGMgr->selectedRandomLfgDungeon(player->GetGUID()))
+ player->CastSpell(player, LFG_SPELL_LUCK_OF_THE_DRAW, true);
+ }
+ else
+ player->RemoveAurasDueToSpell(LFG_SPELL_LUCK_OF_THE_DRAW);
+}
+
LFGGroupScript::LFGGroupScript() : GroupScript("LFGGroupScript")
{
}
@@ -208,3 +229,5 @@ void LFGGroupScript::OnInviteMember(Group* group, uint64 guid)
if (leader && !gguid)
sLFGMgr->LeaveLfg(leader);
}
+
+} // namespace lfg
diff --git a/src/server/game/DungeonFinding/LFGScripts.h b/src/server/game/DungeonFinding/LFGScripts.h
index 227543e1899..bb1900cad93 100644
--- a/src/server/game/DungeonFinding/LFGScripts.h
+++ b/src/server/game/DungeonFinding/LFGScripts.h
@@ -26,6 +26,9 @@
class Player;
class Group;
+namespace lfg
+{
+
class LFGPlayerScript : public PlayerScript
{
public:
@@ -36,6 +39,7 @@ class LFGPlayerScript : public PlayerScript
void OnLogout(Player* player);
void OnLogin(Player* player);
void OnBindToInstance(Player* player, Difficulty difficulty, uint32 mapId, bool permanent);
+ void OnMapChanged(Player* player);
};
class LFGGroupScript : public GroupScript
@@ -50,3 +54,5 @@ class LFGGroupScript : public GroupScript
void OnChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid);
void OnInviteMember(Group* group, uint64 guid);
};
+
+} // namespace lfg
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index a2bed013640..0157cdf9130 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -925,15 +925,7 @@ bool Creature::isCanTrainingOf(Player* player, bool msg) const
}
break;
case TRAINER_TYPE_TRADESKILLS:
- if (GetCreatureTemplate()->trainer_spell && !player->HasSpell(GetCreatureTemplate()->trainer_spell))
- {
- if (msg)
- {
- player->PlayerTalkClass->ClearMenus();
- player->PlayerTalkClass->SendGossipMenu(11031, GetGUID());
- }
- return false;
- }
+ // There's no Blacksmith specialization on Cataclysm, conditions are not required for tradeskills
break;
default:
return false; // checked and error output at creature_template loading
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 9ac5deb56f5..255014a7bbf 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -109,7 +109,6 @@ struct CreatureTemplate
uint32 dynamicflags;
uint32 family; // enum CreatureFamily values (optional)
uint32 trainer_type;
- uint32 trainer_spell;
uint32 trainer_class;
uint32 trainer_race;
float minrangedmg;
diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp
index 700b71303ab..3cd0a1223dd 100644
--- a/src/server/game/Entities/Creature/GossipDef.cpp
+++ b/src/server/game/Entities/Creature/GossipDef.cpp
@@ -142,6 +142,9 @@ void PlayerMenu::SendGossipMenu(uint32 titleTextId, uint64 objectGUID) const
data << uint32(_questMenu.GetMenuItemCount()); // max count 0x20
+ // Store this instead of checking the Singleton every loop iteration
+ bool questLevelInTitle = sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS);
+
for (uint8 i = 0; i < _questMenu.GetMenuItemCount(); ++i)
{
QuestMenuItem const& item = _questMenu.GetItem(i);
@@ -160,6 +163,9 @@ void PlayerMenu::SendGossipMenu(uint32 titleTextId, uint64 objectGUID) const
if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(questID))
ObjectMgr::GetLocaleString(localeData->Title, locale, title);
+ if (questLevelInTitle)
+ AddQuestLevelToTitle(title, quest->GetQuestLevel());
+
data << title; // max 0x200
}
@@ -252,6 +258,10 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote eEmote, const std::string& Title
size_t count_pos = data.wpos();
data << uint8 (_questMenu.GetMenuItemCount());
uint32 count = 0;
+
+ // Store this instead of checking the Singleton every loop iteration
+ bool questLevelInTitle = sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS);
+
for (; count < _questMenu.GetMenuItemCount(); ++count)
{
QuestMenuItem const& qmi = _questMenu.GetItem(count);
@@ -267,6 +277,9 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote eEmote, const std::string& Title
if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(questID))
ObjectMgr::GetLocaleString(localeData->Title, locale, title);
+ if (questLevelInTitle)
+ AddQuestLevelToTitle(title, quest->GetQuestLevel());
+
data << uint32(questID);
data << uint32(qmi.QuestIcon);
data << int32(quest->GetQuestLevel());
@@ -318,6 +331,9 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, uint64 npcGUID,
}
}
+ if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
+ AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
+
WorldPacket data(SMSG_QUESTGIVER_QUEST_DETAILS, 100); // guess size
data << uint64(npcGUID);
data << uint64(0); // either 0 or a npc guid (quest giver)
@@ -467,6 +483,9 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const
data << float(quest->GetPointY());
data << uint32(quest->GetPointOpt());
+ if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
+ AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
+
data << questTitle;
data << questObjectives;
data << questDetails;
@@ -542,6 +561,9 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, uint64 npcGUID, b
}
}
+ if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
+ AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
+
WorldPacket data(SMSG_QUESTGIVER_OFFER_REWARD, 50); // guess size
data << uint64(npcGUID);
data << uint32(quest->GetQuestId());
@@ -604,6 +626,9 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, uint64 npcGUID,
return;
}
+ if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
+ AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
+
WorldPacket data(SMSG_QUESTGIVER_REQUEST_ITEMS, 50); // guess size
data << uint64(npcGUID);
data << uint32(quest->GetQuestId());
@@ -664,3 +689,13 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, uint64 npcGUID,
_session->SendPacket(&data);
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_QUESTGIVER_REQUEST_ITEMS NPCGuid=%u, questid=%u", GUID_LOPART(npcGUID), quest->GetQuestId());
}
+
+void PlayerMenu::AddQuestLevelToTitle(std::string &title, int32 level)
+{
+ // Adds the quest level to the front of the quest title
+ // example: [13] Westfall Stew
+
+ std::stringstream questTitlePretty;
+ questTitlePretty << "[" << level << "] " << title;
+ title = questTitlePretty.str();
+}
diff --git a/src/server/game/Entities/Creature/GossipDef.h b/src/server/game/Entities/Creature/GossipDef.h
index b1b45b3d459..7d6d21cd9ad 100644
--- a/src/server/game/Entities/Creature/GossipDef.h
+++ b/src/server/game/Entities/Creature/GossipDef.h
@@ -277,6 +277,8 @@ class PlayerMenu
void SendQuestGiverOfferReward(Quest const* quest, uint64 npcGUID, bool enableNext) const;
void SendQuestGiverRequestItems(Quest const* quest, uint64 npcGUID, bool canComplete, bool closeOnCancel) const;
+ static void AddQuestLevelToTitle(std::string &title, int32 level);
+
private:
GossipMenu _gossipMenu;
QuestMenu _questMenu;
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 4c6a13136eb..0be9002e1d8 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -76,7 +76,6 @@ Object::Object() : m_PackGUID(sizeof(uint64)+1)
m_objectType = TYPEMASK_OBJECT;
m_uint32Values = NULL;
- _changedFields = NULL;
m_valuesCount = 0;
_fieldNotifyFlags = UF_FLAG_DYNAMIC;
@@ -120,8 +119,6 @@ Object::~Object()
}
delete [] m_uint32Values;
- delete [] _changedFields;
-
}
void Object::_InitValues()
@@ -129,8 +126,7 @@ void Object::_InitValues()
m_uint32Values = new uint32[m_valuesCount];
memset(m_uint32Values, 0, m_valuesCount*sizeof(uint32));
- _changedFields = new bool[m_valuesCount];
- memset(_changedFields, 0, m_valuesCount*sizeof(bool));
+ _changesMask.SetCount(m_valuesCount);
m_objectUpdated = false;
}
@@ -901,7 +897,7 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, UpdateMask*
void Object::ClearUpdateMask(bool remove)
{
- memset(_changedFields, 0, m_valuesCount*sizeof(bool));
+ _changesMask.Clear();
if (m_objectUpdated)
{
@@ -925,64 +921,57 @@ void Object::BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) cons
BuildValuesUpdateBlockForPlayer(&iter->second, iter->first);
}
-void Object::GetUpdateFieldData(Player const* target, uint32*& flags, bool& isOwner, bool& isItemOwner, bool& hasSpecialInfo, bool& isPartyMember) const
+uint32 Object::GetUpdateFieldData(Player const* target, uint32*& flags) const
{
- // This function assumes updatefield index is always valid
+ uint32 visibleFlag = UF_FLAG_PUBLIC;
+
+ if (target == this)
+ visibleFlag |= UF_FLAG_PRIVATE;
+
switch (GetTypeId())
{
case TYPEID_ITEM:
case TYPEID_CONTAINER:
flags = ItemUpdateFieldFlags;
- isOwner = isItemOwner = ((Item*)this)->GetOwnerGUID() == target->GetGUID();
+ if (((Item*)this)->GetOwnerGUID() == target->GetGUID())
+ visibleFlag |= UF_FLAG_OWNER | UF_FLAG_ITEM_OWNER;
break;
case TYPEID_UNIT:
case TYPEID_PLAYER:
{
Player* plr = ToUnit()->GetCharmerOrOwnerPlayerOrPlayerItself();
flags = UnitUpdateFieldFlags;
- isOwner = ToUnit()->GetOwnerGUID() == target->GetGUID();
- hasSpecialInfo = ToUnit()->HasAuraTypeWithCaster(SPELL_AURA_EMPATHY, target->GetGUID());
- isPartyMember = plr && plr->IsInSameGroupWith(target);
+ if (ToUnit()->GetOwnerGUID() == target->GetGUID())
+ visibleFlag |= UF_FLAG_OWNER;
+
+ if (HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO))
+ if (ToUnit()->HasAuraTypeWithCaster(SPELL_AURA_EMPATHY, target->GetGUID()))
+ visibleFlag |= UF_FLAG_SPECIAL_INFO;
+
+ if (plr && plr->IsInSameRaidWith(target))
+ visibleFlag |= UF_FLAG_PARTY_MEMBER;
break;
}
case TYPEID_GAMEOBJECT:
flags = GameObjectUpdateFieldFlags;
- isOwner = ToGameObject()->GetOwnerGUID() == target->GetGUID();
+ if (ToGameObject()->GetOwnerGUID() == target->GetGUID())
+ visibleFlag |= UF_FLAG_OWNER;
break;
case TYPEID_DYNAMICOBJECT:
flags = DynamicObjectUpdateFieldFlags;
- isOwner = ((DynamicObject*)this)->GetCasterGUID() == target->GetGUID();
+ if (((DynamicObject*)this)->GetCasterGUID() == target->GetGUID())
+ visibleFlag |= UF_FLAG_OWNER;
break;
case TYPEID_CORPSE:
flags = CorpseUpdateFieldFlags;
- isOwner = ToCorpse()->GetOwnerGUID() == target->GetGUID();
+ if (ToCorpse()->GetOwnerGUID() == target->GetGUID())
+ visibleFlag |= UF_FLAG_OWNER;
break;
case TYPEID_OBJECT:
break;
}
-}
-
-bool Object::IsUpdateFieldVisible(uint32 flags, bool isSelf, bool isOwner, bool isItemOwner, bool isPartyMember) const
-{
- if (flags == UF_FLAG_NONE)
- return false;
-
- if (flags & UF_FLAG_PUBLIC)
- return true;
-
- if (flags & UF_FLAG_PRIVATE && isSelf)
- return true;
- if (flags & UF_FLAG_OWNER && isOwner)
- return true;
-
- if (flags & UF_FLAG_ITEM_OWNER && isItemOwner)
- return true;
-
- if (flags & UF_FLAG_PARTY_MEMBER && isPartyMember)
- return true;
-
- return false;
+ return visibleFlag;
}
void Object::_LoadIntoDataField(std::string const& data, uint32 startOffset, uint32 count)
@@ -998,28 +987,20 @@ void Object::_LoadIntoDataField(std::string const& data, uint32 startOffset, uin
for (uint32 index = 0; index < count; ++index)
{
m_uint32Values[startOffset + index] = atol(tokens[index]);
- _changedFields[startOffset + index] = true;
+ _changesMask.SetBit(startOffset + index);
}
}
void Object::_SetUpdateBits(UpdateMask* updateMask, Player* target) const
{
- bool* indexes = _changedFields;
uint32* flags = NULL;
- bool isSelf = target == this;
- bool isOwner = false;
- bool isItemOwner = false;
- bool hasSpecialInfo = false;
- bool isPartyMember = false;
-
- GetUpdateFieldData(target, flags, isOwner, isItemOwner, hasSpecialInfo, isPartyMember);
-
+ uint32 visibleFlag = GetUpdateFieldData(target, flags);
uint32 valCount = m_valuesCount;
if (GetTypeId() == TYPEID_PLAYER && target != this)
valCount = PLAYER_END_NOT_SELF;
- for (uint16 index = 0; index < valCount; ++index, ++indexes)
- if (_fieldNotifyFlags & flags[index] || (flags[index] & UF_FLAG_SPECIAL_INFO && hasSpecialInfo) || (*indexes && IsUpdateFieldVisible(flags[index], isSelf, isOwner, isItemOwner, isPartyMember)))
+ for (uint16 index = 0; index < valCount; ++index)
+ if (_fieldNotifyFlags & flags[index] || ((flags[index] & visibleFlag) & UF_FLAG_SPECIAL_INFO) || (_changesMask.GetBit(index) && (flags[index] & visibleFlag)))
updateMask->SetBit(index);
}
@@ -1027,20 +1008,13 @@ void Object::_SetCreateBits(UpdateMask* updateMask, Player* target) const
{
uint32* value = m_uint32Values;
uint32* flags = NULL;
- bool isSelf = target == this;
- bool isOwner = false;
- bool isItemOwner = false;
- bool hasSpecialInfo = false;
- bool isPartyMember = false;
-
- GetUpdateFieldData(target, flags, isOwner, isItemOwner, hasSpecialInfo, isPartyMember);
-
+ uint32 visibleFlag = GetUpdateFieldData(target, flags);
uint32 valCount = m_valuesCount;
if (GetTypeId() == TYPEID_PLAYER && target != this)
valCount = PLAYER_END_NOT_SELF;
for (uint16 index = 0; index < valCount; ++index, ++value)
- if (_fieldNotifyFlags & flags[index] || (flags[index] & UF_FLAG_SPECIAL_INFO && hasSpecialInfo) || (*value && IsUpdateFieldVisible(flags[index], isSelf, isOwner, isItemOwner, isPartyMember)))
+ if (_fieldNotifyFlags & flags[index] || ((flags[index] & visibleFlag) & UF_FLAG_SPECIAL_INFO) || (*value && (flags[index] & visibleFlag)))
updateMask->SetBit(index);
}
@@ -1051,7 +1025,7 @@ void Object::SetInt32Value(uint16 index, int32 value)
if (m_int32Values[index] != value)
{
m_int32Values[index] = value;
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1068,7 +1042,7 @@ void Object::SetUInt32Value(uint16 index, uint32 value)
if (m_uint32Values[index] != value)
{
m_uint32Values[index] = value;
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1083,7 +1057,7 @@ void Object::UpdateUInt32Value(uint16 index, uint32 value)
ASSERT(index < m_valuesCount || PrintIndexError(index, true));
m_uint32Values[index] = value;
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
}
void Object::SetUInt64Value(uint16 index, uint64 value)
@@ -1093,8 +1067,8 @@ void Object::SetUInt64Value(uint16 index, uint64 value)
{
m_uint32Values[index] = PAIR64_LOPART(value);
m_uint32Values[index + 1] = PAIR64_HIPART(value);
- _changedFields[index] = true;
- _changedFields[index + 1] = true;
+ _changesMask.SetBit(index);
+ _changesMask.SetBit(index + 1);
if (m_inWorld && !m_objectUpdated)
{
@@ -1111,8 +1085,8 @@ bool Object::AddUInt64Value(uint16 index, uint64 value)
{
m_uint32Values[index] = PAIR64_LOPART(value);
m_uint32Values[index + 1] = PAIR64_HIPART(value);
- _changedFields[index] = true;
- _changedFields[index + 1] = true;
+ _changesMask.SetBit(index);
+ _changesMask.SetBit(index + 1);
if (m_inWorld && !m_objectUpdated)
{
@@ -1133,8 +1107,8 @@ bool Object::RemoveUInt64Value(uint16 index, uint64 value)
{
m_uint32Values[index] = 0;
m_uint32Values[index + 1] = 0;
- _changedFields[index] = true;
- _changedFields[index + 1] = true;
+ _changesMask.SetBit(index);
+ _changesMask.SetBit(index + 1);
if (m_inWorld && !m_objectUpdated)
{
@@ -1155,7 +1129,7 @@ void Object::SetFloatValue(uint16 index, float value)
if (m_floatValues[index] != value)
{
m_floatValues[index] = value;
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1179,7 +1153,7 @@ void Object::SetByteValue(uint16 index, uint8 offset, uint8 value)
{
m_uint32Values[index] &= ~uint32(uint32(0xFF) << (offset * 8));
m_uint32Values[index] |= uint32(uint32(value) << (offset * 8));
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1203,7 +1177,7 @@ void Object::SetUInt16Value(uint16 index, uint8 offset, uint16 value)
{
m_uint32Values[index] &= ~uint32(uint32(0xFFFF) << (offset * 16));
m_uint32Values[index] |= uint32(uint32(value) << (offset * 16));
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1270,7 +1244,7 @@ void Object::SetFlag(uint16 index, uint32 newFlag)
if (oldval != newval)
{
m_uint32Values[index] = newval;
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1291,7 +1265,7 @@ void Object::RemoveFlag(uint16 index, uint32 oldFlag)
if (oldval != newval)
{
m_uint32Values[index] = newval;
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1314,7 +1288,7 @@ void Object::SetByteFlag(uint16 index, uint8 offset, uint8 newFlag)
if (!(uint8(m_uint32Values[index] >> (offset * 8)) & newFlag))
{
m_uint32Values[index] |= uint32(uint32(newFlag) << (offset * 8));
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1337,7 +1311,7 @@ void Object::RemoveByteFlag(uint16 index, uint8 offset, uint8 oldFlag)
if (uint8(m_uint32Values[index] >> (offset * 8)) & oldFlag)
{
m_uint32Values[index] &= ~uint32(uint32(oldFlag) << (offset * 8));
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -2113,7 +2087,7 @@ void WorldObject::SendPlaySound(uint32 Sound, bool OnlySelf)
void Object::ForceValuesUpdateAtIndex(uint32 i)
{
- _changedFields[i] = true;
+ _changesMask.SetBit(i);
if (m_inWorld && !m_objectUpdated)
{
sObjectAccessor->AddUpdateObject(this);
@@ -2838,7 +2812,7 @@ void WorldObject::MovePosition(Position &pos, float dist, float angle)
desty = pos.m_positionY + dist * std::sin(angle);
// Prevent invalid coordinates here, position is unchanged
- if (!Trinity::IsValidMapCoord(destx, desty))
+ if (!Trinity::IsValidMapCoord(destx, desty, pos.m_positionZ))
{
sLog->outFatal(LOG_FILTER_GENERAL, "WorldObject::MovePosition invalid coordinates X: %f and Y: %f were passed!", destx, desty);
return;
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index ebe29e0f5a3..8b61b6ec2c8 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -20,7 +20,7 @@
#define _OBJECT_H
#include "Common.h"
-#include "UpdateFields.h"
+#include "UpdateMask.h"
#include "UpdateData.h"
#include "GridReference.h"
#include "ObjectDefines.h"
@@ -107,7 +107,6 @@ class ByteBuffer;
class WorldSession;
class Creature;
class Player;
-class UpdateMask;
class InstanceScript;
class GameObject;
class TempSummon;
@@ -387,9 +386,7 @@ class Object
std::string _ConcatFields(uint16 startIndex, uint16 size) const;
void _LoadIntoDataField(std::string const& data, uint32 startOffset, uint32 count);
- void GetUpdateFieldData(Player const* target, uint32*& flags, bool& isOwner, bool& isItemOwner, bool& hasSpecialInfo, bool& isPartyMember) const;
-
- bool IsUpdateFieldVisible(uint32 flags, bool isSelf, bool isOwner, bool isItemOwner, bool isPartyMember) const;
+ uint32 GetUpdateFieldData(Player const* target, uint32*& flags) const;
void _SetUpdateBits(UpdateMask* updateMask, Player* target) const;
void _SetCreateBits(UpdateMask* updateMask, Player* target) const;
@@ -408,7 +405,7 @@ class Object
float *m_floatValues;
};
- bool* _changedFields;
+ UpdateMask _changesMask;
uint16 m_valuesCount;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 1fe980f60b5..a520ae67442 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -859,7 +859,6 @@ Player::Player(WorldSession* session): Unit(true), phaseMgr(this)
_activeCheats = CHEAT_NONE;
_maxPersonalArenaRate = 0;
- _ConquestCurrencyTotalWeekCap = 0;
memset(_voidStorageItems, 0, VOID_STORAGE_MAX_SLOT * sizeof(VoidStorageItem*));
memset(_CUFProfiles, 0, MAX_CUF_PROFILES * sizeof(CUFProfile*));
@@ -1566,7 +1565,9 @@ void Player::Update(uint32 p_time)
GetSession()->m_muteTime = 0;
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME);
stmt->setInt64(0, 0); // Set the mute time to 0
- stmt->setUInt32(1, GetSession()->GetAccountId());
+ stmt->setString(1, "");
+ stmt->setString(2, "");
+ stmt->setUInt32(3, GetSession()->GetAccountId());
LoginDatabase.Execute(stmt);
}
@@ -2526,7 +2527,7 @@ void Player::Regenerate(Powers power)
return;
// Skip regeneration for power type we cannot have
- uint32 powerIndex = GetPowerIndexByClass(power, getClass());
+ uint32 powerIndex = GetPowerIndex(power);
if (powerIndex == MAX_POWERS)
return;
@@ -4896,7 +4897,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
stmt->setUInt32(0, guid);
trans->Append(stmt);
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_BY_OWNER);
stmt->setUInt32(0, guid);
trans->Append(stmt);
@@ -5500,7 +5501,8 @@ void Player::RepopAtGraveyard()
// and don't show spirit healer location
if (ClosestGrave)
{
- TeleportTo(ClosestGrave->map_id, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, GetOrientation());
+ float const* orientation = sObjectMgr->GetGraveyardOrientation(ClosestGrave->ID);
+ TeleportTo(ClosestGrave->map_id, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, orientation ? *orientation : GetOrientation());
if (isDead()) // not send if alive, because it used in TeleportTo()
{
WorldPacket data(SMSG_DEATH_RELEASE_LOC, 4*4); // show spirit healer position on minimap
@@ -7205,14 +7207,6 @@ void Player::_LoadCurrency(PreparedQueryResult result)
_currencyStorage.insert(PlayerCurrenciesMap::value_type(currencyID, cur));
- // load total conquest cap. should be after insert.
- if (currency->Category == CURRENCY_CATEGORY_META_CONQUEST)
- {
- uint32 cap = _GetCurrencyWeekCap(currency);
- if (cap > _ConquestCurrencyTotalWeekCap)
- _ConquestCurrencyTotalWeekCap = cap;
- }
-
} while (result->NextRow());
}
@@ -7267,7 +7261,7 @@ void Player::SendNewCurrency(uint32 id) const
uint32 precision = (entry->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1;
uint32 weekCount = itr->second.weekCount / precision;
- uint32 weekCap = _GetCurrencyWeekCap(entry) / precision;
+ uint32 weekCap = GetCurrencyWeekCap(entry) / precision;
packet.WriteBit(weekCount);
packet.WriteBits(0, 4); // some flags
@@ -7279,7 +7273,7 @@ void Player::SendNewCurrency(uint32 id) const
currencyData << uint32(weekCap);
//if (seasonTotal)
- // currencyData << uint32(seasonTotal);
+ // currencyData << uint32(seasonTotal / precision);
currencyData << uint32(entry->ID);
if (weekCount)
@@ -7308,7 +7302,7 @@ void Player::SendCurrencies() const
uint32 precision = (entry->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1;
uint32 weekCount = itr->second.weekCount / precision;
- uint32 weekCap = _GetCurrencyWeekCap(entry) / precision;
+ uint32 weekCap = GetCurrencyWeekCap(entry) / precision;
packet.WriteBit(weekCount);
packet.WriteBits(0, 4); // some flags
@@ -7320,7 +7314,7 @@ void Player::SendCurrencies() const
currencyData << uint32(weekCap);
//if (seasonTotal)
- // currencyData << uint32(seasonTotal);
+ // currencyData << uint32(seasonTotal / precision);
currencyData << uint32(entry->ID);
if (weekCount)
@@ -7348,36 +7342,28 @@ void Player::SendPvpRewards() const
GetSession()->SendPacket(&packet);
}
-uint32 Player::GetCurrency(uint32 id, bool precision) const
+uint32 Player::GetCurrency(uint32 id, bool usePrecision) const
{
PlayerCurrenciesMap::const_iterator itr = _currencyStorage.find(id);
if (itr == _currencyStorage.end())
return 0;
- if (!precision)
- return itr->second.totalCount;
-
CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(id);
- ASSERT(currency);
+ uint32 precision = (usePrecision && currency->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1;
- int32 mod = currency->Flags & CURRENCY_FLAG_HIGH_PRECISION ? 100 : 1;
- return itr->second.totalCount / mod;
+ return itr->second.totalCount / precision;
}
-uint32 Player::GetCurrencyOnWeek(uint32 id, bool precision) const
+uint32 Player::GetCurrencyOnWeek(uint32 id, bool usePrecision) const
{
PlayerCurrenciesMap::const_iterator itr = _currencyStorage.find(id);
if (itr == _currencyStorage.end())
return 0;
- if (!precision)
- return itr->second.weekCount;
-
CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(id);
- ASSERT(currency);
+ uint32 precision = (usePrecision && currency->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1;
- int32 mod = currency->Flags & CURRENCY_FLAG_HIGH_PRECISION ? 100 : 1;
- return itr->second.weekCount / mod;
+ return itr->second.weekCount / precision;
}
bool Player::HasCurrency(uint32 id, uint32 count) const
@@ -7417,12 +7403,12 @@ void Player::ModifyCurrency(uint32 id, int32 count, bool printLog/* = true*/, bo
}
// count can't be more then weekCap if used (weekCap > 0)
- uint32 weekCap = _GetCurrencyWeekCap(currency);
+ uint32 weekCap = GetCurrencyWeekCap(currency);
if (weekCap && count > int32(weekCap))
count = weekCap;
// count can't be more then totalCap if used (totalCap > 0)
- uint32 totalCap = _GetCurrencyTotalCap(currency);
+ uint32 totalCap = GetCurrencyTotalCap(currency);
if (totalCap && count > int32(totalCap))
count = totalCap;
@@ -7457,44 +7443,30 @@ void Player::ModifyCurrency(uint32 id, int32 count, bool printLog/* = true*/, bo
itr->second.totalCount = newTotalCount;
itr->second.weekCount = newWeekCount;
- // probably excessive checks
- if (IsInWorld() && !GetSession()->PlayerLoading())
- {
- if (count > 0)
- UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CURRENCY, id, count);
-
- if (currency->Category == CURRENCY_CATEGORY_META_CONQUEST)
- {
- //original conquest cap is highest of bg/arena conquest cap.
- if (weekCap > _ConquestCurrencyTotalWeekCap)
- _ConquestCurrencyTotalWeekCap = weekCap;
- // count was changed to week limit, now we can modify original points.
- ModifyCurrency(CURRENCY_TYPE_CONQUEST_POINTS, count, printLog );
- return;
- }
+ if (count > 0)
+ UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CURRENCY, id, count);
- // on new case just set init.
- if (itr->second.state == PLAYERCURRENCY_NEW)
- {
- SendNewCurrency(id);
- return;
- }
+ if (currency->Category == CURRENCY_CATEGORY_META_CONQUEST)
+ {
+ // count was changed to week limit, now we can modify original points.
+ ModifyCurrency(CURRENCY_TYPE_CONQUEST_POINTS, count, printLog);
+ return;
+ }
- WorldPacket packet(SMSG_UPDATE_CURRENCY, 12);
+ WorldPacket packet(SMSG_UPDATE_CURRENCY, 12);
- packet.WriteBit(weekCap != 0);
- packet.WriteBit(0); // hasSeasonCount
- packet.WriteBit(printLog); // print in log
+ packet.WriteBit(weekCap != 0);
+ packet.WriteBit(0); // hasSeasonCount
+ packet.WriteBit(!printLog); // print in log
- // if hasSeasonCount packet << uint32(seasontotalearned); TODO: save this in character DB and use it
+ // if hasSeasonCount packet << uint32(seasontotalearned); TODO: save this in character DB and use it
- packet << uint32(newTotalCount / precision);
- packet << uint32(id);
- if (weekCap)
- packet << uint32(newWeekCount / precision);
+ packet << uint32(newTotalCount / precision);
+ packet << uint32(id);
+ if (weekCap)
+ packet << uint32(newWeekCount / precision);
- GetSession()->SendPacket(&packet);
- }
+ GetSession()->SendPacket(&packet);
}
}
@@ -7517,11 +7489,9 @@ uint32 Player::GetCurrencyWeekCap(uint32 id, bool usePrecision) const
if (!entry)
return 0;
- uint32 cap = _GetCurrencyWeekCap(entry);
- if (usePrecision && entry->Flags & CURRENCY_FLAG_HIGH_PRECISION)
- cap /= 100;
+ uint32 precision = (usePrecision && entry->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1;
- return cap;
+ return GetCurrencyWeekCap(entry) / precision;
}
void Player::ResetCurrencyWeekCap()
@@ -7547,15 +7517,13 @@ void Player::ResetCurrencyWeekCap()
SendDirectMessage(&data);
}
-uint32 Player::_GetCurrencyWeekCap(const CurrencyTypesEntry* currency) const
+uint32 Player::GetCurrencyWeekCap(CurrencyTypesEntry const* currency) const
{
- uint32 cap = currency->WeekCap;
-
switch (currency->ID)
{
//original conquest not have week cap
case CURRENCY_TYPE_CONQUEST_POINTS:
- return _ConquestCurrencyTotalWeekCap;
+ return std::max(GetCurrencyWeekCap(CURRENCY_TYPE_CONQUEST_META_ARENA, false), GetCurrencyWeekCap(CURRENCY_TYPE_CONQUEST_META_RBG, false));
case CURRENCY_TYPE_CONQUEST_META_ARENA:
// should add precision mod = 100
return Trinity::Currency::ConquestRatingCalculator(_maxPersonalArenaRate) * CURRENCY_PRECISION;
@@ -7564,18 +7532,10 @@ uint32 Player::_GetCurrencyWeekCap(const CurrencyTypesEntry* currency) const
return Trinity::Currency::BgConquestRatingCalculator(GetRBGPersonalRating()) * CURRENCY_PRECISION;
}
- if (cap != currency->WeekCap && IsInWorld() && !GetSession()->PlayerLoading())
- {
- WorldPacket packet(SMSG_UPDATE_CURRENCY_WEEK_LIMIT, 8);
- packet << uint32(cap / ((currency->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? 100 : 1));
- packet << uint32(currency->ID);
- GetSession()->SendPacket(&packet);
- }
-
- return cap;
+ return currency->WeekCap;
}
-uint32 Player::_GetCurrencyTotalCap(const CurrencyTypesEntry* currency) const
+uint32 Player::GetCurrencyTotalCap(CurrencyTypesEntry const* currency) const
{
uint32 cap = currency->TotalCap;
@@ -7600,6 +7560,26 @@ uint32 Player::_GetCurrencyTotalCap(const CurrencyTypesEntry* currency) const
return cap;
}
+void Player::UpdateConquestCurrencyCap(uint32 currency)
+{
+ uint32 currenciesToUpdate[2] = { currency, CURRENCY_TYPE_CONQUEST_POINTS };
+
+ for (uint32 i = 0; i < 2; ++i)
+ {
+ CurrencyTypesEntry const* currencyEntry = sCurrencyTypesStore.LookupEntry(currenciesToUpdate[i]);
+ if (!currencyEntry)
+ continue;
+
+ uint32 precision = (currencyEntry->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? 100 : 1;
+ uint32 cap = GetCurrencyWeekCap(currencyEntry);
+
+ WorldPacket packet(SMSG_UPDATE_CURRENCY_WEEK_LIMIT, 8);
+ packet << uint32(cap / precision);
+ packet << uint32(currenciesToUpdate[i]);
+ GetSession()->SendPacket(&packet);
+ }
+}
+
void Player::SetInGuild(uint32 guildId)
{
if (guildId)
@@ -7635,7 +7615,10 @@ void Player::SetArenaTeamInfoField(uint8 slot, ArenaTeamInfoType type, uint32 v
{
SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + type, value);
if (type == ARENA_TEAM_PERSONAL_RATING && value > _maxPersonalArenaRate)
+ {
_maxPersonalArenaRate = value;
+ UpdateConquestCurrencyCap(CURRENCY_TYPE_CONQUEST_META_ARENA);
+ }
}
uint32 Player::GetArenaTeamIdFromDB(uint64 guid, uint8 type)
@@ -7754,14 +7737,8 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
}
// group update
- if (Group* group = GetGroup())
- {
+ if (GetGroup())
SetGroupUpdateFlag(GROUP_UPDATE_FULL);
- if (GetSession() && group->isLFGGroup() && sLFGMgr->IsTeleported(GetGUID()))
- for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
- if (Player* member = itr->getSource())
- GetSession()->SendNameQueryOpcode(member->GetGUID());
- }
m_zoneUpdateId = newZone;
m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL;
@@ -10825,7 +10802,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des
{
if (no_space_count)
*no_space_count = count;
- return swap ? EQUIP_ERR_CANT_SWAP :EQUIP_ERR_ITEM_NOT_FOUND;
+ return swap ? EQUIP_ERR_CANT_SWAP : EQUIP_ERR_ITEM_NOT_FOUND;
}
if (pItem)
@@ -11365,8 +11342,37 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool
if (!swap && GetItemByPos(INVENTORY_SLOT_BAG_0, eslot))
return EQUIP_ERR_NO_SLOT_AVAILABLE;
- // if swap ignore item (equipped also)
- InventoryResult res2 = CanEquipUniqueItem(pItem, swap ? eslot : uint8(NULL_SLOT));
+ // if we are swapping 2 equiped items, CanEquipUniqueItem check
+ // should ignore the item we are trying to swap, and not the
+ // destination item. CanEquipUniqueItem should ignore destination
+ // item only when we are swapping weapon from bag
+ uint8 ignore = uint8(NULL_SLOT);
+ switch (eslot)
+ {
+ case EQUIPMENT_SLOT_MAINHAND:
+ ignore = EQUIPMENT_SLOT_OFFHAND;
+ break;
+ case EQUIPMENT_SLOT_OFFHAND:
+ ignore = EQUIPMENT_SLOT_MAINHAND;
+ break;
+ case EQUIPMENT_SLOT_FINGER1:
+ ignore = EQUIPMENT_SLOT_FINGER2;
+ break;
+ case EQUIPMENT_SLOT_FINGER2:
+ ignore = EQUIPMENT_SLOT_FINGER1;
+ break;
+ case EQUIPMENT_SLOT_TRINKET1:
+ ignore = EQUIPMENT_SLOT_TRINKET2;
+ break;
+ case EQUIPMENT_SLOT_TRINKET2:
+ ignore = EQUIPMENT_SLOT_TRINKET1;
+ break;
+ }
+
+ if (ignore == uint8(NULL_SLOT) || pItem != GetItemByPos(INVENTORY_SLOT_BAG_0, ignore))
+ ignore = eslot;
+
+ InventoryResult res2 = CanEquipUniqueItem(pItem, swap ? ignore : uint8(NULL_SLOT));
if (res2 != EQUIP_ERR_OK)
return res2;
@@ -11760,22 +11766,12 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const
InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObject const* lootedObject) const
{
- LfgDungeonSet const& dungeons = sLFGMgr->GetSelectedDungeons(GetGUID());
- if (dungeons.empty())
- return EQUIP_ERR_OK; // not using LFG
-
if (!GetGroup() || !GetGroup()->isLFGGroup())
return EQUIP_ERR_OK; // not in LFG group
// check if looted object is inside the lfg dungeon
- bool lootedObjectInDungeon = false;
Map const* map = lootedObject->GetMap();
- if (uint32 dungeonId = sLFGMgr->GetDungeon(GetGroup()->GetGUID(), true))
- if (LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId))
- if (uint32(dungeon->map) == map->GetId() && dungeon->difficulty == map->GetDifficulty())
- lootedObjectInDungeon = true;
-
- if (!lootedObjectInDungeon)
+ if (!sLFGMgr->inLfgDungeonMap(GetGroup()->GetGUID(), map->GetId(), map->GetDifficulty()))
return EQUIP_ERR_OK;
if (!proto)
@@ -14275,7 +14271,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool
VendorItemData const* vendorItems = creature->GetVendorItems();
if (!vendorItems || vendorItems->Empty())
{
- sLog->outError(LOG_FILTER_SQL, "Creature %u (Entry: %u) have UNIT_NPC_FLAG_VENDOR but have empty trading item list.", creature->GetGUIDLow(), creature->GetEntry());
+ sLog->outError(LOG_FILTER_SQL, "Creature (GUID: %u, Entry: %u) have UNIT_NPC_FLAG_VENDOR but have empty trading item list.", creature->GetGUIDLow(), creature->GetEntry());
canTalk = false;
}
break;
@@ -17334,7 +17330,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
uint32 loadedPowers = 0;
for (uint32 i = 0; i < MAX_POWERS; ++i)
{
- if (GetPowerIndexByClass(Powers(i), getClass()) != MAX_POWERS)
+ if (GetPowerIndex(i) != MAX_POWERS)
{
uint32 savedPower = fields[47+loadedPowers].GetUInt32();
uint32 maxPower = GetUInt32Value(UNIT_FIELD_MAXPOWER1 + loadedPowers);
@@ -18928,7 +18924,7 @@ void Player::SaveToDB(bool create /*=false*/)
uint32 storedPowers = 0;
for (uint32 i = 0; i < MAX_POWERS; ++i)
{
- if (GetPowerIndexByClass(Powers(i), getClass()) != MAX_POWERS)
+ if (GetPowerIndex(i) != MAX_POWERS)
{
stmt->setUInt32(index++, GetUInt32Value(UNIT_FIELD_POWER1 + storedPowers));
if (++storedPowers >= MAX_POWERS_PER_CLASS)
@@ -19048,7 +19044,7 @@ void Player::SaveToDB(bool create /*=false*/)
uint32 storedPowers = 0;
for (uint32 i = 0; i < MAX_POWERS; ++i)
{
- if (GetPowerIndexByClass(Powers(i), getClass()) != MAX_POWERS)
+ if (GetPowerIndex(i) != MAX_POWERS)
{
stmt->setUInt32(index++, GetUInt32Value(UNIT_FIELD_POWER1 + storedPowers));
if (++storedPowers >= MAX_POWERS_PER_CLASS)
@@ -20917,11 +20913,6 @@ void Player::LeaveAllArenaTeams(uint64 guid)
while (result->NextRow());
}
-uint32 Player::GetRBGPersonalRating() const
-{
- return 0;
-}
-
void Player::SetRestBonus(float rest_bonus_new)
{
// Prevent resting on max level
@@ -21325,6 +21316,7 @@ void Player::InitDisplayIds()
inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot, int32 price, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore)
{
+ uint32 stacks = count / pProto->BuyCount;
ItemPosCountVec vDest;
uint16 uiDest = 0;
InventoryResult msg = bStore ?
@@ -21344,13 +21336,13 @@ inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 c
for (int i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i)
{
if (iece->RequiredItem[i])
- DestroyItemCount(iece->RequiredItem[i], iece->RequiredItemCount[i], true);
+ DestroyItemCount(iece->RequiredItem[i], iece->RequiredItemCount[i] * stacks, true);
}
for (int i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i)
{
if (iece->RequiredCurrency[i])
- ModifyCurrency(iece->RequiredCurrency[i], -int32(iece->RequiredCurrencyCount[i]), true, true);
+ ModifyCurrency(iece->RequiredCurrency[i], -int32(iece->RequiredCurrencyCount[i] * stacks), true, true);
}
}
@@ -21387,8 +21379,6 @@ inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 c
bool Player::BuyCurrencyFromVendorSlot(uint64 vendorGuid, uint32 vendorSlot, uint32 currency, uint32 count)
{
- vendorSlot += 1;
-
// cheating attempt
if (count < 1) count = 1;
@@ -21431,9 +21421,17 @@ bool Player::BuyCurrencyFromVendorSlot(uint64 vendorGuid, uint32 vendorSlot, uin
return false;
}
+ if (count % crItem->maxcount)
+ {
+ SendEquipError(EQUIP_ERR_CANT_BUY_QUANTITY, NULL, NULL);
+ return false;
+ }
+
+ uint32 stacks = count / crItem->maxcount;
+ ItemExtendedCostEntry const* iece = NULL;
if (crItem->ExtendedCost)
{
- ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
+ iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
if (!iece)
{
sLog->outError(LOG_FILTER_PLAYER, "Currency %u have wrong ExtendedCost field value %u", currency, crItem->ExtendedCost);
@@ -21442,7 +21440,7 @@ bool Player::BuyCurrencyFromVendorSlot(uint64 vendorGuid, uint32 vendorSlot, uin
for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i)
{
- if (iece->RequiredItem[i] && !HasItemCount(iece->RequiredItem[i], (iece->RequiredItemCount[i] * count)))
+ if (iece->RequiredItem[i] && !HasItemCount(iece->RequiredItem[i], (iece->RequiredItemCount[i] * stacks)))
{
SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL);
return false;
@@ -21461,9 +21459,7 @@ bool Player::BuyCurrencyFromVendorSlot(uint64 vendorGuid, uint32 vendorSlot, uin
return false;
}
- uint32 precision = (entry->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1;
-
- if (!HasCurrency(iece->RequiredCurrency[i], (iece->RequiredCurrencyCount[i] * count) / precision))
+ if (!HasCurrency(iece->RequiredCurrency[i], (iece->RequiredCurrencyCount[i] * stacks)))
{
SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); // Find correct error
return false;
@@ -21484,7 +21480,25 @@ bool Player::BuyCurrencyFromVendorSlot(uint64 vendorGuid, uint32 vendorSlot, uin
return false;
}
- ModifyCurrency(currency, crItem->maxcount, true, true);
+ ModifyCurrency(currency, count, true, true);
+ if (iece)
+ {
+ for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i)
+ {
+ if (!iece->RequiredItem[i])
+ continue;
+
+ DestroyItemCount(iece->RequiredItem[i], iece->RequiredItemCount[i] * stacks, true);
+ }
+
+ for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i)
+ {
+ if (!iece->RequiredCurrency[i])
+ continue;
+
+ ModifyCurrency(iece->RequiredCurrency[i], -int32(iece->RequiredCurrencyCount[i]) * stacks, false, true);
+ }
+ }
return true;
}
@@ -21557,12 +21571,13 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32
if (crItem->ExtendedCost)
{
// Can only buy full stacks for extended cost
- if (pProto->BuyCount != count)
+ if (count % pProto->BuyCount)
{
SendEquipError(EQUIP_ERR_CANT_BUY_QUANTITY, NULL, NULL);
return false;
}
+ uint32 stacks = count / pProto->BuyCount;
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
if (!iece)
{
@@ -21572,7 +21587,7 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32
for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i)
{
- if (iece->RequiredItem[i] && !HasItemCount(iece->RequiredItem[i], (iece->RequiredItemCount[i] * count)))
+ if (iece->RequiredItem[i] && !HasItemCount(iece->RequiredItem[i], iece->RequiredItemCount[i] * stacks))
{
SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL);
return false;
@@ -21591,9 +21606,7 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32
return false;
}
- uint32 precision = (entry->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1;
-
- if (!HasCurrency(iece->RequiredCurrency[i], (iece->RequiredCurrencyCount[i] * count) / precision))
+ if (!HasCurrency(iece->RequiredCurrency[i], iece->RequiredCurrencyCount[i] * stacks))
{
SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL);
return false;
@@ -22141,12 +22154,21 @@ void Player::LeaveBattleground(bool teleportToEntryPoint)
}
}
-bool Player::CanJoinToBattleground() const
+bool Player::CanJoinToBattleground(Battleground const* bg) const
{
// check Deserter debuff
if (HasAura(26013))
return false;
+ if (bg->isArena() && !GetSession()->HasPermission(RBAC_PERM_JOIN_ARENAS))
+ return false;
+
+ if (bg->IsRandom() && !GetSession()->HasPermission(RBAC_PERM_JOIN_RANDOM_BG))
+ return false;
+
+ if (!GetSession()->HasPermission(RBAC_PERM_JOIN_NORMAL_BG))
+ return false;
+
return true;
}
@@ -22430,26 +22452,28 @@ void Player::InitPrimaryProfessions()
SetFreePrimaryProfessions(sWorld->getIntConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL));
}
-void Player::ModifyMoney(int64 d)
+bool Player::ModifyMoney(int64 amount, bool sendError /*= true*/)
{
- sScriptMgr->OnPlayerMoneyChanged(this, d);
+ if (!amount)
+ return true;
+
+ sScriptMgr->OnPlayerMoneyChanged(this, amount);
- if (d < 0)
- SetMoney (GetMoney() > uint64(-d) ? GetMoney() + d : 0);
+ if (amount < 0)
+ SetMoney (GetMoney() > uint64(-amount) ? GetMoney() + amount : 0);
else
{
- uint64 newAmount = 0;
- if (GetMoney() < uint64(MAX_MONEY_AMOUNT - d))
- newAmount = GetMoney() + d;
+ if (GetMoney() < uint64(MAX_MONEY_AMOUNT - amount))
+ SetMoney(GetMoney() + amount);
else
{
- // "At Gold Limit"
- newAmount = MAX_MONEY_AMOUNT;
- if (d)
+ if (sendError)
SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL);
+ return false;
}
- SetMoney(newAmount);
}
+
+ return true;
}
Unit* Player::GetSelectedUnit() const
@@ -23811,14 +23835,14 @@ PartyResult Player::CanUninviteFromGroup() const
if (!sLFGMgr->GetKicksLeft(gguid))
return ERR_PARTY_LFG_BOOT_LIMIT;
- LfgState state = sLFGMgr->GetState(gguid);
- if (state == LFG_STATE_BOOT)
+ lfg::LfgState state = sLFGMgr->GetState(gguid);
+ if (state == lfg::LFG_STATE_BOOT)
return ERR_PARTY_LFG_BOOT_IN_PROGRESS;
- if (grp->GetMembersCount() <= LFG_GROUP_KICK_VOTES_NEEDED)
+ if (grp->GetMembersCount() <= lfg::LFG_GROUP_KICK_VOTES_NEEDED)
return ERR_PARTY_LFG_BOOT_TOO_FEW_PLAYERS;
- if (state == LFG_STATE_FINISHED_DUNGEON)
+ if (state == lfg::LFG_STATE_FINISHED_DUNGEON)
return ERR_PARTY_LFG_BOOT_DUNGEON_COMPLETE;
if (grp->isRollLootActive())
@@ -23848,21 +23872,17 @@ PartyResult Player::CanUninviteFromGroup() const
bool Player::isUsingLfg()
{
- return sLFGMgr->GetState(GetGUID()) != LFG_STATE_NONE;
+ return sLFGMgr->GetState(GetGUID()) != lfg::LFG_STATE_NONE;
}
bool Player::inRandomLfgDungeon()
{
- if (isUsingLfg())
+ if (sLFGMgr->selectedRandomLfgDungeon(GetGUID()))
{
- const LfgDungeonSet& dungeons = sLFGMgr->GetSelectedDungeons(GetGUID());
- if (!dungeons.empty())
- {
- LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(*dungeons.begin());
- if (dungeon && (dungeon->type == LFG_TYPE_RANDOM || dungeon->seasonal))
- return true;
- }
+ Map const* map = GetMap();
+ return sLFGMgr->inLfgDungeonMap(GetGUID(), map->GetId(), map->GetDifficulty());
}
+
return false;
}
@@ -25934,8 +25954,6 @@ void Player::DeleteRefundReference(uint32 it)
void Player::SendRefundInfo(Item* item)
{
- const CurrencyTypesEntry* currencyType;
- uint32 divisor;
// This function call unsets ITEM_FLAGS_REFUNDABLE if played time is over 2 hours.
item->UpdatePlayedTime(this);
@@ -25970,6 +25988,7 @@ void Player::SendRefundInfo(Item* item)
data.WriteBit(guid[0]);
data.WriteBit(guid[1]);
data.FlushBits();
+
data.WriteByteSeq(guid[7]);
data << uint32(GetTotalPlayedTime() - item->GetPlayedTime());
for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i) // item cost data
@@ -25984,12 +26003,10 @@ void Player::SendRefundInfo(Item* item)
data.WriteByteSeq(guid[2]);
for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i) // currency cost data
{
- currencyType = sCurrencyTypesStore.LookupEntry(iece->RequiredCurrency[i]);
- if (currencyType && currencyType->Flags & CURRENCY_FLAG_HIGH_PRECISION)
- divisor = 100;
- else
- divisor = 1;
- data << uint32(iece->RequiredCurrencyCount[i] / divisor);
+ CurrencyTypesEntry const* currencyType = sCurrencyTypesStore.LookupEntry(iece->RequiredCurrency[i]);
+ uint32 precision = (currencyType && currencyType->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1;
+
+ data << uint32(iece->RequiredCurrencyCount[i] / precision);
data << uint32(iece->RequiredCurrency[i]);
}
@@ -26028,8 +26045,6 @@ void Player::SendItemRefundResult(Item* item, ItemExtendedCostEntry const* iece,
{
ObjectGuid guid = item->GetGUID();
WorldPacket data(SMSG_ITEM_REFUND_RESULT, 1 + 1 + 8 + 4*8 + 4 + 4*8 + 1);
- const CurrencyTypesEntry* currencyType;
- uint32 divisor;
data.WriteBit(guid[4]);
data.WriteBit(guid[5]);
data.WriteBit(guid[1]);
@@ -26045,12 +26060,10 @@ void Player::SendItemRefundResult(Item* item, ItemExtendedCostEntry const* iece,
{
for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i)
{
- currencyType = sCurrencyTypesStore.LookupEntry(iece->RequiredCurrency[i]);
- if (currencyType && currencyType->Flags & CURRENCY_FLAG_HIGH_PRECISION)
- divisor = 100;
- else
- divisor = 1;
- data << uint32(iece->RequiredCurrencyCount[i] / divisor);
+ CurrencyTypesEntry const* currencyType = sCurrencyTypesStore.LookupEntry(iece->RequiredCurrency[i]);
+ uint32 precision = (currencyType && currencyType->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1;
+
+ data << uint32(iece->RequiredCurrencyCount[i] / precision);
data << uint32(iece->RequiredCurrency[i]);
}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index b27d66a7654..9034c26d4f1 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -531,53 +531,8 @@ enum PlayerFlags
PLAYER_FLAGS_UNK31 = 0x80000000
};
-// used for PLAYER__FIELD_KNOWN_TITLES field (uint64), (1<<bit_index) without (-1)
-// can't use enum for uint64 values
-#define PLAYER_TITLE_DISABLED UI64LIT(0x0000000000000000)
-#define PLAYER_TITLE_NONE UI64LIT(0x0000000000000001)
-#define PLAYER_TITLE_PRIVATE UI64LIT(0x0000000000000002) // 1
-#define PLAYER_TITLE_CORPORAL UI64LIT(0x0000000000000004) // 2
-#define PLAYER_TITLE_SERGEANT_A UI64LIT(0x0000000000000008) // 3
-#define PLAYER_TITLE_MASTER_SERGEANT UI64LIT(0x0000000000000010) // 4
-#define PLAYER_TITLE_SERGEANT_MAJOR UI64LIT(0x0000000000000020) // 5
-#define PLAYER_TITLE_KNIGHT UI64LIT(0x0000000000000040) // 6
-#define PLAYER_TITLE_KNIGHT_LIEUTENANT UI64LIT(0x0000000000000080) // 7
-#define PLAYER_TITLE_KNIGHT_CAPTAIN UI64LIT(0x0000000000000100) // 8
-#define PLAYER_TITLE_KNIGHT_CHAMPION UI64LIT(0x0000000000000200) // 9
-#define PLAYER_TITLE_LIEUTENANT_COMMANDER UI64LIT(0x0000000000000400) // 10
-#define PLAYER_TITLE_COMMANDER UI64LIT(0x0000000000000800) // 11
-#define PLAYER_TITLE_MARSHAL UI64LIT(0x0000000000001000) // 12
-#define PLAYER_TITLE_FIELD_MARSHAL UI64LIT(0x0000000000002000) // 13
-#define PLAYER_TITLE_GRAND_MARSHAL UI64LIT(0x0000000000004000) // 14
-#define PLAYER_TITLE_SCOUT UI64LIT(0x0000000000008000) // 15
-#define PLAYER_TITLE_GRUNT UI64LIT(0x0000000000010000) // 16
-#define PLAYER_TITLE_SERGEANT_H UI64LIT(0x0000000000020000) // 17
-#define PLAYER_TITLE_SENIOR_SERGEANT UI64LIT(0x0000000000040000) // 18
-#define PLAYER_TITLE_FIRST_SERGEANT UI64LIT(0x0000000000080000) // 19
-#define PLAYER_TITLE_STONE_GUARD UI64LIT(0x0000000000100000) // 20
-#define PLAYER_TITLE_BLOOD_GUARD UI64LIT(0x0000000000200000) // 21
-#define PLAYER_TITLE_LEGIONNAIRE UI64LIT(0x0000000000400000) // 22
-#define PLAYER_TITLE_CENTURION UI64LIT(0x0000000000800000) // 23
-#define PLAYER_TITLE_CHAMPION UI64LIT(0x0000000001000000) // 24
-#define PLAYER_TITLE_LIEUTENANT_GENERAL UI64LIT(0x0000000002000000) // 25
-#define PLAYER_TITLE_GENERAL UI64LIT(0x0000000004000000) // 26
-#define PLAYER_TITLE_WARLORD UI64LIT(0x0000000008000000) // 27
-#define PLAYER_TITLE_HIGH_WARLORD UI64LIT(0x0000000010000000) // 28
-#define PLAYER_TITLE_GLADIATOR UI64LIT(0x0000000020000000) // 29
-#define PLAYER_TITLE_DUELIST UI64LIT(0x0000000040000000) // 30
-#define PLAYER_TITLE_RIVAL UI64LIT(0x0000000080000000) // 31
-#define PLAYER_TITLE_CHALLENGER UI64LIT(0x0000000100000000) // 32
-#define PLAYER_TITLE_SCARAB_LORD UI64LIT(0x0000000200000000) // 33
-#define PLAYER_TITLE_CONQUEROR UI64LIT(0x0000000400000000) // 34
-#define PLAYER_TITLE_JUSTICAR UI64LIT(0x0000000800000000) // 35
-#define PLAYER_TITLE_CHAMPION_OF_THE_NAARU UI64LIT(0x0000001000000000) // 36
-#define PLAYER_TITLE_MERCILESS_GLADIATOR UI64LIT(0x0000002000000000) // 37
-#define PLAYER_TITLE_OF_THE_SHATTERED_SUN UI64LIT(0x0000004000000000) // 38
-#define PLAYER_TITLE_HAND_OF_ADAL UI64LIT(0x0000008000000000) // 39
-#define PLAYER_TITLE_VENGEFUL_GLADIATOR UI64LIT(0x0000010000000000) // 40
-
-#define KNOWN_TITLES_SIZE 3
-#define MAX_TITLE_INDEX (KNOWN_TITLES_SIZE*64) // 3 uint64 fields
+#define KNOWN_TITLES_SIZE 4
+#define MAX_TITLE_INDEX (KNOWN_TITLES_SIZE * 64) // 4 uint64 fields
// used in PLAYER_FIELD_BYTES values
enum PlayerFieldByteFlags
@@ -1476,9 +1431,9 @@ class Player : public Unit, public GridObject<Player>
/// send conquest currency points and their cap week/arena
void SendPvpRewards() const;
/// return count of currency witch has plr
- uint32 GetCurrency(uint32 id, bool precision) const;
+ uint32 GetCurrency(uint32 id, bool usePrecision) const;
/// return count of currency gaind on current week
- uint32 GetCurrencyOnWeek(uint32 id, bool precision) const;
+ uint32 GetCurrencyOnWeek(uint32 id, bool usePrecision) const;
/// return week cap by currency id
uint32 GetCurrencyWeekCap(uint32 id, bool usePrecision) const;
/// return presence related currency
@@ -1776,7 +1731,7 @@ class Player : public Unit, public GridObject<Player>
void setWeaponChangeTimer(uint32 time) {m_weaponChangeTimer = time;}
uint64 GetMoney() const { return GetUInt64Value(PLAYER_FIELD_COINAGE); }
- void ModifyMoney(int64 d);
+ bool ModifyMoney(int64 amount, bool sendError = true);
bool HasEnoughMoney(uint64 amount) const { return GetMoney() >= amount; }
bool HasEnoughMoney(int64 amount) const
{
@@ -2094,7 +2049,7 @@ class Player : public Unit, public GridObject<Player>
uint32 GetArenaPersonalRating(uint8 slot) const { return GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + ARENA_TEAM_PERSONAL_RATING); }
void SetArenaTeamIdInvited(uint32 ArenaTeamId) { m_ArenaTeamIdInvited = ArenaTeamId; }
uint32 GetArenaTeamIdInvited() { return m_ArenaTeamIdInvited; }
- uint32 GetRBGPersonalRating() const;
+ uint32 GetRBGPersonalRating() const { return 0; }
Difficulty GetDifficulty(bool isRaid) const { return isRaid ? m_raidDifficulty : m_dungeonDifficulty; }
Difficulty GetDungeonDifficulty() const { return m_dungeonDifficulty; }
@@ -2469,11 +2424,15 @@ class Player : public Unit, public GridObject<Player>
WorldLocation const& GetBattlegroundEntryPoint() const { return m_bgData.joinPos; }
void SetBattlegroundEntryPoint();
- void SetBGTeam(uint32 team) { m_bgData.bgTeam = team; }
+ void SetBGTeam(uint32 team)
+ {
+ m_bgData.bgTeam = team;
+ SetByteValue(PLAYER_BYTES_3, 3, uint8(team == ALLIANCE ? 1 : 0));
+ }
uint32 GetBGTeam() const { return m_bgData.bgTeam ? m_bgData.bgTeam : GetTeam(); }
void LeaveBattleground(bool teleportToEntryPoint = true);
- bool CanJoinToBattleground() const;
+ bool CanJoinToBattleground(Battleground const* bg) const;
bool CanReportAfkDueToLimit();
void ReportedAfkBy(Player* reporter);
void ClearAfkReports() { m_bgData.bgAfkReporter.clear(); }
@@ -2928,20 +2887,23 @@ class Player : public Unit, public GridObject<Player>
PlayerCurrenciesMap _currencyStorage;
/**
- * @name _GetCurrencyWeekCap
+ * @name GetCurrencyWeekCap
* @brief return week cap for selected currency
- * @param currency CurrencyTypesEntry witch should get week cap
+ * @param CurrencyTypesEntry for which to retrieve weekly cap
*/
- uint32 _GetCurrencyWeekCap(const CurrencyTypesEntry* currency) const;
+ uint32 GetCurrencyWeekCap(CurrencyTypesEntry const* currency) const;
/*
- * @name _GetCurrencyTotalCap
+ * @name GetCurrencyTotalCap
* @brief return total cap for selected currency
- * @param currency CurrencyTypesEntry witch should get week cap
+ * @param CurrencyTypesEntry for which to retrieve total cap
*/
- uint32 _GetCurrencyTotalCap(const CurrencyTypesEntry* currency) const;
+ uint32 GetCurrencyTotalCap(CurrencyTypesEntry const* currency) const;
+
+ /// Updates weekly conquest point cap (dynamic cap)
+ void UpdateConquestCurrencyCap(uint32 currency);
VoidStorageItem* _voidStorageItems[VOID_STORAGE_MAX_SLOT];
@@ -3145,7 +3107,6 @@ class Player : public Unit, public GridObject<Player>
uint32 _activeCheats;
uint32 _maxPersonalArenaRate;
- uint32 _ConquestCurrencyTotalWeekCap;
PhaseMgr phaseMgr;
};
diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp
index ce761db2dcb..9644d4d5a6c 100644
--- a/src/server/game/Entities/Transport/Transport.cpp
+++ b/src/server/game/Entities/Transport/Transport.cpp
@@ -680,8 +680,8 @@ uint32 Transport::AddNPCPassenger(uint32 tguid, uint32 entry, float x, float y,
void Transport::UpdatePosition(MovementInfo* mi)
{
float transport_o = mi->pos.GetOrientation() - mi->t_pos.GetOrientation();
- float transport_x = mi->pos.m_positionX - (mi->t_pos.m_positionX * std::cos(transport_o) - mi->t_pos.m_positionY*sin(transport_o));
- float transport_y = mi->pos.m_positionY - (mi->t_pos.m_positionY * std::cos(transport_o) + mi->t_pos.m_positionX*sin(transport_o));
+ float transport_x = mi->pos.m_positionX - (mi->t_pos.m_positionX * std::cos(transport_o) - mi->t_pos.m_positionY * std::sin(transport_o));
+ float transport_y = mi->pos.m_positionY - (mi->t_pos.m_positionY * std::cos(transport_o) + mi->t_pos.m_positionX * std::sin(transport_o));
float transport_z = mi->pos.m_positionZ - mi->t_pos.m_positionZ;
Relocate(transport_x, transport_y, transport_z, transport_o);
@@ -715,7 +715,7 @@ void Transport::CalculatePassengerPosition(float& x, float& y, float& z, float&
void Transport::CalculatePassengerOffset(float& x, float& y, float& z, float& o)
{
- o = o - GetOrientation();
+ o -= GetOrientation();
z -= GetPositionZ();
y -= GetPositionY(); // y = searchedY * std::cos(o) + searchedX * std::sin(o)
x -= GetPositionX(); // x = searchedX * std::cos(o) + searchedY * std::sin(o + pi)
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index faf6c5dcf0b..f7bc6a99fb1 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -256,8 +256,8 @@ Unit::Unit(bool isWorldObject): WorldObject(isWorldObject)
m_speed_rate[i] = 1.0f;
m_charmInfo = NULL;
- m_reducedThreatPercent = 0;
- m_misdirectionTargetGUID = 0;
+
+ _redirectThreadInfo = RedirectThreatInfo();
// remove aurastates allowing special moves
for (uint8 i = 0; i < MAX_REACTIVE; ++i)
@@ -385,10 +385,10 @@ bool Unit::haveOffhandWeapon() const
return m_canDualWield;
}
-void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed)
+void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath, bool forceDestination)
{
- Movement::MoveSplineInit init(*this);
- init.MoveTo(x, y, z);
+ Movement::MoveSplineInit init(this);
+ init.MoveTo(x, y, z, generatePath, forceDestination);
init.SetVelocity(speed);
init.Launch();
}
@@ -4776,106 +4776,6 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType
SendAttackStateUpdate(&dmgInfo);
}
-bool Unit::HandleHasteAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
-{
- SpellInfo const* hasteSpell = triggeredByAura->GetSpellInfo();
-
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
-
- uint32 triggered_spell_id = 0;
- Unit* target = victim;
- int32 basepoints0 = 0;
-
- switch (hasteSpell->SpellFamilyName)
- {
- case SPELLFAMILY_ROGUE:
- {
- switch (hasteSpell->Id)
- {
- // Blade Flurry
- case 13877:
- case 33735:
- {
- target = SelectNearbyTarget(victim);
- if (!target)
- return false;
- basepoints0 = damage;
- triggered_spell_id = 22482;
- break;
- }
- }
- break;
- }
- }
-
- // processed charge only counting case
- if (!triggered_spell_id)
- return true;
-
- SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id);
-
- if (!triggerEntry)
- {
- sLog->outError(LOG_FILTER_UNITS, "Unit::HandleHasteAuraProc: Spell %u has non-existing triggered spell %u", hasteSpell->Id, triggered_spell_id);
- return false;
- }
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
- return false;
-
- if (basepoints0)
- CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
-
- return true;
-}
-
-bool Unit::HandleSpellCritChanceAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
-{
- SpellInfo const* triggeredByAuraSpell = triggeredByAura->GetSpellInfo();
-
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
-
- uint32 triggered_spell_id = 0;
- Unit* target = victim;
- int32 basepoints0 = 0;
-
- // processed charge only counting case
- if (!triggered_spell_id)
- return true;
-
- SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id);
-
- if (!triggerEntry)
- {
- sLog->outError(LOG_FILTER_UNITS, "Unit::HandleSpellCritChanceAuraProc: Spell %u has non-existing triggered spell %u", triggeredByAuraSpell->Id, triggered_spell_id);
- return false;
- }
-
- // default case
- if (!target || (target != this && !target->isAlive()))
- return false;
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
- return false;
-
- if (basepoints0)
- CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
-
- return true;
-}
-
bool Unit::HandleAuraProcOnPowerAmount(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 /*procEx*/, uint32 cooldown)
{
// Get triggered aura spell info
@@ -5020,38 +4920,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
{
switch (dummySpell->Id)
{
- // Bloodworms Health Leech
- case 50453:
- {
- if (Unit* owner = GetOwner())
- {
- basepoints0 = int32(damage * 1.50f);
- target = owner;
- triggered_spell_id = 50454;
- break;
- }
- return false;
- }
- // Eye for an Eye
- case 9799:
- case 25988:
- {
- // return damage % to attacker but < 50% own total health
- basepoints0 = int32(std::min(CalculatePct(damage, triggerAmount), CountPctFromMaxHealth(50)));
- triggered_spell_id = 25997;
- break;
- }
- // Sweeping Strikes
- case 18765:
- case 35429:
- {
- target = SelectNearbyTarget(victim);
- if (!target)
- return false;
-
- triggered_spell_id = 26654;
- break;
- }
// Unstable Power
case 24658:
{
@@ -5068,67 +4936,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
RemoveAuraFromStack(24662);
return true;
}
- // Adaptive Warding (Frostfire Regalia set)
- case 28764:
- {
- if (!procSpell)
- return false;
-
- // find Mage Armor
- if (!GetAuraEffect(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT, SPELLFAMILY_MAGE, 0x10000000, 0, 0))
- return false;
-
- switch (GetFirstSchoolInMask(procSpell->GetSchoolMask()))
- {
- case SPELL_SCHOOL_NORMAL:
- case SPELL_SCHOOL_HOLY:
- return false; // ignored
- case SPELL_SCHOOL_FIRE: triggered_spell_id = 28765; break;
- case SPELL_SCHOOL_NATURE: triggered_spell_id = 28768; break;
- case SPELL_SCHOOL_FROST: triggered_spell_id = 28766; break;
- case SPELL_SCHOOL_SHADOW: triggered_spell_id = 28769; break;
- case SPELL_SCHOOL_ARCANE: triggered_spell_id = 28770; break;
- default:
- return false;
- }
-
- target = this;
- break;
- }
- // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
- case 27539:
- {
- if (!procSpell)
- return false;
-
- switch (GetFirstSchoolInMask(procSpell->GetSchoolMask()))
- {
- case SPELL_SCHOOL_NORMAL:
- return false; // ignore
- case SPELL_SCHOOL_HOLY: triggered_spell_id = 27536; break;
- case SPELL_SCHOOL_FIRE: triggered_spell_id = 27533; break;
- case SPELL_SCHOOL_NATURE: triggered_spell_id = 27538; break;
- case SPELL_SCHOOL_FROST: triggered_spell_id = 27534; break;
- case SPELL_SCHOOL_SHADOW: triggered_spell_id = 27535; break;
- case SPELL_SCHOOL_ARCANE: triggered_spell_id = 27540; break;
- default:
- return false;
- }
-
- target = this;
- break;
- }
- // Mana Leech (Passive) (Priest Pet Aura)
- case 28305:
- {
- // Cast on owner
- target = GetOwner();
- if (!target)
- return false;
-
- triggered_spell_id = 34650;
- break;
- }
// Mark of Malice
case 33493:
{
@@ -5319,14 +5126,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
}
return false;
}
- // Living Seed
- case 48504:
- {
- triggered_spell_id = 48503;
- basepoints0 = triggerAmount;
- target = this;
- break;
- }
// Kill command
case 58914:
{
@@ -5486,50 +5285,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
}
break;
}
- case 71875: // Item - Black Bruise: Necrotic Touch Proc
- case 71877:
- {
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- triggered_spell_id = 71879;
- break;
- }
- // Item - Shadowmourne Legendary
- case 71903:
- {
- if (!victim || !victim->isAlive() || HasAura(73422)) // cant collect shards while under effect of Chaos Bane buff
- return false;
-
- CastSpell(this, 71905, true, NULL, triggeredByAura);
-
- // this can't be handled in AuraScript because we need to know victim
- Aura const* dummy = GetAura(71905);
- if (!dummy || dummy->GetStackAmount() < 10)
- return false;
-
- RemoveAurasDueToSpell(71905);
- triggered_spell_id = 71904;
- target = victim;
- break;
- }
- // Shadow's Fate (Shadowmourne questline)
- case 71169:
- {
- Unit* caster = triggeredByAura->GetCaster();
- if (caster && caster->GetTypeId() == TYPEID_PLAYER && caster->ToPlayer()->GetQuestStatus(24547) == QUEST_STATUS_INCOMPLETE)
- {
- CastSpell(caster, 71203, true);
- return true;
- }
- else
- return false;
- }
- // Essence of the Blood Queen
- case 70871:
- {
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- CastCustomSpell(70872, SPELLVALUE_BASE_POINT0, basepoints0, this);
- return true;
- }
case 65032: // Boom aura (321 Boombot)
{
if (victim->GetEntry() != 33343) // Scrapbot
@@ -5542,13 +5297,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
instance->DoCastSpellOnPlayers(65037); // Achievement criteria marker
break;
}
- // Dark Hunger (The Lich King encounter)
- case 69383:
- {
- basepoints0 = CalculatePct(int32(damage), 50);
- triggered_spell_id = 69384;
- break;
- }
case 47020: // Enter vehicle XT-002 (Scrapbot)
{
if (GetTypeId() != TYPEID_UNIT)
@@ -5579,22 +5327,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
triggered_spell_id = 29442;
break;
}
- // Master of Elements
- if (dummySpell->SpellIconID == 1920)
- {
- if (!procSpell)
- return false;
-
- // mana cost save
- int32 cost = int32(procSpell->ManaCost + CalculatePct(GetCreateMana(), procSpell->ManaCostPercentage));
- basepoints0 = CalculatePct(cost, triggerAmount);
- if (basepoints0 <= 0)
- return false;
-
- target = this;
- triggered_spell_id = 29077;
- break;
- }
// Arcane Potency
if (dummySpell->SpellIconID == 2120)
{
@@ -5612,7 +5344,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
}
break;
}
-
// Hot Streak & Improved Hot Streak
if (dummySpell->SpellIconID == 2999)
{
@@ -5664,16 +5395,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
return true;
}
- // Ignite
- case 11119:
- case 11120:
- case 12846:
- {
- basepoints0 = CalculatePct(damage, triggerAmount);
- triggered_spell_id = 12654;
- basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
- break;
- }
// Glyph of Ice Block
case 56372:
{
@@ -5685,25 +5406,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
player->RemoveSpellCooldown(122, true);
break;
}
- // Blessing of Ancient Kings (Val'anyr, Hammer of Ancient Kings)
- case 64411:
- {
- if (!victim)
- return false;
- basepoints0 = int32(CalculatePct(damage, 15));
- if (AuraEffect* aurEff = victim->GetAuraEffect(64413, 0, GetGUID()))
- {
- // The shield can grow to a maximum size of 20, 000 damage absorbtion
- aurEff->SetAmount(std::min<int32>(aurEff->GetAmount() + basepoints0, 20000));
-
- // Refresh and return to prevent replacing the aura
- aurEff->GetBase()->RefreshDuration();
- return true;
- }
- target = victim;
- triggered_spell_id = 64413;
- break;
- }
// Permafrost
case 11175:
case 12569:
@@ -5725,16 +5427,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
{
switch (dummySpell->Id)
{
- // Sweeping Strikes
- case 12328:
- {
- target = SelectNearbyTarget(victim);
- if (!target)
- return false;
-
- triggered_spell_id = 26654;
- break;
- }
// Victorious
case 32216:
{
@@ -5840,16 +5532,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage);
return true;
}
- // Fel Synergy
- if (dummySpell->SpellIconID == 3222)
- {
- target = GetGuardianPet();
- if (!target)
- return false;
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- triggered_spell_id = 54181;
- break;
- }
switch (dummySpell->Id)
{
// Glyph of Shadowflame
@@ -5935,24 +5617,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
victim->CastSpell(victim, 57669, true, castItem, triggeredByAura);
return true; // no hidden cooldown
}
- // Divine Aegis
- if (dummySpell->SpellIconID == 2820)
- {
- if (!target)
- return false;
-
- // Multiple effects stack, so let's try to find this aura.
- int32 bonus = 0;
- if (AuraEffect const* aurEff = target->GetAuraEffect(47753, 0))
- bonus = aurEff->GetAmount();
-
- basepoints0 = CalculatePct(int32(damage), triggerAmount) + bonus;
- if (basepoints0 > target->getLevel() * 125)
- basepoints0 = target->getLevel() * 125;
-
- triggered_spell_id = 47753;
- break;
- }
// Body and Soul
if (dummySpell->SpellIconID == 2218)
{
@@ -5992,19 +5656,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
target = this;
break;
}
- // Glyph of Prayer of Healing
- case 55680:
- {
- triggered_spell_id = 56161;
-
- SpellInfo const* GoPoH = sSpellMgr->GetSpellInfo(triggered_spell_id);
- if (!GoPoH)
- return false;
-
- int32 tickcount = GoPoH->GetMaxDuration() / GoPoH->Effects[EFFECT_0].Amplitude;
- basepoints0 = CalculatePct(int32(damage), triggerAmount) / tickcount;
- break;
- }
// Phantasm
case 47569:
case 47570:
@@ -6228,13 +5879,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
return true;
}
}
- // Living Seed
- if (dummySpell->SpellIconID == 2860)
- {
- triggered_spell_id = 48504;
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- break;
- }
break;
}
case SPELLFAMILY_ROGUE:
@@ -6250,16 +5894,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
triggered_spell_id = 32747;
break;
}
- case 57934: // Tricks of the Trade
- {
- Unit* redirectTarget = GetMisdirectionTarget();
- RemoveAura(57934);
- if (!redirectTarget)
- break;
- CastSpell(this, 59628, true);
- CastSpell(redirectTarget, 57933, true);
- break;
- }
}
switch (dummySpell->SpellIconID)
@@ -6321,34 +5955,10 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
break;
}
}
-
- switch (dummySpell->Id)
- {
- case 34477: // Misdirection
- {
- if (!GetMisdirectionTarget())
- return false;
- triggered_spell_id = 35079; // 4 sec buff on self
- target = this;
- break;
- }
- }
break;
}
case SPELLFAMILY_PALADIN:
{
- // Seal of Righteousness - melee proc dummy (addition (MWS * (0.011 * AP.022 * holy spell power) * 100 / 100) damage)
- if (dummySpell->SpellFamilyFlags[0] & 0x8000000)
- {
- if (effIndex != 0)
- return false;
- triggered_spell_id = 25742;
- float ap = GetTotalAttackPowerValue(BASE_ATTACK);
- int32 holy = SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_HOLY) +
- victim->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_HOLY);
- basepoints0 = (int32)GetAttackTime(BASE_ATTACK) * int32(ap * 0.011f + 0.022f * holy) / 1000;
- break;
- }
// Light's Beacon - Beacon of Light
if (dummySpell->Id == 53651)
{
@@ -6472,7 +6082,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
}
break;
}
- // Seal of Truth (damage calc on apply aura)
case 31801:
{
if (effIndex != 0) // effect 2 used by seal unleashing code
@@ -6875,20 +6484,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
target = this;
break;
}
- // Earth Shield
- if (dummySpell->Id == 974)
- {
- // 3.0.8: Now correctly uses the Shaman's own spell critical strike chance to determine the chance of a critical heal.
- originalCaster = triggeredByAura->GetCasterGUID();
- target = this;
- basepoints0 = triggerAmount;
-
- // Glyph of Earth Shield
- if (AuraEffect* aur = GetAuraEffect(63279, 0))
- AddPct(basepoints0, aur->GetAmount());
- triggered_spell_id = 379;
- break;
- }
// Flametongue Weapon (Passive)
if (dummySpell->SpellFamilyFlags[0] & 0x200000)
{
@@ -7143,88 +6738,9 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
return true;
}
-bool Unit::HandleObsModEnergyAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
-{
- SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo();
- //uint32 effIndex = triggeredByAura->GetEffIndex();
- //int32 triggerAmount = triggeredByAura->GetAmount();
-
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
-
- uint32 triggered_spell_id = 0;
- Unit* target = victim;
- int32 basepoints0 = 0;
-
- // processed charge only counting case
- if (!triggered_spell_id)
- return true;
-
- SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id);
-
- // Try handle unknown trigger spells
- if (!triggerEntry)
- {
- sLog->outError(LOG_FILTER_UNITS, "Unit::HandleObsModEnergyAuraProc: Spell %u has non-existing triggered spell %u", dummySpell->Id, triggered_spell_id);
- return false;
- }
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
- return false;
- if (basepoints0)
- CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
- return true;
-}
-bool Unit::HandleModDamagePctTakenAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
-{
- SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo();
- //uint32 effIndex = triggeredByAura->GetEffIndex();
- //int32 triggerAmount = triggeredByAura->GetAmount();
-
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
-
- uint32 triggered_spell_id = 0;
- Unit* target = victim;
- int32 basepoints0 = 0;
-
/*
- switch (dummySpell->SpellFamilyName)
- {
-
- }
*/
- // processed charge only counting case
- if (!triggered_spell_id)
- return true;
-
- SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id);
-
- if (!triggerEntry)
- {
- sLog->outError(LOG_FILTER_UNITS, "Unit::HandleModDamagePctTakenAuraProc: Spell %u has non-existing triggered spell %u", dummySpell->Id, triggered_spell_id);
- return false;
- }
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
- return false;
-
- if (basepoints0)
- CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
-
- return true;
-}
// Used in case when access to whole aura is needed
// All procs should be handled like this...
@@ -9708,7 +9224,7 @@ int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask)
DoneAdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
// Check if we are ever using mana - PaperDollFrame.lua
- if (GetPowerIndexByClass(POWER_MANA, getClass()) != MAX_POWERS)
+ if (GetPowerIndex(POWER_MANA) != MAX_POWERS)
DoneAdvertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT)) - 10); // spellpower from intellect
// Damage bonus from stats
@@ -10231,7 +9747,7 @@ int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask)
AdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
// Check if we are ever using mana - PaperDollFrame.lua
- if (GetPowerIndexByClass(POWER_MANA, getClass()) != MAX_POWERS)
+ if (GetPowerIndex(POWER_MANA) != MAX_POWERS)
AdvertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT)) - 10); // spellpower from intellect
// Healing bonus from stats
@@ -12848,7 +12364,7 @@ void Unit::SetMaxHealth(uint32 val)
int32 Unit::GetPower(Powers power) const
{
- uint32 powerIndex = GetPowerIndexByClass(power, getClass());
+ uint32 powerIndex = GetPowerIndex(power);
if (powerIndex == MAX_POWERS)
return 0;
@@ -12857,7 +12373,7 @@ int32 Unit::GetPower(Powers power) const
int32 Unit::GetMaxPower(Powers power) const
{
- uint32 powerIndex = GetPowerIndexByClass(power, getClass());
+ uint32 powerIndex = GetPowerIndex(power);
if (powerIndex == MAX_POWERS)
return 0;
@@ -12866,7 +12382,7 @@ int32 Unit::GetMaxPower(Powers power) const
void Unit::SetPower(Powers power, int32 val)
{
- uint32 powerIndex = GetPowerIndexByClass(power, getClass());
+ uint32 powerIndex = GetPowerIndex(power);
if (powerIndex == MAX_POWERS)
return;
@@ -12905,7 +12421,7 @@ void Unit::SetPower(Powers power, int32 val)
void Unit::SetMaxPower(Powers power, int32 val)
{
- uint32 powerIndex = GetPowerIndexByClass(power, getClass());
+ uint32 powerIndex = GetPowerIndex(power);
if (powerIndex == MAX_POWERS)
return;
@@ -12932,6 +12448,19 @@ void Unit::SetMaxPower(Powers power, int32 val)
SetPower(power, val);
}
+uint32 Unit::GetPowerIndex(uint32 powerType) const
+{
+ /// This is here because hunter pets are of the warrior class.
+ /// With the current implementation, the core only gives them
+ /// POWER_RAGE, so we enforce the class to hunter so that they
+ /// effectively get focus power.
+ uint32 classId = getClass();
+ if (ToPet() && ToPet()->getPetType() == HUNTER_PET)
+ classId = CLASS_HUNTER;
+
+ return GetPowerIndexByClass(powerType, classId);
+}
+
int32 Unit::GetCreatePowers(Powers power) const
{
switch (power)
@@ -13606,7 +13135,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
SpellInfo const* spellInfo = i->aura->GetSpellInfo();
uint32 Id = i->aura->GetId();
- AuraApplication const* aurApp = i->aura->GetApplicationOfTarget(GetGUID());
+ AuraApplication* aurApp = i->aura->GetApplicationOfTarget(GetGUID());
bool prepare = i->aura->CallScriptPrepareProcHandlers(aurApp, eventInfo);
@@ -13660,17 +13189,10 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
case SPELL_AURA_PROC_TRIGGER_DAMAGE:
{
// target has to be valid
- if (!target)
+ if (!eventInfo.GetProcTarget())
break;
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", triggeredByAura->GetAmount(), spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- SpellNonMeleeDamage damageInfo(this, target, spellInfo->Id, spellInfo->SchoolMask);
- uint32 newDamage = SpellDamageBonusDone(target, spellInfo, triggeredByAura->GetAmount(), SPELL_DIRECT_DAMAGE);
- newDamage = target->SpellDamageBonusTaken(this, spellInfo, newDamage, SPELL_DIRECT_DAMAGE);
- CalculateSpellDamageTaken(&damageInfo, newDamage, spellInfo);
- DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
- SendSpellNonMeleeDamageLog(&damageInfo);
- DealSpellDamage(&damageInfo, true);
+ triggeredByAura->HandleProcTriggerDamageAuraProc(aurApp, eventInfo); // this function is part of the new proc system
takeCharges = true;
break;
}
@@ -13690,23 +13212,13 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
break;
}
case SPELL_AURA_OBS_MOD_POWER:
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (HandleObsModEnergyAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- takeCharges = true;
- break;
+ case SPELL_AURA_MOD_SPELL_CRIT_CHANCE:
case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (HandleModDamagePctTakenAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- takeCharges = true;
- break;
case SPELL_AURA_MOD_MELEE_HASTE:
case SPELL_AURA_MOD_MELEE_HASTE_3:
- {
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (HandleHasteAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- takeCharges = true;
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, isVictim ? "a victim's" : "an attacker's", triggeredByAura->GetId());
+ takeCharges = true;
break;
- }
case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
{
sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
@@ -13778,11 +13290,6 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
if (triggeredByAura->GetCasterGUID() == target->GetGUID())
takeCharges = true;
break;
- case SPELL_AURA_MOD_SPELL_CRIT_CHANCE:
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s spell crit chance aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (procSpell && HandleSpellCritChanceAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- takeCharges = true;
- break;
// CC Auras which use their amount amount to drop
// Are there any more auras which need this?
case SPELL_AURA_MOD_CONFUSE:
@@ -13985,9 +13492,10 @@ void Unit::StopMoving()
if (!IsInWorld() || movespline->Finalized())
return;
- // Update position using old spline
- UpdateSplinePosition();
- Movement::MoveSplineInit(*this).Stop();
+ Movement::MoveSplineInit init(this);
+ init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset());
+ init.SetFacing(GetOrientation());
+ init.Launch();
}
void Unit::SendMovementFlagUpdate(bool self /* = false */)
@@ -15039,15 +14547,32 @@ void Unit::SetControlled(bool apply, UnitState state)
{
switch (state)
{
- case UNIT_STATE_STUNNED: if (HasAuraType(SPELL_AURA_MOD_STUN)) return;
- else SetStunned(false); break;
- case UNIT_STATE_ROOT: if (HasAuraType(SPELL_AURA_MOD_ROOT) || GetVehicle()) return;
- else SetRooted(false); break;
- case UNIT_STATE_CONFUSED:if (HasAuraType(SPELL_AURA_MOD_CONFUSE)) return;
- else SetConfused(false); break;
- case UNIT_STATE_FLEEING: if (HasAuraType(SPELL_AURA_MOD_FEAR)) return;
- else SetFeared(false); break;
- default: return;
+ case UNIT_STATE_STUNNED:
+ if (HasAuraType(SPELL_AURA_MOD_STUN))
+ return;
+
+ SetStunned(false);
+ break;
+ case UNIT_STATE_ROOT:
+ if (HasAuraType(SPELL_AURA_MOD_ROOT) || GetVehicle())
+ return;
+
+ SetRooted(false);
+ break;
+ case UNIT_STATE_CONFUSED:
+ if (HasAuraType(SPELL_AURA_MOD_CONFUSE))
+ return;
+
+ SetConfused(false);
+ break;
+ case UNIT_STATE_FLEEING:
+ if (HasAuraType(SPELL_AURA_MOD_FEAR))
+ return;
+
+ SetFeared(false);
+ break;
+ default:
+ return;
}
ClearUnitState(state);
@@ -16659,8 +16184,8 @@ void Unit::_ExitVehicle(Position const* exitPosition)
SendMessageToSet(&data, false);
}
- Movement::MoveSplineInit init(*this);
- init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
+ Movement::MoveSplineInit init(this);
+ init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), false);
init.SetFacing(GetOrientation());
init.SetTransportExit();
init.Launch();
@@ -17669,7 +17194,7 @@ void Unit::SetInFront(Unit const* target)
void Unit::SetFacingTo(float ori)
{
- Movement::MoveSplineInit init(*this);
+ Movement::MoveSplineInit init(this);
init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset());
init.SetFacing(ori);
init.Launch();
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 40918dbb611..a8e088b2dd3 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -497,6 +497,7 @@ enum UnitState
UNIT_STATE_FLEEING_MOVE = 0x02000000,
UNIT_STATE_CHASE_MOVE = 0x04000000,
UNIT_STATE_FOLLOW_MOVE = 0x08000000,
+ UNIT_STATE_IGNORE_PATHFINDING = 0x10000000, // do not use pathfinding in any MovementGenerator
UNIT_STATE_UNATTACKABLE = (UNIT_STATE_IN_FLIGHT | UNIT_STATE_ONVEHICLE),
// for real move using movegen check and stop (except unstoppable flight)
UNIT_STATE_MOVING = UNIT_STATE_ROAMING_MOVE | UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE | UNIT_STATE_CHASE_MOVE | UNIT_STATE_FOLLOW_MOVE,
@@ -973,6 +974,28 @@ struct SpellPeriodicAuraLogInfo
uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition);
+struct RedirectThreatInfo
+{
+ RedirectThreatInfo() : _targetGUID(0), _threatPct(0) { }
+ uint64 _targetGUID;
+ uint32 _threatPct;
+
+ uint64 GetTargetGUID() { return _targetGUID; }
+ uint32 GetThreatPct() { return _threatPct; }
+
+ void Set(uint64 guid, uint32 pct)
+ {
+ _targetGUID = guid;
+ _threatPct = pct;
+ }
+
+ void ModifyThreatPct(int32 amount)
+ {
+ amount += _threatPct;
+ _threatPct = uint32(std::max(0, amount));
+ }
+};
+
#define MAX_DECLINED_NAME_CASES 5
struct DeclinedName
@@ -1599,7 +1622,7 @@ class Unit : public WorldObject
void JumpTo(float speedXY, float speedZ, bool forward = true);
void JumpTo(WorldObject* obj, float speedZ);
- void MonsterMoveWithSpeed(float x, float y, float z, float speed);
+ void MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath = false, bool forceDestination = false);
//void SetFacing(float ori, WorldObject* obj = NULL);
//void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL);
void SendMovementFlagUpdate(bool self = false);
@@ -1854,6 +1877,7 @@ class Unit : public WorldObject
uint32 GetCreateHealth() const { return GetUInt32Value(UNIT_FIELD_BASE_HEALTH); }
void SetCreateMana(uint32 val) { SetUInt32Value(UNIT_FIELD_BASE_MANA, val); }
uint32 GetCreateMana() const { return GetUInt32Value(UNIT_FIELD_BASE_MANA); }
+ uint32 GetPowerIndex(uint32 powerType) const;
int32 GetCreatePowers(Powers power) const;
float GetPosStat(Stats stat) const { return GetFloatValue(UNIT_FIELD_POSSTAT0+stat); }
float GetNegStat(Stats stat) const { return GetFloatValue(UNIT_FIELD_NEGSTAT0+stat); }
@@ -2139,13 +2163,12 @@ class Unit : public WorldObject
uint32 GetModelForForm(ShapeshiftForm form) const;
uint32 GetModelForTotem(PlayerTotemType totemType);
- void SetReducedThreatPercent(uint32 pct, uint64 guid)
- {
- m_reducedThreatPercent = pct;
- m_misdirectionTargetGUID = guid;
- }
- uint32 GetReducedThreatPercent() { return m_reducedThreatPercent; }
- Unit* GetMisdirectionTarget() { return m_misdirectionTargetGUID ? GetUnit(*this, m_misdirectionTargetGUID) : NULL; }
+ // Redirect Threat
+ void SetRedirectThreat(uint64 guid, uint32 pct) { _redirectThreadInfo.Set(guid, pct); }
+ void ResetRedirectThreat() { SetRedirectThreat(0, 0); }
+ void ModifyRedirectThreat(int32 amount) { _redirectThreadInfo.ModifyThreatPct(amount); }
+ uint32 GetRedirectThreatPercent() { return _redirectThreadInfo.GetThreatPct(); }
+ Unit* GetRedirectThreatTarget() { return _redirectThreadInfo.GetTargetGUID() ? GetUnit(*this, _redirectThreadInfo.GetTargetGUID()) : NULL; }
bool IsAIEnabled, NeedChangeAI;
bool CreateVehicleKit(uint32 id, uint32 creatureEntry);
@@ -2298,10 +2321,6 @@ class Unit : public WorldObject
bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, SpellInfo const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const* & spellProcEvent);
bool HandleAuraProcOnPowerAmount(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
- bool HandleHasteAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
- bool HandleSpellCritChanceAuraProc(Unit* victim, uint32 damage, AuraEffect* triggredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
- bool HandleObsModEnergyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
- bool HandleModDamagePctTakenAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool * handled);
bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown);
@@ -2338,8 +2357,7 @@ class Unit : public WorldObject
ComboPointHolderSet m_ComboPointHolders;
- uint32 m_reducedThreatPercent;
- uint64 m_misdirectionTargetGUID;
+ RedirectThreatInfo _redirectThreadInfo;
bool m_cleanupDone; // lock made to not add stuff after cleanup before delete
bool m_duringRemoveFromWorld; // lock made to not add stuff after begining removing from world
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index d81feffa71e..16a90018293 100644..100755
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -381,7 +381,7 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
unit->SendClearTarget(); // SMSG_BREAK_TARGET
unit->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures)
// also adds MOVEMENTFLAG_ROOT
- Movement::MoveSplineInit init(*unit);
+ Movement::MoveSplineInit init(unit);
init.DisableTransportPathTransformations();
init.MoveTo(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
init.SetFacing(0.0f);
@@ -466,7 +466,6 @@ void Vehicle::RelocatePassengers()
float px, py, pz, po;
passenger->m_movementInfo.t_pos.GetPosition(px, py, pz, po);
CalculatePassengerPosition(px, py, pz, po);
-
passenger->UpdatePosition(px, py, pz, po);
}
}
diff --git a/src/server/game/Entities/Vehicle/VehicleDefines.h b/src/server/game/Entities/Vehicle/VehicleDefines.h
index 7c4ac090743..d7df1b44b99 100644
--- a/src/server/game/Entities/Vehicle/VehicleDefines.h
+++ b/src/server/game/Entities/Vehicle/VehicleDefines.h
@@ -100,6 +100,8 @@ typedef std::map<int8, VehicleSeat> SeatMap;
class TransportBase
{
public:
+ virtual ~TransportBase() { }
+
/// This method transforms supplied transport offsets into global coordinates
virtual void CalculatePassengerPosition(float& x, float& y, float& z, float& o) = 0;
diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp
index 82bf4702c53..051d76f46ed 100644
--- a/src/server/game/Events/GameEventMgr.cpp
+++ b/src/server/game/Events/GameEventMgr.cpp
@@ -211,7 +211,6 @@ void GameEventMgr::LoadFromDB()
{
mGameEvent.clear();
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 game events. DB table `game_event` is empty.");
-
return;
}
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 45859290d1f..8597b6098a9 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -268,6 +268,7 @@ ObjectMgr::~ObjectMgr()
itr->second.Clear();
_cacheTrainerSpellStore.clear();
+ _graveyardOrientations.clear();
for (DungeonEncounterContainer::iterator itr =_dungeonEncounterStore.begin(); itr != _dungeonEncounterStore.end(); ++itr)
for (DungeonEncounterList::iterator encounterItr = itr->second.begin(); encounterItr != itr->second.end(); ++encounterItr)
@@ -288,6 +289,34 @@ void ObjectMgr::AddLocaleString(std::string const& s, LocaleConstant locale, Str
}
}
+void ObjectMgr::LoadGraveyardOrientations()
+{
+ uint32 oldMSTime = getMSTime();
+
+ _graveyardOrientations.clear();
+
+ QueryResult result = WorldDatabase.Query("SELECT id, orientation FROM graveyard_orientation");
+
+ if (!result)
+ return;
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 id = fields[0].GetUInt32();
+ if (!sWorldSafeLocsStore.LookupEntry(id))
+ {
+ sLog->outError(LOG_FILTER_SERVER_LOADING, "Graveyard %u referenced in graveyard_orientation doesn't exist.", id);
+ continue;
+ }
+ _graveyardOrientations[id] = fields[1].GetFloat();
+
+ } while (result->NextRow());
+
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %lu graveyard orientations in %u ms", (unsigned long)_graveyardOrientations.size(), GetMSTimeDiffToNow(oldMSTime));
+}
+
void ObjectMgr::LoadCreatureLocales()
{
uint32 oldMSTime = getMSTime();
@@ -390,15 +419,15 @@ void ObjectMgr::LoadCreatureTemplates()
"modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, exp_unk, faction_A, faction_H, npcflag, speed_walk, "
// 22 23 24 25 26 27 28 29 30 31 32 33 34
"speed_run, scale, rank, mindmg, maxdmg, dmgschool, attackpower, dmg_multiplier, baseattacktime, rangeattacktime, unit_class, unit_flags, unit_flags2, "
- // 35 36 37 38 39 40 41 42 43 44
- "dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, "
- // 45 46 47 48 49 50 51 52 53 54 55
+ // 35 36 37 38 39 40 41 42 43
+ "dynamicflags, family, trainer_type, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, "
+ // 44 45 46 47 48 49 50 51 52 53 54
"type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, "
- // 56 57 58 59 60 61 62 63 64 65 66 67 68 69
+ // 55 56 59 60 61 62 63 64 65 66 67 68 69 70
"spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, "
- // 70 71 72 73 74 75 76 77 78 79 80 81
+ // 71 72 73 74 75 76 77 78 79 80 81 82
"InhabitType, HoverHeight, Health_mod, Mana_mod, Mana_mod_extra, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, "
- // 82 83 84 85 86 87 88
+ // 83 84 85 86 87 88 89
" questItem6, movementId, RegenHealth, equipment_id, mechanic_immune_mask, flags_extra, ScriptName "
"FROM creature_template;");
@@ -459,48 +488,47 @@ void ObjectMgr::LoadCreatureTemplates()
creatureTemplate.dynamicflags = fields[35].GetUInt32();
creatureTemplate.family = uint32(fields[36].GetUInt8());
creatureTemplate.trainer_type = uint32(fields[37].GetUInt8());
- creatureTemplate.trainer_spell = fields[38].GetUInt32();
- creatureTemplate.trainer_class = uint32(fields[39].GetUInt8());
- creatureTemplate.trainer_race = uint32(fields[40].GetUInt8());
- creatureTemplate.minrangedmg = fields[41].GetFloat();
- creatureTemplate.maxrangedmg = fields[42].GetFloat();
- creatureTemplate.rangedattackpower = uint32(fields[43].GetUInt16());
- creatureTemplate.type = uint32(fields[44].GetUInt8());
- creatureTemplate.type_flags = fields[45].GetUInt32();
- creatureTemplate.type_flags2 = fields[46].GetUInt32();
- creatureTemplate.lootid = fields[47].GetUInt32();
- creatureTemplate.pickpocketLootId = fields[48].GetUInt32();
- creatureTemplate.SkinLootId = fields[49].GetUInt32();
+ creatureTemplate.trainer_class = uint32(fields[38].GetUInt8());
+ creatureTemplate.trainer_race = uint32(fields[39].GetUInt8());
+ creatureTemplate.minrangedmg = fields[40].GetFloat();
+ creatureTemplate.maxrangedmg = fields[41].GetFloat();
+ creatureTemplate.rangedattackpower = uint32(fields[42].GetUInt16());
+ creatureTemplate.type = uint32(fields[43].GetUInt8());
+ creatureTemplate.type_flags = fields[44].GetUInt32();
+ creatureTemplate.type_flags2 = fields[45].GetUInt32();
+ creatureTemplate.lootid = fields[46].GetUInt32();
+ creatureTemplate.pickpocketLootId = fields[47].GetUInt32();
+ creatureTemplate.SkinLootId = fields[48].GetUInt32();
for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
- creatureTemplate.resistance[i] = fields[50 + i - 1].GetInt16();
+ creatureTemplate.resistance[i] = fields[49 + i - 1].GetInt16();
for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i)
- creatureTemplate.spells[i] = fields[56 + i].GetUInt32();
-
- creatureTemplate.PetSpellDataId = fields[64].GetUInt32();
- creatureTemplate.VehicleId = fields[65].GetUInt32();
- creatureTemplate.mingold = fields[66].GetUInt32();
- creatureTemplate.maxgold = fields[67].GetUInt32();
- creatureTemplate.AIName = fields[68].GetString();
- creatureTemplate.MovementType = uint32(fields[69].GetUInt8());
- creatureTemplate.InhabitType = uint32(fields[70].GetUInt8());
- creatureTemplate.HoverHeight = fields[71].GetFloat();
- creatureTemplate.ModHealth = fields[72].GetFloat();
- creatureTemplate.ModMana = fields[73].GetFloat();
- creatureTemplate.ModManaExtra = fields[74].GetFloat();
- creatureTemplate.ModArmor = fields[75].GetFloat();
- creatureTemplate.RacialLeader = fields[76].GetBool();
+ creatureTemplate.spells[i] = fields[55 + i].GetUInt32();
+
+ creatureTemplate.PetSpellDataId = fields[63].GetUInt32();
+ creatureTemplate.VehicleId = fields[64].GetUInt32();
+ creatureTemplate.mingold = fields[65].GetUInt32();
+ creatureTemplate.maxgold = fields[66].GetUInt32();
+ creatureTemplate.AIName = fields[67].GetString();
+ creatureTemplate.MovementType = uint32(fields[68].GetUInt8());
+ creatureTemplate.InhabitType = uint32(fields[69].GetUInt8());
+ creatureTemplate.HoverHeight = fields[70].GetFloat();
+ creatureTemplate.ModHealth = fields[71].GetFloat();
+ creatureTemplate.ModMana = fields[72].GetFloat();
+ creatureTemplate.ModManaExtra = fields[73].GetFloat();
+ creatureTemplate.ModArmor = fields[74].GetFloat();
+ creatureTemplate.RacialLeader = fields[75].GetBool();
for (uint8 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i)
- creatureTemplate.questItems[i] = fields[77 + i].GetUInt32();
+ creatureTemplate.questItems[i] = fields[76 + i].GetUInt32();
- creatureTemplate.movementId = fields[83].GetUInt32();
- creatureTemplate.RegenHealth = fields[84].GetBool();
- creatureTemplate.equipmentId = fields[85].GetUInt32();
- creatureTemplate.MechanicImmuneMask = fields[86].GetUInt32();
- creatureTemplate.flags_extra = fields[87].GetUInt32();
- creatureTemplate.ScriptID = GetScriptId(fields[88].GetCString());
+ creatureTemplate.movementId = fields[82].GetUInt32();
+ creatureTemplate.RegenHealth = fields[83].GetBool();
+ creatureTemplate.equipmentId = fields[84].GetUInt32();
+ creatureTemplate.MechanicImmuneMask = fields[85].GetUInt32();
+ creatureTemplate.flags_extra = fields[86].GetUInt32();
+ creatureTemplate.ScriptID = GetScriptId(fields[87].GetCString());
++count;
}
@@ -662,12 +690,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
continue;
}
- if (cInfo->trainer_spell != difficultyInfo->trainer_spell)
- {
- sLog->outError(LOG_FILTER_SQL, "Creature (Entry: %u) has different `trainer_spell` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
- continue;
- }
-
if (!difficultyInfo->AIName.empty())
{
sLog->outError(LOG_FILTER_SQL, "Creature (Entry: %u) lists difficulty %u mode entry %u with `AIName` filled in. `AIName` of difficulty 0 mode creature is always used instead.",
@@ -1193,7 +1215,6 @@ void ObjectMgr::LoadLinkedRespawn()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 linked respawns. DB table `linked_respawn` is empty.");
-
return;
}
@@ -1424,7 +1445,6 @@ void ObjectMgr::LoadCreatures()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 creatures. DB table `creature` is empty.");
-
return;
}
@@ -1732,7 +1752,7 @@ void ObjectMgr::LoadGameobjects()
if (!result)
{
- sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 gameobjects. DB table `gameobject` is empty.");
+ sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 gameobjects. DB table `gameobject` is empty.");
return;
}
@@ -2633,7 +2653,6 @@ void ObjectMgr::LoadVehicleTemplateAccessories()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 vehicle template accessories. DB table `vehicle_template_accessory` is empty.");
-
return;
}
@@ -2728,7 +2747,6 @@ void ObjectMgr::LoadPetLevelInfo()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 level pet stats definitions. DB table `pet_levelstats` is empty.");
-
return;
}
@@ -2866,7 +2884,6 @@ void ObjectMgr::LoadPlayerInfo()
if (!result)
{
-
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 player create definitions. DB table `playercreateinfo` is empty.");
exit(1);
}
@@ -3025,7 +3042,6 @@ void ObjectMgr::LoadPlayerInfo()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 player create spells. DB table `%s` is empty.", sWorld->getBoolConfig(CONFIG_START_ALL_SPELLS) ? "playercreateinfo_spell_custom" : "playercreateinfo_spell");
-
}
else
{
@@ -3087,7 +3103,6 @@ void ObjectMgr::LoadPlayerInfo()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 player create actions. DB table `playercreateinfo_action` is empty.");
-
}
else
{
@@ -3133,7 +3148,6 @@ void ObjectMgr::LoadPlayerInfo()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 level stats definitions. DB table `player_levelstats` is empty.");
-
exit(1);
}
@@ -3246,7 +3260,6 @@ void ObjectMgr::LoadPlayerInfo()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 xp for level definitions. DB table `player_xp_for_level` is empty.");
-
exit(1);
}
@@ -4672,7 +4685,7 @@ void ObjectMgr::LoadWaypointScripts()
for (ScriptMapMap::const_iterator itr = sWaypointScripts.begin(); itr != sWaypointScripts.end(); ++itr)
actionSet.insert(itr->first);
- PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WOLRD_SEL_WAYPOINT_DATA_ACTION);
+ PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_ACTION);
PreparedQueryResult result = WorldDatabase.Query(stmt);
if (result)
@@ -4942,7 +4955,6 @@ void ObjectMgr::LoadInstanceEncounters()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 instance encounters, table is empty!");
-
return;
}
@@ -4962,7 +4974,7 @@ void ObjectMgr::LoadInstanceEncounters()
continue;
}
- if (lastEncounterDungeon && !sLFGMgr->GetLFGDungeon(lastEncounterDungeon))
+ if (lastEncounterDungeon && !sLFGMgr->GetLFGDungeonEntry(lastEncounterDungeon))
{
sLog->outError(LOG_FILTER_SQL, "Table `instance_encounters` has an encounter %u (%s) marked as final for invalid dungeon id %u, skipped!", entry, dungeonEncounter->encounterName, lastEncounterDungeon);
continue;
@@ -6403,7 +6415,6 @@ void ObjectMgr::LoadExplorationBaseXP()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 BaseXP definitions. DB table `exploration_basexp` is empty.");
-
return;
}
@@ -6558,7 +6569,7 @@ void ObjectMgr::LoadReputationRewardRate()
QueryResult result = WorldDatabase.Query("SELECT faction, quest_rate, quest_daily_rate, quest_weekly_rate, quest_monthly_rate, creature_rate, spell_rate FROM reputation_reward_rate");
if (!result)
{
- sLog->outError(LOG_FILTER_SQL, ">> Loaded `reputation_reward_rate`, table is empty!");
+ sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded `reputation_reward_rate`, table is empty!");
return;
}
@@ -6647,7 +6658,6 @@ void ObjectMgr::LoadReputationOnKill()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 creature award reputation definitions. DB table `creature_onkill_reputation` is empty.");
-
return;
}
@@ -6835,7 +6845,6 @@ void ObjectMgr::LoadPointsOfInterest()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 Points of Interest definitions. DB table `points_of_interest` is empty.");
-
return;
}
@@ -6881,7 +6890,6 @@ void ObjectMgr::LoadQuestPOI()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 quest POI definitions. DB table `quest_poi` is empty.");
-
return;
}
@@ -6949,7 +6957,6 @@ void ObjectMgr::LoadNPCSpellClickSpells()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 spellclick spells. DB table `npc_spellclick_spells` is empty.");
-
return;
}
@@ -7426,7 +7433,7 @@ bool ObjectMgr::LoadTrinityStrings(const char* table, int32 min_value, int32 max
if (!result)
{
if (min_value == MIN_TRINITY_STRING_ID) // error only in case internal strings
- sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 trinity strings. DB table `%s` is empty. Cannot continue.", table);
+ sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 trinity strings. DB table `%s` is empty. Cannot continue.", table);
else
sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 string templates. DB table `%s` is empty.", table);
@@ -7503,7 +7510,6 @@ void ObjectMgr::LoadFishingBaseSkillLevel()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 areas for fishing base skill level. DB table `skill_fishing_base_level` is empty.");
-
return;
}
@@ -7629,8 +7635,7 @@ void ObjectMgr::LoadGameTele()
if (!result)
{
- sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 GameTeleports. DB table `game_tele` is empty!");
-
+ sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 GameTeleports. DB table `game_tele` is empty!");
return;
}
@@ -7769,8 +7774,7 @@ void ObjectMgr::LoadMailLevelRewards()
if (!result)
{
- sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 level dependent mail rewards. DB table `mail_level_reward` is empty.");
-
+ sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 level dependent mail rewards. DB table `mail_level_reward` is empty.");
return;
}
@@ -8040,7 +8044,6 @@ void ObjectMgr::LoadGossipMenu()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 gossip_menu entries. DB table `gossip_menu` is empty!");
-
return;
}
@@ -8086,7 +8089,6 @@ void ObjectMgr::LoadGossipMenuItems()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 gossip_menu_option entries. DB table `gossip_menu_option` is empty!");
-
return;
}
@@ -8299,8 +8301,7 @@ void ObjectMgr::LoadScriptNames()
if (!result)
{
-
- sLog->outError(LOG_FILTER_SQL, ">> Loaded empty set of Script Names!");
+ sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded empty set of Script Names!");
return;
}
@@ -8477,7 +8478,6 @@ void ObjectMgr::LoadFactionChangeAchievements()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 faction change achievement pairs. DB table `player_factionchange_achievement` is empty.");
-
return;
}
@@ -8548,7 +8548,6 @@ void ObjectMgr::LoadFactionChangeSpells()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 faction change spell pairs. DB table `player_factionchange_spells` is empty.");
-
return;
}
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index eb56bb09b93..8c14f902c1f 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -561,6 +561,7 @@ struct GraveYardData
};
typedef std::multimap<uint32, GraveYardData> GraveYardContainer;
+typedef UNORDERED_MAP<uint32 /* graveyard Id */, float /* orientation */> GraveyardOrientationContainer;
typedef std::pair<GraveYardContainer::const_iterator, GraveYardContainer::const_iterator> GraveYardMapBounds;
typedef std::pair<GraveYardContainer::iterator, GraveYardContainer::iterator> GraveYardMapBoundsNonConst;
@@ -867,6 +868,7 @@ class ObjectMgr
void LoadDbScriptStrings();
void LoadCreatureClassLevelStats();
void LoadCreatureLocales();
+ void LoadGraveyardOrientations();
void LoadCreatureTemplates();
void LoadCreatureTemplateAddons();
void CheckCreatureTemplate(CreatureTemplate const* cInfo);
@@ -1116,6 +1118,16 @@ class ObjectMgr
return &iter->second;
}
+
+ float const* GetGraveyardOrientation(uint32 id) const
+ {
+ GraveyardOrientationContainer::const_iterator iter = _graveyardOrientations.find(id);
+ if (iter != _graveyardOrientations.end())
+ return &iter->second;
+
+ return NULL;
+ }
+
void AddVendorItem(uint32 entry, uint32 item, int32 maxcount, uint32 incrtime, uint32 extendedCost, uint8 type, bool persist = true); // for event
bool RemoveVendorItem(uint32 entry, uint32 item, uint8 type, bool persist = true); // for event
bool IsVendorItemValid(uint32 vendor_entry, uint32 id, int32 maxcount, uint32 ptime, uint32 ExtendedCost, uint8 type, Player* player = NULL, std::set<uint32>* skip_vendors = NULL, uint32 ORnpcflag = 0) const;
@@ -1314,6 +1326,8 @@ class ObjectMgr
CacheVendorItemContainer _cacheVendorItemStore;
CacheTrainerSpellContainer _cacheTrainerSpellStore;
+ GraveyardOrientationContainer _graveyardOrientations;
+
std::set<uint32> _difficultyEntries[MAX_DIFFICULTY - 1]; // already loaded difficulty 1 value in creatures, used in CheckCreatureTemplate
std::set<uint32> _hasDifficultyEntries[MAX_DIFFICULTY - 1]; // already loaded creatures with difficulty 1 values, used in CheckCreatureTemplate
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index d70d1c824ec..031a8ee96e7 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -1529,7 +1529,7 @@ void Group::SendUpdateToPlayer(uint64 playerGUID, MemberSlot* slot)
data << uint8(slot->roles);
if (isLFGGroup())
{
- data << uint8(sLFGMgr->GetState(m_guid) == LFG_STATE_FINISHED_DUNGEON ? 2 : 0); // FIXME - Dungeon save status? 2 = done
+ data << uint8(sLFGMgr->GetState(m_guid) == lfg::LFG_STATE_FINISHED_DUNGEON ? 2 : 0); // FIXME - Dungeon save status? 2 = done
data << uint32(sLFGMgr->GetDungeon(m_guid));
data << uint8(0); // 4.x new
}
@@ -1866,7 +1866,7 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const*
if (bgOrTemplate->GetTypeID() == BATTLEGROUND_RB && member->InBattlegroundQueue())
return ERR_IN_NON_RANDOM_BG;
// check for deserter debuff in case not arena queue
- if (bgOrTemplate->GetTypeID() != BATTLEGROUND_AA && !member->CanJoinToBattleground())
+ if (bgOrTemplate->GetTypeID() != BATTLEGROUND_AA && !member->CanJoinToBattleground(bgOrTemplate))
return ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS;
// check if member can join any more battleground queues
if (!member->HasFreeBattlegroundQueueId())
diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp
index cef21863b60..b112888d1b3 100644
--- a/src/server/game/Guilds/Guild.cpp
+++ b/src/server/game/Guilds/Guild.cpp
@@ -2035,16 +2035,20 @@ bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint64 amount, bool
sScriptMgr->OnGuildMemberWitdrawMoney(this, player, amount, repair);
SQLTransaction trans = CharacterDatabase.BeginTransaction();
- // Update remaining money amount
- member->UpdateBankWithdrawValue(trans, GUILD_BANK_MAX_TABS, amount);
- // Remove money from bank
- _ModifyBankMoney(trans, amount, false);
// Add money to player (if required)
if (!repair)
{
- player->ModifyMoney((int64)amount);
+ if (!player->ModifyMoney(amount))
+ return false;
+
player->SaveGoldToDB(trans);
}
+
+ // Update remaining money amount
+ member->UpdateBankWithdrawValue(trans, GUILD_BANK_MAX_TABS, amount);
+ // Remove money from bank
+ _ModifyBankMoney(trans, amount, false);
+
// Log guild bank event
_LogBankEvent(trans, repair ? GUILD_BANK_LOG_REPAIR_MONEY : GUILD_BANK_LOG_WITHDRAW_MONEY, uint8(0), player->GetGUIDLow(), amount);
CharacterDatabase.CommitTransaction(trans);
@@ -2520,7 +2524,7 @@ void Guild::BroadcastAddonToGuild(WorldSession* session, bool officerOnly, std::
if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK))
{
WorldPacket data;
- ChatHandler::FillMessageData(&data, session, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, CHAT_MSG_ADDON, NULL, 0, msg.c_str(), NULL, prefix.c_str());
+ ChatHandler::FillMessageData(&data, session, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, uint32(CHAT_MSG_ADDON), NULL, 0, msg.c_str(), NULL, prefix.c_str());
for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
if (Player* player = itr->second->FindPlayer())
if (player->GetSession() && _HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) &&
diff --git a/src/server/game/Handlers/AddonHandler.cpp b/src/server/game/Handlers/AddonHandler.cpp
index 7e62280f17c..68c93259fcb 100644
--- a/src/server/game/Handlers/AddonHandler.cpp
+++ b/src/server/game/Handlers/AddonHandler.cpp
@@ -30,7 +30,7 @@ AddonHandler::~AddonHandler()
{
}
-bool AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target)
+bool AddonHandler::BuildAddonPacket(WorldPacket* source, WorldPacket* target)
{
ByteBuffer AddOnPacked;
uLongf AddonRealSize;
@@ -38,10 +38,10 @@ bool AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target)
uint32 TempValue;
// broken addon packet, can't be received from real client
- if (Source->rpos() + 4 > Source->size())
+ if (source->rpos() + 4 > source->size())
return false;
- *Source >> TempValue; // get real size of the packed structure
+ *source >> TempValue; // get real size of the packed structure
// empty addon packet, nothing process, can't be received from real client
if (!TempValue)
@@ -49,13 +49,13 @@ bool AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target)
AddonRealSize = TempValue; // temp value because ZLIB only excepts uLongf
- CurrentPosition = Source->rpos(); // get the position of the pointer in the structure
+ CurrentPosition = source->rpos(); // get the position of the pointer in the structure
AddOnPacked.resize(AddonRealSize); // resize target for zlib action
- if (!uncompress(const_cast<uint8*>(AddOnPacked.contents()), &AddonRealSize, const_cast<uint8*>((*Source).contents() + CurrentPosition), (*Source).size() - CurrentPosition)!= Z_OK)
+ if (!uncompress(AddOnPacked.contents(), &AddonRealSize, source->contents() + CurrentPosition, source->size() - CurrentPosition)!= Z_OK)
{
- Target->Initialize(SMSG_ADDON_INFO);
+ target->Initialize(SMSG_ADDON_INFO);
uint32 addonsCount;
AddOnPacked >> addonsCount; // addons count?
@@ -81,14 +81,14 @@ bool AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target)
sLog->outDebug(LOG_FILTER_NETWORKIO, "ADDON: Name: %s, Enabled: 0x%x, CRC: 0x%x, Unknown2: 0x%x", addonName.c_str(), enabled, crc, unk2);
uint8 state = (enabled ? 2 : 1);
- *Target << uint8(state);
+ *target << uint8(state);
uint8 unk1 = (enabled ? 1 : 0);
- *Target << uint8(unk1);
+ *target << uint8(unk1);
if (unk1)
{
uint8 unk = (crc != 0x4c1c776d); // If addon is Standard addon CRC
- *Target << uint8(unk);
+ *target << uint8(unk);
if (unk)
{
unsigned char tdata[256] =
@@ -110,18 +110,18 @@ bool AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target)
0xC3, 0xFB, 0x1B, 0x8C, 0x29, 0xEF, 0x8E, 0xE5, 0x34, 0xCB, 0xD1, 0x2A, 0xCE, 0x79, 0xC3, 0x9A,
0x0D, 0x36, 0xEA, 0x01, 0xE0, 0xAA, 0x91, 0x20, 0x54, 0xF0, 0x72, 0xD8, 0x1E, 0xC7, 0x89, 0xD2
};
- Target->append(tdata, sizeof(tdata));
+ target->append(tdata, sizeof(tdata));
}
- *Target << uint32(0);
+ *target << uint32(0);
}
uint8 unk3 = (enabled ? 0 : 1);
- *Target << uint8(unk3);
+ *target << uint8(unk3);
if (unk3)
{
// String, 256 (null terminated?)
- *Target << uint8(0);
+ *target << uint8(0);
}
}
@@ -129,7 +129,7 @@ bool AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target)
AddOnPacked >> unk4;
uint32 count = 0;
- *Target << uint32(count);
+ *target << uint32(count);
if (AddOnPacked.rpos() != AddOnPacked.size())
sLog->outDebug(LOG_FILTER_NETWORKIO, "packet under read!");
diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp
index 71c5da9af2b..9955879d37a 100644
--- a/src/server/game/Handlers/BattleGroundHandler.cpp
+++ b/src/server/game/Handlers/BattleGroundHandler.cpp
@@ -154,7 +154,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
}
// check Deserter debuff
- if (!_player->CanJoinToBattleground())
+ if (!_player->CanJoinToBattleground(bg))
{
WorldPacket data;
sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS);
@@ -498,7 +498,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData)
if (action == 1 && ginfo.ArenaType == 0)
{
//if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue
- if (!_player->CanJoinToBattleground())
+ if (!_player->CanJoinToBattleground(bg))
{
//send bg command result to show nice message
WorldPacket data2;
@@ -540,6 +540,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData)
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, _player, queueSlot, STATUS_IN_PROGRESS, _player->GetBattlegroundQueueJoinTime(bgTypeId), bg->GetElapsedTime(), bg->GetArenaType());
_player->GetSession()->SendPacket(&data);
+
// remove battleground queue status from BGmgr
bgQueue.RemovePlayer(_player->GetGUID(), false);
// this is still needed here if battleground "jumping" shouldn't add deserter debuff
@@ -551,6 +552,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData)
_player->SetBattlegroundId(bg->GetInstanceID(), bgTypeId);
// set the destination team
_player->SetBGTeam(ginfo.Team);
+
// bg->HandleBeforeTeleportToBattleground(_player);
sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
// add only in HandleMoveWorldPortAck()
diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp
index 1105886813a..eef049fdb66 100644
--- a/src/server/game/Handlers/ChatHandler.cpp
+++ b/src/server/game/Handlers/ChatHandler.cpp
@@ -600,7 +600,7 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recvData)
return;
// Weird way to log stuff...
- sScriptMgr->OnPlayerChat(sender, CHAT_MSG_ADDON, LANG_ADDON, message);
+ sScriptMgr->OnPlayerChat(sender, uint32(CHAT_MSG_ADDON), uint32(LANG_ADDON), message);
}
// Disabled addon channel?
@@ -616,7 +616,7 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recvData)
return;
WorldPacket data;
- ChatHandler::FillMessageData(&data, this, type, LANG_ADDON, "", 0, message.c_str(), NULL);
+ ChatHandler::FillMessageData(&data, this, type, uint32(LANG_ADDON), "", 0, message.c_str(), NULL);
group->BroadcastAddonMessagePacket(&data, prefix, false);
break;
}
@@ -649,7 +649,7 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recvData)
break;
WorldPacket data;
- ChatHandler::FillMessageData(&data, this, type, LANG_ADDON, "", 0, message.c_str(), NULL, prefix.c_str());
+ ChatHandler::FillMessageData(&data, this, type, uint32(LANG_ADDON), "", 0, message.c_str(), NULL, prefix.c_str());
group->BroadcastAddonMessagePacket(&data, prefix, true, -1, group->GetMemberGroup(sender->GetGUID()));
break;
}
diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp
index 617270ac119..4887bfee38b 100644
--- a/src/server/game/Handlers/ItemHandler.cpp
+++ b/src/server/game/Handlers/ItemHandler.cpp
@@ -816,8 +816,6 @@ void WorldSession::SendListInventory(uint64 vendorGuid)
if (vendorItem->ExtendedCost == 0)
continue; // there's no price defined for currencies, only extendedcost is used
- uint32 precision = (currencyTemplate->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1;
-
++count;
itemsData << uint32(slot + 1); // client expects counting to start at 1
itemsData << uint32(0); // max durability
@@ -838,7 +836,7 @@ void WorldSession::SendListInventory(uint64 vendorGuid)
itemsData << uint32(0); // displayId
// if (!unk "enabler") data << uint32(something);
itemsData << int32(-1);
- itemsData << uint32(vendorItem->maxcount * precision);
+ itemsData << uint32(vendorItem->maxcount);
}
// else error
}
diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp
index ef8b39a926d..c2ff0d4b8e0 100644
--- a/src/server/game/Handlers/LFGHandler.cpp
+++ b/src/server/game/Handlers/LFGHandler.cpp
@@ -23,10 +23,10 @@
#include "WorldPacket.h"
#include "WorldSession.h"
-void BuildPlayerLockDungeonBlock(WorldPacket& data, LfgLockMap const& lock)
+void BuildPlayerLockDungeonBlock(WorldPacket& data, lfg::LfgLockMap const& lock)
{
data << uint32(lock.size()); // Size of lock dungeons
- for (LfgLockMap::const_iterator it = lock.begin(); it != lock.end(); ++it)
+ for (lfg::LfgLockMap::const_iterator it = lock.begin(); it != lock.end(); ++it)
{
data << uint32(it->first); // Dungeon entry (id + type)
data << uint32(it->second); // Lock status
@@ -35,10 +35,10 @@ void BuildPlayerLockDungeonBlock(WorldPacket& data, LfgLockMap const& lock)
}
}
-void BuildPartyLockDungeonBlock(WorldPacket& data, const LfgLockPartyMap& lockMap)
+void BuildPartyLockDungeonBlock(WorldPacket& data, lfg::LfgLockPartyMap const& lockMap)
{
data << uint8(lockMap.size());
- for (LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it)
+ for (lfg::LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it)
{
data << uint64(it->first); // Player guid
BuildPlayerLockDungeonBlock(data, it->second);
@@ -47,7 +47,7 @@ void BuildPartyLockDungeonBlock(WorldPacket& data, const LfgLockPartyMap& lockMa
void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData)
{
- if (!sLFGMgr->isOptionEnabled(LFG_OPTION_ENABLE_DUNGEON_FINDER | LFG_OPTION_ENABLE_RAID_BROWSER) ||
+ if (!sLFGMgr->isOptionEnabled(lfg::LFG_OPTION_ENABLE_DUNGEON_FINDER | lfg::LFG_OPTION_ENABLE_RAID_BROWSER) ||
(GetPlayer()->GetGroup() && GetPlayer()->GetGroup()->GetLeaderGUID() != GetPlayer()->GetGUID() &&
(GetPlayer()->GetGroup()->GetMembersCount() == MAXGROUPSIZE || !GetPlayer()->GetGroup()->isLFGGroup())))
{
@@ -68,7 +68,7 @@ void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData)
return;
}
- LfgDungeonSet newDungeons;
+ lfg::LfgDungeonSet newDungeons;
for (int8 i = 0; i < numDungeons; ++i)
{
uint32 dungeon;
@@ -169,21 +169,12 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData*
GetPlayerInfo().c_str());
// Get Random dungeons that can be done at a certain level and expansion
- LfgDungeonSet randomDungeons;
uint8 level = GetPlayer()->getLevel();
- uint8 expansion = GetPlayer()->GetSession()->Expansion();
-
- LFGDungeonContainer& LfgDungeons = sLFGMgr->GetLFGDungeonMap();
- for (LFGDungeonContainer::const_iterator itr = LfgDungeons.begin(); itr != LfgDungeons.end(); ++itr)
- {
- LFGDungeonData const& dungeon = itr->second;
- if ((dungeon.type == LFG_TYPE_RANDOM || (dungeon.seasonal && sLFGMgr->IsSeasonActive(dungeon.id)))
- && dungeon.expansion <= expansion && dungeon.minlevel <= level && level <= dungeon.maxlevel)
- randomDungeons.insert(dungeon.Entry());
- }
+ lfg::LfgDungeonSet const& randomDungeons =
+ sLFGMgr->GetRandomAndSeasonalDungeons(level, GetPlayer()->GetSession()->Expansion());
// Get player locked Dungeons
- LfgLockMap const& lock = sLFGMgr->GetLockedDungeons(guid);
+ lfg::LfgLockMap const& lock = sLFGMgr->GetLockedDungeons(guid);
uint32 rsize = uint32(randomDungeons.size());
uint32 lsize = uint32(lock.size());
@@ -191,10 +182,10 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData*
WorldPacket data(SMSG_LFG_PLAYER_INFO, 1 + rsize * (4 + 1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4) + 4 + lsize * (1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4));
data << uint8(randomDungeons.size()); // Random Dungeon count
- for (LfgDungeonSet::const_iterator it = randomDungeons.begin(); it != randomDungeons.end(); ++it)
+ for (lfg::LfgDungeonSet::const_iterator it = randomDungeons.begin(); it != randomDungeons.end(); ++it)
{
data << uint32(*it); // Dungeon Entry (id + type)
- LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(*it, level);
+ lfg::LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(*it, level);
Quest const* quest = NULL;
bool done = false;
if (reward)
@@ -252,7 +243,7 @@ void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket& /*recvData*
return;
// Get the locked dungeons of the other party members
- LfgLockPartyMap lockMap;
+ lfg::LfgLockPartyMap lockMap;
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player* plrg = itr->getSource();
@@ -267,7 +258,7 @@ void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket& /*recvData*
}
uint32 size = 0;
- for (LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it)
+ for (lfg::LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it)
size += 8 + 4 + uint32(it->second.size()) * (4 + 4 + 4 + 4);
sLog->outDebug(LOG_FILTER_LFG, "SMSG_LFG_PARTY_INFO %s", GetPlayerInfo().c_str());
@@ -299,7 +290,7 @@ void WorldSession::HandleLfgGetStatus(WorldPacket& /*recvData*/)
sLog->outDebug(LOG_FILTER_LFG, "CMSG_LFG_GET_STATUS %s", GetPlayerInfo().c_str());
uint64 guid = GetPlayer()->GetGUID();
- LfgUpdateData updateData = sLFGMgr->GetLfgStatus(guid);
+ lfg::LfgUpdateData updateData = sLFGMgr->GetLfgStatus(guid);
if (GetPlayer()->GetGroup())
{
@@ -315,19 +306,19 @@ void WorldSession::HandleLfgGetStatus(WorldPacket& /*recvData*/)
}
}
-void WorldSession::SendLfgUpdatePlayer(LfgUpdateData const& updateData)
+void WorldSession::SendLfgUpdatePlayer(lfg::LfgUpdateData const& updateData)
{
bool queued = false;
uint8 size = uint8(updateData.dungeons.size());
switch (updateData.updateType)
{
- case LFG_UPDATETYPE_JOIN_QUEUE:
- case LFG_UPDATETYPE_ADDED_TO_QUEUE:
+ case lfg::LFG_UPDATETYPE_JOIN_QUEUE:
+ case lfg::LFG_UPDATETYPE_ADDED_TO_QUEUE:
queued = true;
break;
- case LFG_UPDATETYPE_UPDATE_STATUS:
- queued = updateData.state == LFG_STATE_QUEUED;
+ case lfg::LFG_UPDATETYPE_UPDATE_STATUS:
+ queued = updateData.state == lfg::LFG_STATE_QUEUED;
break;
default:
break;
@@ -345,14 +336,14 @@ void WorldSession::SendLfgUpdatePlayer(LfgUpdateData const& updateData)
data << uint8(0); // unk - Always 0
data << uint8(size);
- for (LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it)
+ for (lfg::LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it)
data << uint32(*it);
data << updateData.comment;
}
SendPacket(&data);
}
-void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData)
+void WorldSession::SendLfgUpdateParty(const lfg::LfgUpdateData& updateData)
{
bool join = false;
bool queued = false;
@@ -360,15 +351,15 @@ void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData)
switch (updateData.updateType)
{
- case LFG_UPDATETYPE_ADDED_TO_QUEUE: // Rolecheck Success
+ case lfg::LFG_UPDATETYPE_ADDED_TO_QUEUE: // Rolecheck Success
queued = true;
// no break on purpose
- case LFG_UPDATETYPE_PROPOSAL_BEGIN:
+ case lfg::LFG_UPDATETYPE_PROPOSAL_BEGIN:
join = true;
break;
- case LFG_UPDATETYPE_UPDATE_STATUS:
- join = updateData.state != LFG_STATE_ROLECHECK && updateData.state != LFG_STATE_NONE;
- queued = updateData.state == LFG_STATE_QUEUED;
+ case lfg::LFG_UPDATETYPE_UPDATE_STATUS:
+ join = updateData.state != lfg::LFG_STATE_ROLECHECK && updateData.state != lfg::LFG_STATE_NONE;
+ queued = updateData.state == lfg::LFG_STATE_QUEUED;
break;
default:
break;
@@ -389,7 +380,7 @@ void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData)
data << uint8(0); // unk - Always 0
data << uint8(size);
- for (LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it)
+ for (lfg::LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it)
data << uint32(*it);
data << updateData.comment;
}
@@ -408,9 +399,9 @@ void WorldSession::SendLfgRoleChosen(uint64 guid, uint8 roles)
SendPacket(&data);
}
-void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck)
+void WorldSession::SendLfgRoleCheckUpdate(lfg::LfgRoleCheck const& roleCheck)
{
- LfgDungeonSet dungeons;
+ lfg::LfgDungeonSet dungeons;
if (roleCheck.rDungeonId)
dungeons.insert(roleCheck.rDungeonId);
else
@@ -420,16 +411,11 @@ void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck)
WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + dungeons.size() * 4 + 1 + roleCheck.roles.size() * (8 + 1 + 4 + 1));
data << uint32(roleCheck.state); // Check result
- data << uint8(roleCheck.state == LFG_ROLECHECK_INITIALITING);
+ data << uint8(roleCheck.state == lfg::LFG_ROLECHECK_INITIALITING);
data << uint8(dungeons.size()); // Number of dungeons
if (!dungeons.empty())
- {
- for (LfgDungeonSet::iterator it = dungeons.begin(); it != dungeons.end(); ++it)
- {
- LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(*it);
- data << uint32(dungeon ? dungeon->Entry() : 0); // Dungeon
- }
- }
+ for (lfg::LfgDungeonSet::iterator it = dungeons.begin(); it != dungeons.end(); ++it)
+ data << uint32(sLFGMgr->GetLFGDungeonEntry(*it)); // Dungeon
data << uint8(roleCheck.roles.size()); // Players in group
if (!roleCheck.roles.empty())
@@ -443,7 +429,7 @@ void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck)
Player* player = ObjectAccessor::FindPlayer(guid);
data << uint8(player ? player->getLevel() : 0); // Level
- for (LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it)
+ for (lfg::LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it)
{
if (it->first == roleCheck.leader)
continue;
@@ -460,10 +446,10 @@ void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck)
SendPacket(&data);
}
-void WorldSession::SendLfgJoinResult(LfgJoinResultData const& joinData)
+void WorldSession::SendLfgJoinResult(lfg::LfgJoinResultData const& joinData)
{
uint32 size = 0;
- for (LfgLockPartyMap::const_iterator it = joinData.lockmap.begin(); it != joinData.lockmap.end(); ++it)
+ for (lfg::LfgLockPartyMap::const_iterator it = joinData.lockmap.begin(); it != joinData.lockmap.end(); ++it)
size += 8 + 4 + uint32(it->second.size()) * (4 + 4 + 4 + 4);
sLog->outDebug(LOG_FILTER_LFG, "SMSG_LFG_JOIN_RESULT %s checkResult: %u checkValue: %u",
@@ -477,7 +463,7 @@ void WorldSession::SendLfgJoinResult(LfgJoinResultData const& joinData)
SendPacket(&data);
}
-void WorldSession::SendLfgQueueStatus(LfgQueueStatusData const& queueData)
+void WorldSession::SendLfgQueueStatus(lfg::LfgQueueStatusData const& queueData)
{
sLog->outDebug(LOG_FILTER_LFG, "SMSG_LFG_QUEUE_STATUS %s dungeon: %u, waitTime: %d, "
"avgWaitTime: %d, waitTimeTanks: %d, waitTimeHealer: %d, waitTimeDps: %d, "
@@ -500,7 +486,7 @@ void WorldSession::SendLfgQueueStatus(LfgQueueStatusData const& queueData)
SendPacket(&data);
}
-void WorldSession::SendLfgPlayerReward(LfgPlayerRewardData const& rewardData)
+void WorldSession::SendLfgPlayerReward(lfg::LfgPlayerRewardData const& rewardData)
{
if (!rewardData.rdungeonEntry || !rewardData.sdungeonEntry || !rewardData.quest)
return;
@@ -534,43 +520,43 @@ void WorldSession::SendLfgPlayerReward(LfgPlayerRewardData const& rewardData)
SendPacket(&data);
}
-void WorldSession::SendLfgBootProposalUpdate(LfgPlayerBoot const& boot)
+void WorldSession::SendLfgBootProposalUpdate(lfg::LfgPlayerBoot const& boot)
{
uint64 guid = GetPlayer()->GetGUID();
- LfgAnswer playerVote = boot.votes.find(guid)->second;
+ lfg::LfgAnswer playerVote = boot.votes.find(guid)->second;
uint8 votesNum = 0;
uint8 agreeNum = 0;
uint32 secsleft = uint8((boot.cancelTime - time(NULL)) / 1000);
- for (LfgAnswerContainer::const_iterator it = boot.votes.begin(); it != boot.votes.end(); ++it)
+ for (lfg::LfgAnswerContainer::const_iterator it = boot.votes.begin(); it != boot.votes.end(); ++it)
{
- if (it->second != LFG_ANSWER_PENDING)
+ if (it->second != lfg::LFG_ANSWER_PENDING)
{
++votesNum;
- if (it->second == LFG_ANSWER_AGREE)
+ if (it->second == lfg::LFG_ANSWER_AGREE)
++agreeNum;
}
}
sLog->outDebug(LOG_FILTER_LFG, "SMSG_LFG_BOOT_PROPOSAL_UPDATE %s inProgress: %u - "
"didVote: %u - agree: %u - victim: %u votes: %u - agrees: %u - left: %u - "
"needed: %u - reason %s",
- GetPlayerInfo().c_str(), uint8(boot.inProgress), uint8(playerVote != LFG_ANSWER_PENDING),
- uint8(playerVote == LFG_ANSWER_AGREE), GUID_LOPART(boot.victim), votesNum, agreeNum,
- secsleft, LFG_GROUP_KICK_VOTES_NEEDED, boot.reason.c_str());
- WorldPacket data(SMSG_LFG_BOOT_PROPOSAL_UPDATE, 1 + 1 + 1 + 8 + 4 + 4 + 4 + 4 + boot.reason.length());
+ GetPlayerInfo().c_str(), uint8(boot.inProgress), uint8(playerVote != lfg::LFG_ANSWER_PENDING),
+ uint8(playerVote == lfg::LFG_ANSWER_AGREE), GUID_LOPART(boot.victim), votesNum, agreeNum,
+ secsleft, lfg::LFG_GROUP_KICK_VOTES_NEEDED, boot.reason.c_str());
+ WorldPacket data(SMSG_LFG_BOOT_PROPOSAL_UPDATE, 1 + 1 + 1 + 1 + 8 + 4 + 4 + 4 + 4 + boot.reason.length());
data << uint8(boot.inProgress); // Vote in progress
- data << uint8(playerVote != LFG_ANSWER_PENDING); // Did Vote
- data << uint8(playerVote == LFG_ANSWER_AGREE); // Agree
+ data << uint8(playerVote != lfg::LFG_ANSWER_PENDING); // Did Vote
+ data << uint8(playerVote == lfg::LFG_ANSWER_AGREE); // Agree
data << uint8(0); // Unknown 4.2.2
data << uint64(boot.victim); // Victim GUID
data << uint32(votesNum); // Total Votes
data << uint32(agreeNum); // Agree Count
data << uint32(secsleft); // Time Left
- data << uint32(LFG_GROUP_KICK_VOTES_NEEDED); // Needed Votes
+ data << uint32(lfg::LFG_GROUP_KICK_VOTES_NEEDED); // Needed Votes
data << boot.reason.c_str(); // Kick reason
SendPacket(&data);
}
-void WorldSession::SendLfgUpdateProposal(LfgProposal const& proposal)
+void WorldSession::SendLfgUpdateProposal(lfg::LfgProposal const& proposal)
{
uint64 guid = GetPlayer()->GetGUID();
uint64 gguid = proposal.players.find(guid)->second.group;
@@ -583,13 +569,12 @@ void WorldSession::SendLfgUpdateProposal(LfgProposal const& proposal)
// show random dungeon if player selected random dungeon and it's not lfg group
if (!silent)
{
- LfgDungeonSet const& playerDungeons = sLFGMgr->GetSelectedDungeons(guid);
+ lfg::LfgDungeonSet const& playerDungeons = sLFGMgr->GetSelectedDungeons(guid);
if (playerDungeons.find(proposal.dungeonId) == playerDungeons.end())
dungeonEntry = (*playerDungeons.begin());
}
- if (LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(dungeonEntry))
- dungeonEntry = dungeon->Entry();
+ dungeonEntry = sLFGMgr->GetLFGDungeonEntry(dungeonEntry);
WorldPacket data(SMSG_LFG_PROPOSAL_UPDATE, 4 + 1 + 4 + 4 + 1 + 1 + proposal.players.size() * (4 + 1 + 1 + 1 + 1 +1));
data << uint32(dungeonEntry); // Dungeon
@@ -599,9 +584,9 @@ void WorldSession::SendLfgUpdateProposal(LfgProposal const& proposal)
data << uint8(silent); // Show proposal window
data << uint8(proposal.players.size()); // Group size
- for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
+ for (lfg::LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
{
- LfgProposalPlayer const& player = it->second;
+ lfg::LfgProposalPlayer const& player = it->second;
data << uint32(player.role); // Role
data << uint8(it->first == guid); // Self player
if (!player.group) // Player not it a group
@@ -614,8 +599,8 @@ void WorldSession::SendLfgUpdateProposal(LfgProposal const& proposal)
data << uint8(player.group == proposal.group); // In dungeon (silent)
data << uint8(player.group == gguid); // Same Group than player
}
- data << uint8(player.accept != LFG_ANSWER_PENDING);// Answered
- data << uint8(player.accept == LFG_ANSWER_AGREE); // Accepted
+ data << uint8(player.accept != lfg::LFG_ANSWER_PENDING);// Answered
+ data << uint8(player.accept == lfg::LFG_ANSWER_AGREE); // Accepted
}
SendPacket(&data);
}
diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp
index c21d16d3600..48f11c596d2 100644
--- a/src/server/game/Handlers/MailHandler.cpp
+++ b/src/server/game/Handlers/MailHandler.cpp
@@ -570,13 +570,18 @@ void WorldSession::HandleMailTakeMoney(WorldPacket& recvData)
return;
}
- player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK);
+ if (!player->ModifyMoney(m->money, false))
+ {
+ player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_TOO_MUCH_GOLD);
+ return;
+ }
- player->ModifyMoney(money);
m->money = 0;
m->state = MAIL_STATE_CHANGED;
player->m_mailsUpdated = true;
+ player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK);
+
// save money and mail to prevent cheating
SQLTransaction trans = CharacterDatabase.BeginTransaction();
player->SaveGoldToDB(trans);
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index 579b4f38a5c..e08a7a30699 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -396,7 +396,7 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPacket& /*recvData*/)
//instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in worldserver.conf
if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->isInFlight() ||
- GetSecurity() >= AccountTypes(sWorld->getIntConfig(CONFIG_INSTANT_LOGOUT)))
+ HasPermission(RBAC_PERM_INSTANT_LOGOUT))
{
WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4);
data << uint32(reason);
@@ -975,7 +975,7 @@ void WorldSession::HandleUpdateAccountData(WorldPacket& recvData)
dest.resize(decompressedSize);
uLongf realSize = decompressedSize;
- if (uncompress(const_cast<uint8*>(dest.contents()), &realSize, const_cast<uint8*>(recvData.contents() + recvData.rpos()), recvData.size() - recvData.rpos()) != Z_OK)
+ if (uncompress(dest.contents(), &realSize, recvData.contents() + recvData.rpos(), recvData.size() - recvData.rpos()) != Z_OK)
{
recvData.rfinish(); // unnneded warning spam in this case
sLog->outError(LOG_FILTER_NETWORKIO, "UAD: Failed to decompress account data");
@@ -1016,7 +1016,7 @@ void WorldSession::HandleRequestAccountData(WorldPacket& recvData)
ByteBuffer dest;
dest.resize(destSize);
- if (size && compress(const_cast<uint8*>(dest.contents()), &destSize, (uint8*)adata->Data.c_str(), size) != Z_OK)
+ if (size && compress(dest.contents(), &destSize, (uint8 const*)adata->Data.c_str(), size) != Z_OK)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "RAD: Failed to compress account data");
return;
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index 3d2e84c57e8..b2971abaeba 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -126,7 +126,7 @@ void WorldSession::HandleMoveWorldportAckOpcode()
{
// short preparations to continue flight
FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top());
- flight->Initialize(*GetPlayer());
+ flight->Initialize(GetPlayer());
return;
}
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 340b5a3ddc1..f7f540a7be5 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -203,13 +203,6 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid
if (!owner->IsValidAttackTarget(TargetUnit))
return;
- // Not let attack through obstructions
- if (sWorld->getBoolConfig(CONFIG_PET_LOS))
- {
- if (!pet->IsWithinLOSInMap(TargetUnit))
- return;
- }
-
pet->ClearUnitState(UNIT_STATE_FOLLOW);
// This is true if pet has no target or has target but targets differs.
if (pet->getVictim() != TargetUnit || (pet->getVictim() == TargetUnit && !pet->GetCharmInfo()->IsCommandAttack()))
diff --git a/src/server/game/Handlers/TicketHandler.cpp b/src/server/game/Handlers/TicketHandler.cpp
index 4463613a97b..2da2735a3f9 100644
--- a/src/server/game/Handlers/TicketHandler.cpp
+++ b/src/server/game/Handlers/TicketHandler.cpp
@@ -69,7 +69,7 @@ void WorldSession::HandleGMTicketCreateOpcode(WorldPacket& recvData)
dest.resize(decompressedSize);
uLongf realSize = decompressedSize;
- if (uncompress(const_cast<uint8*>(dest.contents()), &realSize, const_cast<uint8*>(recvData.contents() + pos), recvData.size() - pos) == Z_OK)
+ if (uncompress(dest.contents(), &realSize, recvData.contents() + pos, recvData.size() - pos) == Z_OK)
{
dest >> chatLog;
ticket->SetChatLog(times, chatLog);
diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp
index 4545a8df353..b25f0a301a9 100644
--- a/src/server/game/Handlers/TradeHandler.cpp
+++ b/src/server/game/Handlers/TradeHandler.cpp
@@ -353,6 +353,20 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
return;
}
+ if (_player->GetMoney() >= uint64(MAX_MONEY_AMOUNT) - his_trade->GetMoney())
+ {
+ _player->SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL);
+ my_trade->SetAccepted(false, true);
+ return;
+ }
+
+ if (trader->GetMoney() >= uint64(MAX_MONEY_AMOUNT) - my_trade->GetMoney())
+ {
+ trader->SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL);
+ his_trade->SetAccepted(false, true);
+ return;
+ }
+
// not accept if some items now can't be trade (cheating)
for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i)
{
@@ -363,6 +377,7 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
return;
}
+
if (item->IsBindedNotWith(trader))
{
SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE);
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index 0a66c781c8f..94aea40f511 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -26,6 +26,7 @@
#include "SpellInfo.h"
#include "Group.h"
#include "Player.h"
+#include "Containers.h"
static Rates const qualityToRate[MAX_ITEM_QUALITY] =
{
@@ -51,10 +52,26 @@ LootStore LootTemplates_Reference("reference_loot_template", "reference
LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true);
LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)", false);
+struct NotMatchingLootMode : public std::unary_function<LootStoreItem*, bool>
+{
+ explicit NotMatchingLootMode(uint16 lootMode) : _lootMode(lootMode) { }
+
+ bool operator()(LootStoreItem* item) const
+ {
+ return !(item->lootmode & _lootMode);
+ }
+
+private:
+ uint16 _lootMode;
+};
+
class LootTemplate::LootGroup // A set of loot definitions for items (refs are not allowed)
{
public:
- void AddEntry(LootStoreItem& item); // Adds an entry to the group (at loading stage)
+ LootGroup() { }
+ ~LootGroup();
+
+ void AddEntry(LootStoreItem* item); // Adds an entry to the group (at loading stage)
bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry
bool HasQuestDropForPlayer(Player const* player) const;
// The same for active quests of the player
@@ -72,7 +89,11 @@ class LootTemplate::LootGroup // A set of loot def
LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB
LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance
- LootStoreItem const* Roll() const; // Rolls an item from the group, returns NULL if all miss their chances
+ LootStoreItem const* Roll(uint16 lootMode) const; // Rolls an item from the group, returns NULL if all miss their chances
+
+ // This class must never be copied - storing pointers
+ LootGroup(LootGroup const&);
+ LootGroup& operator=(LootGroup const&);
};
//Remove all data and free all memory
@@ -126,10 +147,13 @@ uint32 LootStore::LoadLootTable()
continue; // error already printed to log/console.
}
- LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, lootmode, group, mincountOrRef, maxcount);
+ LootStoreItem* storeitem = new LootStoreItem(item, chanceOrQuestChance, lootmode, group, mincountOrRef, maxcount);
- if (!storeitem.IsValid(*this, entry)) // Validity checks
+ if (!storeitem->IsValid(*this, entry)) // Validity checks
+ {
+ delete storeitem;
continue;
+ }
// Looking for the template of the entry
// often entries are put together
@@ -139,7 +163,7 @@ uint32 LootStore::LoadLootTable()
tab = m_LootTemplates.find(entry);
if (tab == m_LootTemplates.end())
{
- std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate));
+ std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate()));
tab = pr.first;
}
}
@@ -182,7 +206,7 @@ void LootStore::ResetConditions()
for (LootTemplateMap::iterator itr = m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr)
{
ConditionList empty;
- (*itr).second->CopyConditions(empty);
+ itr->second->CopyConditions(empty);
}
}
@@ -327,7 +351,6 @@ LootItem::LootItem(LootStoreItem const& li)
needs_quest = li.needs_quest;
- count = urand(li.mincountOrRef, li.maxcount); // constructor called for mincountOrRef > 0 only
randomSuffix = GenerateEnchSuffixFactor(itemid);
randomPropertyId = Item::GenerateItemRandomPropertyId(itemid);
is_looted = 0;
@@ -376,26 +399,30 @@ void LootItem::AddAllowedLooter(const Player* player)
//
// Inserts the item into the loot (called by LootTemplate processors)
-void Loot::AddItem(LootStoreItem const & item)
+void Loot::AddItem(LootStoreItem const& item)
{
- if (item.needs_quest) // Quest drop
- {
- if (quest_items.size() < MAX_NR_QUEST_ITEMS)
- quest_items.push_back(LootItem(item));
- }
- else if (items.size() < MAX_NR_LOOT_ITEMS) // Non-quest drop
+ ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid);
+ if (!proto)
+ return;
+
+ uint32 count = urand(item.mincountOrRef, item.maxcount);
+ uint32 stacks = count / proto->GetMaxStackSize() + (count % proto->GetMaxStackSize() ? 1 : 0);
+
+ std::vector<LootItem>& lootItems = item.needs_quest ? quest_items : items;
+ uint32 limit = item.needs_quest ? MAX_NR_QUEST_ITEMS : MAX_NR_LOOT_ITEMS;
+
+ for (uint32 i = 0; i < stacks && lootItems.size() < limit; ++i)
{
- items.push_back(LootItem(item));
+ LootItem generatedLoot(item);
+ generatedLoot.count = std::min(count, proto->GetMaxStackSize());
+ lootItems.push_back(generatedLoot);
+ count -= proto->GetMaxStackSize();
// non-conditional one-player only items are counted here,
// free for all items are counted in FillFFALoot(),
// non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
- if (item.conditions.empty())
- {
- ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid);
- if (!proto || (proto->Flags & ITEM_PROTO_FLAG_PARTY_LOOT) == 0)
- ++unlootedCount;
- }
+ if (!item.needs_quest && item.conditions.empty() && !(proto->Flags & ITEM_PROTO_FLAG_PARTY_LOOT))
+ ++unlootedCount;
}
}
@@ -1028,34 +1055,56 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
// --------- LootTemplate::LootGroup ---------
//
+LootTemplate::LootGroup::~LootGroup()
+{
+ while (!ExplicitlyChanced.empty())
+ {
+ delete ExplicitlyChanced.back();
+ ExplicitlyChanced.pop_back();
+ }
+
+ while (!EqualChanced.empty())
+ {
+ delete EqualChanced.back();
+ EqualChanced.pop_back();
+ }
+}
+
// Adds an entry to the group (at loading stage)
-void LootTemplate::LootGroup::AddEntry(LootStoreItem& item)
+void LootTemplate::LootGroup::AddEntry(LootStoreItem* item)
{
- if (item.chance != 0)
+ if (item->chance != 0)
ExplicitlyChanced.push_back(item);
else
EqualChanced.push_back(item);
}
// Rolls an item from the group, returns NULL if all miss their chances
-LootStoreItem const* LootTemplate::LootGroup::Roll() const
+LootStoreItem const* LootTemplate::LootGroup::Roll(uint16 lootMode) const
{
- if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked
+ LootStoreItemList possibleLoot = ExplicitlyChanced;
+ possibleLoot.remove_if(NotMatchingLootMode(lootMode));
+
+ if (!possibleLoot.empty()) // First explicitly chanced entries are checked
{
- float Roll = (float)rand_chance();
+ float roll = (float)rand_chance();
- for (uint32 i = 0; i < ExplicitlyChanced.size(); ++i) // check each explicitly chanced entry in the template and modify its chance based on quality.
+ for (LootStoreItemList::const_iterator itr = possibleLoot.begin(); itr != possibleLoot.end(); ++itr) // check each explicitly chanced entry in the template and modify its chance based on quality.
{
- if (ExplicitlyChanced[i].chance >= 100.0f)
- return &ExplicitlyChanced[i];
+ LootStoreItem* item = *itr;
+ if (item->chance >= 100.0f)
+ return item;
- Roll -= ExplicitlyChanced[i].chance;
- if (Roll < 0)
- return &ExplicitlyChanced[i];
+ roll -= item->chance;
+ if (roll < 0)
+ return item;
}
}
- if (!EqualChanced.empty()) // If nothing selected yet - an item is taken from equal-chanced part
- return &EqualChanced[irand(0, EqualChanced.size()-1)];
+
+ possibleLoot = EqualChanced;
+ possibleLoot.remove_if(NotMatchingLootMode(lootMode));
+ if (!possibleLoot.empty()) // If nothing selected yet - an item is taken from equal-chanced part
+ return Trinity::Containers::SelectRandomContainerElement(possibleLoot);
return NULL; // Empty drop from the group
}
@@ -1063,12 +1112,14 @@ LootStoreItem const* LootTemplate::LootGroup::Roll() const
// True if group includes at least 1 quest drop entry
bool LootTemplate::LootGroup::HasQuestDrop() const
{
- for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
- if (i->needs_quest)
+ for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
+ if ((*i)->needs_quest)
return true;
- for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i)
- if (i->needs_quest)
+
+ for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
+ if ((*i)->needs_quest)
return true;
+
return false;
}
@@ -1076,111 +1127,30 @@ bool LootTemplate::LootGroup::HasQuestDrop() const
bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const* player) const
{
for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
- if (player->HasQuestForItem(i->itemid))
+ if (player->HasQuestForItem((*i)->itemid))
return true;
+
for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
- if (player->HasQuestForItem(i->itemid))
+ if (player->HasQuestForItem((*i)->itemid))
return true;
+
return false;
}
void LootTemplate::LootGroup::CopyConditions(ConditionList /*conditions*/)
{
for (LootStoreItemList::iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
- {
- i->conditions.clear();
- }
+ (*i)->conditions.clear();
+
for (LootStoreItemList::iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
- {
- i->conditions.clear();
- }
+ (*i)->conditions.clear();
}
// Rolls an item from the group (if any takes its chance) and adds the item to the loot
void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode) const
{
- // build up list of possible drops
- LootStoreItemList EqualPossibleDrops = EqualChanced;
- LootStoreItemList ExplicitPossibleDrops = ExplicitlyChanced;
-
- uint8 uiAttemptCount = 0;
- const uint8 uiMaxAttempts = ExplicitlyChanced.size() + EqualChanced.size();
-
- while (!ExplicitPossibleDrops.empty() || !EqualPossibleDrops.empty())
- {
- if (uiAttemptCount == uiMaxAttempts) // already tried rolling too many times, just abort
- return;
-
- LootStoreItem* item = NULL;
-
- // begin rolling (normally called via Roll())
- LootStoreItemList::iterator itr;
- uint8 itemSource = 0;
- if (!ExplicitPossibleDrops.empty()) // First explicitly chanced entries are checked
- {
- itemSource = 1;
- float Roll = (float)rand_chance();
- // check each explicitly chanced entry in the template and modify its chance based on quality
- for (itr = ExplicitPossibleDrops.begin(); itr != ExplicitPossibleDrops.end(); itr = ExplicitPossibleDrops.erase(itr))
- {
- if (itr->chance >= 100.0f)
- {
- item = &*itr;
- break;
- }
-
- Roll -= itr->chance;
- if (Roll < 0)
- {
- item = &*itr;
- break;
- }
- }
- }
- if (item == NULL && !EqualPossibleDrops.empty()) // If nothing selected yet - an item is taken from equal-chanced part
- {
- itemSource = 2;
- itr = EqualPossibleDrops.begin();
- std::advance(itr, irand(0, EqualPossibleDrops.size()-1));
- item = &*itr;
- }
- // finish rolling
-
- ++uiAttemptCount;
-
- if (item != NULL && item->lootmode & lootMode) // only add this item if roll succeeds and the mode matches
- {
- bool duplicate = false;
- if (ItemTemplate const* _proto = sObjectMgr->GetItemTemplate(item->itemid))
- {
- uint8 _item_counter = 0;
- for (LootItemList::const_iterator _item = loot.items.begin(); _item != loot.items.end(); ++_item)
- if (_item->itemid == item->itemid) // search through the items that have already dropped
- {
- ++_item_counter;
- if (_proto->InventoryType == 0 && _item_counter == 3) // Non-equippable items are limited to 3 drops
- duplicate = true;
- else if (_proto->InventoryType != 0 && _item_counter == 1) // Equippable item are limited to 1 drop
- duplicate = true;
- }
- }
- if (duplicate) // if item->itemid is a duplicate, remove it
- switch (itemSource)
- {
- case 1: // item came from ExplicitPossibleDrops
- ExplicitPossibleDrops.erase(itr);
- break;
- case 2: // item came from EqualPossibleDrops
- EqualPossibleDrops.erase(itr);
- break;
- }
- else // otherwise, add the item and exit the function
- {
- loot.AddItem(*item);
- return;
- }
- }
- }
+ if (LootStoreItem const* item = Roll(lootMode))
+ loot.AddItem(*item);
}
// Overall chance for the group without equal chanced items
@@ -1189,8 +1159,8 @@ float LootTemplate::LootGroup::RawTotalChance() const
float result = 0;
for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
- if (!i->needs_quest)
- result += i->chance;
+ if (!(*i)->needs_quest)
+ result += (*i)->chance;
return result;
}
@@ -1210,37 +1180,35 @@ void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint
{
float chance = RawTotalChance();
if (chance > 101.0f) // TODO: replace with 100% when DBs will be ready
- {
sLog->outError(LOG_FILTER_SQL, "Table '%s' entry %u group %d has total chance > 100%% (%f)", lootstore.GetName(), id, group_id, chance);
- }
if (chance >= 100.0f && !EqualChanced.empty())
- {
sLog->outError(LOG_FILTER_SQL, "Table '%s' entry %u group %d has items with chance=0%% but group total chance >= 100%% (%f)", lootstore.GetName(), id, group_id, chance);
- }
}
void LootTemplate::LootGroup::CheckLootRefs(LootTemplateMap const& /*store*/, LootIdSet* ref_set) const
{
- for (LootStoreItemList::const_iterator ieItr=ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr)
+ for (LootStoreItemList::const_iterator ieItr = ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr)
{
- if (ieItr->mincountOrRef < 0)
+ LootStoreItem* item = *ieItr;
+ if (item->mincountOrRef < 0)
{
- if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
- LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
+ if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef))
+ LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef);
else if (ref_set)
- ref_set->erase(-ieItr->mincountOrRef);
+ ref_set->erase(-item->mincountOrRef);
}
}
- for (LootStoreItemList::const_iterator ieItr=EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr)
+ for (LootStoreItemList::const_iterator ieItr = EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr)
{
- if (ieItr->mincountOrRef < 0)
+ LootStoreItem* item = *ieItr;
+ if (item->mincountOrRef < 0)
{
- if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
- LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
+ if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef))
+ LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef);
else if (ref_set)
- ref_set->erase(-ieItr->mincountOrRef);
+ ref_set->erase(-item->mincountOrRef);
}
}
}
@@ -1249,14 +1217,30 @@ void LootTemplate::LootGroup::CheckLootRefs(LootTemplateMap const& /*store*/, Lo
// --------- LootTemplate ---------
//
+LootTemplate::~LootTemplate()
+{
+ while (!Entries.empty())
+ {
+ delete Entries.back();
+ Entries.pop_back();
+ }
+
+ for (size_t i = 0; i < Groups.size(); ++i)
+ delete Groups[i];
+ Groups.clear();
+}
+
// Adds an entry to the group (at loading stage)
-void LootTemplate::AddEntry(LootStoreItem& item)
+void LootTemplate::AddEntry(LootStoreItem* item)
{
- if (item.group > 0 && item.mincountOrRef > 0) // Group
+ if (item->group > 0 && item->mincountOrRef > 0) // Group
{
- if (item.group >= Groups.size())
- Groups.resize(item.group); // Adds new group the the loot template if needed
- Groups[item.group-1].AddEntry(item); // Adds new entry to the group
+ if (item->group >= Groups.size())
+ Groups.resize(item->group, NULL); // Adds new group the the loot template if needed
+ if (!Groups[item->group - 1])
+ Groups[item->group - 1] = new LootGroup();
+
+ Groups[item->group-1]->AddEntry(item); // Adds new entry to the group
}
else // Non-grouped entries and references are stored together
Entries.push_back(item);
@@ -1265,10 +1249,11 @@ void LootTemplate::AddEntry(LootStoreItem& item)
void LootTemplate::CopyConditions(ConditionList conditions)
{
for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i)
- i->conditions.clear();
+ (*i)->conditions.clear();
for (LootGroups::iterator i = Groups.begin(); i != Groups.end(); ++i)
- i->CopyConditions(conditions);
+ if (LootGroup* group = *i)
+ group->CopyConditions(conditions);
}
void LootTemplate::CopyConditions(LootItem* li) const
@@ -1276,10 +1261,11 @@ void LootTemplate::CopyConditions(LootItem* li) const
// Copies the conditions list from a template item to a LootItem
for (LootStoreItemList::const_iterator _iter = Entries.begin(); _iter != Entries.end(); ++_iter)
{
- if (_iter->itemid != li->itemid)
+ LootStoreItem* item = *_iter;
+ if (item->itemid != li->itemid)
continue;
- li->conditions = _iter->conditions;
+ li->conditions = item->conditions;
break;
}
}
@@ -1292,54 +1278,42 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId
if (groupId > Groups.size())
return; // Error message already printed at loading stage
- Groups[groupId-1].Process(loot, lootMode);
+ if (!Groups[groupId - 1])
+ return;
+
+ Groups[groupId-1]->Process(loot, lootMode);
return;
}
// Rolling non-grouped items
for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
{
- if (i->lootmode &~ lootMode) // Do not add if mode mismatch
+ LootStoreItem* item = *i;
+ if (item->lootmode &~ lootMode) // Do not add if mode mismatch
continue;
- if (!i->Roll(rate))
- continue; // Bad luck for the entry
+ if (!item->Roll(rate))
+ continue; // Bad luck for the entry
- if (ItemTemplate const* _proto = sObjectMgr->GetItemTemplate(i->itemid))
+ if (item->mincountOrRef < 0) // References processing
{
- uint8 _item_counter = 0;
- LootItemList::const_iterator _item = loot.items.begin();
- for (; _item != loot.items.end(); ++_item)
- if (_item->itemid == i->itemid) // search through the items that have already dropped
- {
- ++_item_counter;
- if (_proto->InventoryType == 0 && _item_counter == 3) // Non-equippable items are limited to 3 drops
- continue;
- else if (_proto->InventoryType != 0 && _item_counter == 1) // Equippable item are limited to 1 drop
- continue;
- }
- if (_item != loot.items.end())
- continue;
- }
-
- if (i->mincountOrRef < 0) // References processing
- {
- LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-i->mincountOrRef);
+ LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-item->mincountOrRef);
if (!Referenced)
- continue; // Error message already printed at loading stage
+ continue; // Error message already printed at loading stage
- uint32 maxcount = uint32(float(i->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT));
- for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator
- Referenced->Process(loot, rate, lootMode, i->group);
+ uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT));
+ for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator
+ Referenced->Process(loot, rate, lootMode, item->group);
}
- else // Plain entries (not a reference, not grouped)
- loot.AddItem(*i); // Chance is already checked, just add
+ else // Plain entries (not a reference, not grouped)
+ loot.AddItem(*item); // Chance is already checked, just add
}
// Now processing groups
for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
- i->Process(loot, lootMode);
+ if (LootGroup* group = *i)
+ group->Process(loot, lootMode);
}
// True if template includes at least 1 quest drop entry
@@ -1349,27 +1323,33 @@ bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) con
{
if (groupId > Groups.size())
return false; // Error message [should be] already printed at loading stage
- return Groups[groupId-1].HasQuestDrop();
+
+ if (!Groups[groupId - 1])
+ return false;
+
+ return Groups[groupId-1]->HasQuestDrop();
}
for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
{
- if (i->mincountOrRef < 0) // References
+ LootStoreItem* item = *i;
+ if (item->mincountOrRef < 0) // References
{
- LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
+ LootTemplateMap::const_iterator Referenced = store.find(-item->mincountOrRef);
if (Referenced == store.end())
continue; // Error message [should be] already printed at loading stage
- if (Referenced->second->HasQuestDrop(store, i->group))
+ if (Referenced->second->HasQuestDrop(store, item->group))
return true;
}
- else if (i->needs_quest)
+ else if (item->needs_quest)
return true; // quest drop found
}
// Now processing groups
for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
- if (i->HasQuestDrop())
- return true;
+ if (LootGroup* group = *i)
+ if (group->HasQuestDrop())
+ return true;
return false;
}
@@ -1381,28 +1361,34 @@ bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player co
{
if (groupId > Groups.size())
return false; // Error message already printed at loading stage
- return Groups[groupId-1].HasQuestDropForPlayer(player);
+
+ if (!Groups[groupId - 1])
+ return false;
+
+ return Groups[groupId-1]->HasQuestDropForPlayer(player);
}
// Checking non-grouped entries
for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
{
- if (i->mincountOrRef < 0) // References processing
+ LootStoreItem* item = *i;
+ if (item->mincountOrRef < 0) // References processing
{
- LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
+ LootTemplateMap::const_iterator Referenced = store.find(-item->mincountOrRef);
if (Referenced == store.end())
continue; // Error message already printed at loading stage
- if (Referenced->second->HasQuestDropForPlayer(store, player, i->group))
+ if (Referenced->second->HasQuestDropForPlayer(store, player, item->group))
return true;
}
- else if (player->HasQuestForItem(i->itemid))
+ else if (player->HasQuestForItem(item->itemid))
return true; // active quest drop found
}
// Now checking groups
for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
- if (i->HasQuestDropForPlayer(player))
- return true;
+ if (LootGroup* group = *i)
+ if (group->HasQuestDropForPlayer(player))
+ return true;
return false;
}
@@ -1411,8 +1397,9 @@ bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player co
void LootTemplate::Verify(LootStore const& lootstore, uint32 id) const
{
// Checking group chances
- for (uint32 i=0; i < Groups.size(); ++i)
- Groups[i].Verify(lootstore, id, i+1);
+ for (uint32 i = 0; i < Groups.size(); ++i)
+ if (Groups[i])
+ Groups[i]->Verify(lootstore, id, i + 1);
// TODO: References validity checks
}
@@ -1421,18 +1408,21 @@ void LootTemplate::CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_se
{
for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
{
- if (ieItr->mincountOrRef < 0)
+ LootStoreItem* item = *ieItr;
+ if (item->mincountOrRef < 0)
{
- if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
- LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
+ if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef))
+ LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef);
else if (ref_set)
- ref_set->erase(-ieItr->mincountOrRef);
+ ref_set->erase(-item->mincountOrRef);
}
}
for (LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr)
- grItr->CheckLootRefs(store, ref_set);
+ if (LootGroup* group = *grItr)
+ group->CheckLootRefs(store, ref_set);
}
+
bool LootTemplate::addConditionItem(Condition* cond)
{
if (!cond || !cond->isLoaded())//should never happen, checked at loading
@@ -1440,41 +1430,48 @@ bool LootTemplate::addConditionItem(Condition* cond)
sLog->outError(LOG_FILTER_LOOT, "LootTemplate::addConditionItem: condition is null");
return false;
}
+
if (!Entries.empty())
{
for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i)
{
- if (i->itemid == uint32(cond->SourceEntry))
+ if ((*i)->itemid == uint32(cond->SourceEntry))
{
- i->conditions.push_back(cond);
+ (*i)->conditions.push_back(cond);
return true;
}
}
}
+
if (!Groups.empty())
{
for (LootGroups::iterator groupItr = Groups.begin(); groupItr != Groups.end(); ++groupItr)
{
- LootStoreItemList* itemList = (*groupItr).GetExplicitlyChancedItemList();
+ LootGroup* group = *groupItr;
+ if (!group)
+ continue;
+
+ LootStoreItemList* itemList = group->GetExplicitlyChancedItemList();
if (!itemList->empty())
{
for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i)
{
- if ((*i).itemid == uint32(cond->SourceEntry))
+ if ((*i)->itemid == uint32(cond->SourceEntry))
{
- (*i).conditions.push_back(cond);
+ (*i)->conditions.push_back(cond);
return true;
}
}
}
- itemList = (*groupItr).GetEqualChancedItemList();
+
+ itemList = group->GetEqualChancedItemList();
if (!itemList->empty())
{
for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i)
{
- if ((*i).itemid == uint32(cond->SourceEntry))
+ if ((*i)->itemid == uint32(cond->SourceEntry))
{
- (*i).conditions.push_back(cond);
+ (*i)->conditions.push_back(cond);
return true;
}
}
@@ -1487,10 +1484,9 @@ bool LootTemplate::addConditionItem(Condition* cond)
bool LootTemplate::isReference(uint32 id)
{
for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
- {
- if (ieItr->itemid == id && ieItr->mincountOrRef < 0)
+ if ((*ieItr)->itemid == id && (*ieItr)->mincountOrRef < 0)
return true;
- }
+
return false;//not found or not reference
}
diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h
index e51a4607ce1..7474fc87a71 100644
--- a/src/server/game/Loot/LootMgr.h
+++ b/src/server/game/Loot/LootMgr.h
@@ -27,6 +27,7 @@
#include <map>
#include <vector>
+#include <list>
enum RollType
{
@@ -173,7 +174,7 @@ class LootTemplate;
typedef std::vector<QuestItem> QuestItemList;
typedef std::vector<LootItem> LootItemList;
typedef std::map<uint32, QuestItemList*> QuestItemMap;
-typedef std::vector<LootStoreItem> LootStoreItemList;
+typedef std::list<LootStoreItem*> LootStoreItemList;
typedef UNORDERED_MAP<uint32, LootTemplate*> LootTemplateMap;
typedef std::set<uint32> LootIdSet;
@@ -217,11 +218,14 @@ class LootStore
class LootTemplate
{
class LootGroup; // A set of loot definitions for items (refs are not allowed inside)
- typedef std::vector<LootGroup> LootGroups;
+ typedef std::vector<LootGroup*> LootGroups;
public:
+ LootTemplate() { }
+ ~LootTemplate();
+
// Adds an entry to the group (at loading stage)
- void AddEntry(LootStoreItem& item);
+ void AddEntry(LootStoreItem* item);
// Rolls for every item in the template and adds the rolled items the the loot
void Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId = 0) const;
void CopyConditions(ConditionList conditions);
@@ -241,6 +245,10 @@ class LootTemplate
private:
LootStoreItemList Entries; // not grouped only
LootGroups Groups; // groups have own (optimised) processing, grouped entries go there
+
+ // Objects of this class must never be copied, we are storing pointers in container
+ LootTemplate(LootTemplate const&);
+ LootTemplate& operator=(LootTemplate const&);
};
//=====================================================
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 9c3b7d5e5b5..30ed39932ae 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -18,6 +18,7 @@
#include "Map.h"
#include "Battleground.h"
+#include "MMapFactory.h"
#include "CellImpl.h"
#include "DynamicTree.h"
#include "GridNotifiers.h"
@@ -25,7 +26,6 @@
#include "GridStates.h"
#include "Group.h"
#include "InstanceScript.h"
-#include "LFGMgr.h"
#include "MapInstanced.h"
#include "MapManager.h"
#include "ObjectAccessor.h"
@@ -43,7 +43,7 @@ union u_map_magic
};
u_map_magic MapMagic = { {'M','A','P','S'} };
-u_map_magic MapVersionMagic = { {'v','1','.','2'} };
+u_map_magic MapVersionMagic = { {'v','1','.','3'} };
u_map_magic MapAreaMagic = { {'A','R','E','A'} };
u_map_magic MapHeightMagic = { {'M','H','G','T'} };
u_map_magic MapLiquidMagic = { {'M','L','I','Q'} };
@@ -71,6 +71,8 @@ Map::~Map()
if (!m_scriptSchedule.empty())
sScriptMgr->DecreaseScheduledScriptCount(m_scriptSchedule.size());
+
+ MMAP::MMapFactory::createOrGetMMapManager()->unloadMapInstance(GetId(), i_InstanceId);
}
bool Map::ExistMap(uint32 mapid, int gx, int gy)
@@ -119,6 +121,16 @@ bool Map::ExistVMap(uint32 mapid, int gx, int gy)
return true;
}
+void Map::LoadMMap(int gx, int gy)
+{
+ bool mmapLoadResult = MMAP::MMapFactory::createOrGetMMapManager()->loadMap((sWorld->GetDataPath() + "mmaps").c_str(), GetId(), gx, gy);
+
+ if (mmapLoadResult)
+ sLog->outInfo(LOG_FILTER_MAPS, "MMAP loaded name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
+ else
+ sLog->outInfo(LOG_FILTER_MAPS, "Could not load MMAP name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
+}
+
void Map::LoadVMap(int gx, int gy)
{
// x and y are swapped !!
@@ -167,18 +179,16 @@ void Map::LoadMap(int gx, int gy, bool reload)
}
// map file name
- char *tmp=NULL;
- int len = sWorld->GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1;
+ char* tmp = NULL;
+ int len = sWorld->GetDataPath().length() + strlen("maps/%03u%02u%02u.map") + 1;
tmp = new char[len];
- snprintf(tmp, len, (char *)(sWorld->GetDataPath()+"maps/%03u%02u%02u.map").c_str(), GetId(), gx, gy);
+ snprintf(tmp, len, (char *)(sWorld->GetDataPath() + "maps/%03u%02u%02u.map").c_str(), GetId(), gx, gy);
sLog->outInfo(LOG_FILTER_MAPS, "Loading map %s", tmp);
// loading data
GridMaps[gx][gy] = new GridMap();
if (!GridMaps[gx][gy]->loadData(tmp))
- {
sLog->outError(LOG_FILTER_MAPS, "Error loading map file: \n %s\n", tmp);
- }
- delete [] tmp;
+ delete[] tmp;
sScriptMgr->OnLoadGridMap(this, GridMaps[gx][gy], gx, gy);
}
@@ -186,8 +196,12 @@ void Map::LoadMap(int gx, int gy, bool reload)
void Map::LoadMapAndVMap(int gx, int gy)
{
LoadMap(gx, gy);
+ // Only load the data for the base map
if (i_InstanceId == 0)
- LoadVMap(gx, gy); // Only load the data for the base map
+ {
+ LoadVMap(gx, gy);
+ LoadMMap(gx, gy);
+ }
}
void Map::InitStateMachine()
@@ -998,8 +1012,8 @@ bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll)
GridMaps[gx][gy]->unloadData();
delete GridMaps[gx][gy];
}
- // x and y are swapped
VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId(), gx, gy);
+ MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(GetId(), gx, gy);
}
else
((MapInstanced*)m_parentMap)->RemoveGridMapReference(GridCoord(gx, gy));
@@ -1071,7 +1085,7 @@ GridMap::~GridMap()
unloadData();
}
-bool GridMap::loadData(char *filename)
+bool GridMap::loadData(char* filename)
{
// Unload old data if exist
unloadData();
@@ -1905,10 +1919,10 @@ bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, floa
bool Map::getObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist)
{
- Vector3 startPos = Vector3(x1, y1, z1);
- Vector3 dstPos = Vector3(x2, y2, z2);
+ G3D::Vector3 startPos(x1, y1, z1);
+ G3D::Vector3 dstPos(x2, y2, z2);
- Vector3 resultPos;
+ G3D::Vector3 resultPos;
bool result = _dynamicTree.getObjectHitPos(phasemask, startPos, dstPos, resultPos, modifyDist);
rx = resultPos.x;
@@ -2470,13 +2484,6 @@ bool InstanceMap::AddPlayerToMap(Player* player)
ASSERT(playerBind->save == mapSave);
}
}
-
- if (group && group->isLFGGroup())
- if (uint32 dungeonId = sLFGMgr->GetDungeon(group->GetGUID(), true))
- if (LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId))
- if (LFGDungeonData const* randomDungeon = sLFGMgr->GetLFGDungeon(*(sLFGMgr->GetSelectedDungeons(player->GetGUID()).begin())))
- if (uint32(dungeon->map) == GetId() && dungeon->difficulty == GetDifficulty() && randomDungeon->type == LFG_TYPE_RANDOM)
- player->CastSpell(player, LFG_SPELL_LUCK_OF_THE_DRAW, true);
}
// for normal instances cancel the reset schedule when the
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 5bb40a45f7e..e66e0869686 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -76,6 +76,8 @@ struct map_fileheader
uint32 heightMapSize;
uint32 liquidMapOffset;
uint32 liquidMapSize;
+ uint32 holesOffset;
+ uint32 holesSize;
};
#define MAP_AREA_NO_AREA 0x0001
@@ -480,6 +482,7 @@ class Map : public GridRefManager<NGridType>
void LoadMapAndVMap(int gx, int gy);
void LoadVMap(int gx, int gy);
void LoadMap(int gx, int gy, bool reload = false);
+ void LoadMMap(int gx, int gy);
GridMap* GetGrid(float x, float y);
void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; }
diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp
index 27a1e0cc432..c2079c22e76 100644
--- a/src/server/game/Maps/MapInstanced.cpp
+++ b/src/server/game/Maps/MapInstanced.cpp
@@ -21,6 +21,7 @@
#include "MapManager.h"
#include "Battleground.h"
#include "VMapFactory.h"
+#include "MMapFactory.h"
#include "InstanceSaveMgr.h"
#include "World.h"
#include "Group.h"
@@ -261,6 +262,7 @@ bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr)
if (m_InstancedMaps.size() <= 1 && sWorld->getBoolConfig(CONFIG_GRID_UNLOAD))
{
VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(itr->second->GetId());
+ MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(itr->second->GetId());
// in that case, unload grids of the base map, too
// so in the next map creation, (EnsureGridCreated actually) VMaps will be reloaded
Map::UnloadAll();
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 77acb5e0218..03884ae003e 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -86,7 +86,40 @@ enum TrinityStrings
LANG_CONNECTED_PLAYERS = 60,
LANG_ACCOUNT_ADDON = 61,
LANG_IMPROPER_VALUE = 62,
- // Room for more level 0 63-99 not used
+ LANG_RBAC_WRONG_PARAMETER_ID = 63,
+ LANG_RBAC_WRONG_PARAMETER_REALM = 64,
+ LANG_RBAC_GROUP_IN_LIST = 65,
+ LANG_RBAC_GROUP_NOT_IN_LIST = 66,
+ LANG_RBAC_GROUP_ADDED = 67,
+ LANG_RBAC_GROUP_REMOVED = 68,
+ LANG_RBAC_GROUP_LIST_HEADER = 69,
+ LANG_RBAC_LIST_EMPTY = 70,
+ LANG_RBAC_LIST_ELEMENT = 71,
+ LANG_RBAC_ROLE_GRANTED_IN_LIST = 72,
+ LANG_RBAC_ROLE_GRANTED_IN_DENIED_LIST = 73,
+ LANG_RBAC_ROLE_GRANTED = 74,
+ LANG_RBAC_ROLE_DENIED_IN_LIST = 75,
+ LANG_RBAC_ROLE_DENIED_IN_GRANTED_LIST = 76,
+ LANG_RBAC_ROLE_DENIED = 77,
+ LANG_RBAC_ROLE_REVOKED = 78,
+ LANG_RBAC_ROLE_REVOKED_NOT_IN_LIST = 79,
+ LANG_RBAC_ROLE_LIST_HEADER_GRANTED = 80,
+ LANG_RBAC_ROLE_LIST_HEADER_DENIED = 81,
+ LANG_RBAC_PERM_GRANTED_IN_LIST = 82,
+ LANG_RBAC_PERM_GRANTED_IN_DENIED_LIST = 83,
+ LANG_RBAC_PERM_GRANTED = 84,
+ LANG_RBAC_PERM_DENIED_IN_LIST = 85,
+ LANG_RBAC_PERM_DENIED_IN_GRANTED_LIST = 86,
+ LANG_RBAC_PERM_DENIED = 87,
+ LANG_RBAC_PERM_REVOKED = 88,
+ LANG_RBAC_PERM_REVOKED_NOT_IN_LIST = 89,
+ LANG_RBAC_PERM_LIST_HEADER_GRANTED = 90,
+ LANG_RBAC_PERM_LIST_HEADER_DENIED = 91,
+ LANG_RBAC_PERM_LIST_GLOBAL = 92,
+ LANG_RBAC_LIST_GROUPS_HEADER = 93,
+ LANG_RBAC_LIST_ROLES_HEADER = 94,
+ LANG_RBAC_LIST_PERMISSIONS_HEADER = 95,
+ // Room for more level 0 96-99 not used
// level 1 chat
LANG_GLOBAL_NOTIFY = 100,
@@ -530,6 +563,7 @@ enum TrinityStrings
LANG_PINFO_BAN = 453,
LANG_PINFO_MAP_ONLINE = 714,
LANG_PINFO_MAP_OFFLINE = 716,
+ LANG_PINFO_GUILD_INFO = 749,
LANG_YOU_SET_EXPLORE_ALL = 551,
LANG_YOU_SET_EXPLORE_NOTHING = 552,
@@ -750,7 +784,32 @@ enum TrinityStrings
LANG_COMMAND_CREATURESTORAGE_NOTFOUND = 818,
LANG_CHANNEL_CITY = 819,
- // Room for in-game strings 820-999 not used
+
+ LANG_NPCINFO_GOSSIP = 820,
+ LANG_NPCINFO_QUESTGIVER = 821,
+ LANG_NPCINFO_TRAINER_CLASS = 822,
+ LANG_NPCINFO_TRAINER_PROFESSION = 823,
+ LANG_NPCINFO_VENDOR_AMMO = 824,
+ LANG_NPCINFO_VENDOR_FOOD = 825,
+ LANG_NPCINFO_VENDOR_POISON = 826,
+ LANG_NPCINFO_VENDOR_REAGENT = 827,
+ LANG_NPCINFO_REPAIR = 828,
+ LANG_NPCINFO_FLIGHTMASTER = 829,
+ LANG_NPCINFO_SPIRITHEALER = 830,
+ LANG_NPCINFO_SPIRITGUIDE = 831,
+ LANG_NPCINFO_INNKEEPER = 832,
+ LANG_NPCINFO_BANKER = 833,
+ LANG_NPCINFO_PETITIONER = 834,
+ LANG_NPCINFO_TABARDDESIGNER = 835,
+ LANG_NPCINFO_BATTLEMASTER = 836,
+ LANG_NPCINFO_AUCTIONEER = 837,
+ LANG_NPCINFO_STABLEMASTER = 838,
+ LANG_NPCINFO_GUILD_BANKER = 839,
+ LANG_NPCINFO_SPELLCLICK = 840,
+ LANG_NPCINFO_MAILBOX = 841,
+ LANG_NPCINFO_PLAYER_VEHICLE = 842,
+
+ // Room for in-game strings 843-999 not used
// Level 4 (CLI only commands)
LANG_COMMAND_EXIT = 1000,
@@ -830,7 +889,13 @@ enum TrinityStrings
LANG_MOVEGENS_EFFECT = 1142,
LANG_MOVEFLAGS_GET = 1143,
LANG_MOVEFLAGS_SET = 1144,
- // Room for more level 3 1144-1199 not used
+ LANG_GROUP_ALREADY_IN_GROUP = 1145,
+ LANG_GROUP_PLAYER_JOINED = 1146,
+ LANG_GROUP_NOT_IN_GROUP = 1147,
+ LANG_GROUP_FULL = 1148,
+ LANG_GROUP_TYPE = 1149,
+ LANG_GROUP_PLAYER_NAME_GUID = 1150,
+ // Room for more level 3 1151-1199 not used
// Debug commands
LANG_CINEMATIC_NOT_EXIST = 1200,
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 6ff47f40ed4..3a061910faa 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -19,6 +19,7 @@
#ifndef TRINITY_SHAREDDEFINES_H
#define TRINITY_SHAREDDEFINES_H
+#include "DetourNavMesh.h"
#include "Define.h"
#include <cassert>
@@ -35,7 +36,6 @@ enum SpellEffIndex
#define EFFECT_FIRST_FOUND 254
#define EFFECT_ALL 255
-
// loot modes for creatures and gameobjects, bitmask!
enum LootModes
{
@@ -2834,7 +2834,7 @@ enum CreatureTypeFlags2
CREATURE_TYPEFLAGS_2_UNK5 = 0x00000010,
CREATURE_TYPEFLAGS_2_UNK6 = 0x00000020,
CREATURE_TYPEFLAGS_2_UNK7 = 0x00000040,
- CREATURE_TYPEFLAGS_2_UNK8 = 0x00000080,
+ CREATURE_TYPEFLAGS_2_UNK8 = 0x00000080
};
enum CreatureEliteType
@@ -2884,7 +2884,7 @@ enum HolidayIds
HOLIDAY_RATED_BG_25_VS_25 = 443,
HOLIDAY_ANNIVERSARY_7_YEARS = 467,
HOLIDAY_DARKMOON_FAIRE_TEROKKAR = 479,
- HOLIDAY_ANNIVERSARY_8_YEARS = 484,
+ HOLIDAY_ANNIVERSARY_8_YEARS = 484
};
// values based at QuestInfo.dbc
@@ -3149,7 +3149,7 @@ enum SkillType
SKILL_PET_SHALE_SPIDER = 817,
SKILL_PET_BEETLE = 818,
SKILL_ALL_GUILD_PERKS = 821,
- SKILL_PET_HYDRA = 824,
+ SKILL_PET_HYDRA = 824
};
#define MAX_SKILL_TYPE 825
@@ -3324,7 +3324,7 @@ enum ChatMsg
CHAT_MSG_ACHIEVEMENT = 0x30,
CHAT_MSG_GUILD_ACHIEVEMENT = 0x31,
CHAT_MSG_ARENA_POINTS = 0x32,
- CHAT_MSG_PARTY_LEADER = 0x33,
+ CHAT_MSG_PARTY_LEADER = 0x33
};
#define MAX_CHAT_MSG_TYPE 0x34
@@ -3342,14 +3342,14 @@ enum ChatLinkColors
// Values from ItemPetFood (power of (value-1) used for compare with CreatureFamilyEntry.petDietMask
enum PetDiet
{
- PET_DIET_MEAT = 1,
- PET_DIET_FISH = 2,
- PET_DIET_CHEESE = 3,
- PET_DIET_BREAD = 4,
- PET_DIET_FUNGAS = 5,
- PET_DIET_FRUIT = 6,
- PET_DIET_RAW_MEAT = 7,
- PET_DIET_RAW_FISH = 8
+ PET_DIET_MEAT = 1,
+ PET_DIET_FISH = 2,
+ PET_DIET_CHEESE = 3,
+ PET_DIET_BREAD = 4,
+ PET_DIET_FUNGAS = 5,
+ PET_DIET_FRUIT = 6,
+ PET_DIET_RAW_MEAT = 7,
+ PET_DIET_RAW_FISH = 8
};
#define MAX_PET_DIET 9
@@ -3874,4 +3874,33 @@ enum PartyResult
ERR_PARTY_LFG_TELEPORT_IN_COMBAT = 30
};
+const uint32 MMAP_MAGIC = 0x4d4d4150; // 'MMAP'
+#define MMAP_VERSION 3
+
+struct MmapTileHeader
+{
+ uint32 mmapMagic;
+ uint32 dtVersion;
+ uint32 mmapVersion;
+ uint32 size;
+ bool usesLiquids : 1;
+
+ MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
+ mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {}
+};
+
+enum NavTerrain
+{
+ NAV_EMPTY = 0x00,
+ NAV_GROUND = 0x01,
+ NAV_MAGMA = 0x02,
+ NAV_SLIME = 0x04,
+ NAV_WATER = 0x08,
+ NAV_UNUSED1 = 0x10,
+ NAV_UNUSED2 = 0x20,
+ NAV_UNUSED3 = 0x40,
+ NAV_UNUSED4 = 0x80
+ // we only have 8 bits
+};
+
#endif
diff --git a/src/server/game/Movement/FollowerRefManager.h b/src/server/game/Movement/FollowerRefManager.h
index 2bb31d27227..92904f8e4af 100644
--- a/src/server/game/Movement/FollowerRefManager.h
+++ b/src/server/game/Movement/FollowerRefManager.h
@@ -29,4 +29,3 @@ class FollowerRefManager : public RefManager<Unit, TargetedMovementGeneratorBase
};
#endif
-
diff --git a/src/server/game/Movement/FollowerReference.cpp b/src/server/game/Movement/FollowerReference.cpp
index 2ce23e214d1..30797bbaaca 100644
--- a/src/server/game/Movement/FollowerReference.cpp
+++ b/src/server/game/Movement/FollowerReference.cpp
@@ -34,4 +34,3 @@ void FollowerReference::sourceObjectDestroyLink()
{
getSource()->stopFollowing();
}
-
diff --git a/src/server/game/Movement/FollowerReference.h b/src/server/game/Movement/FollowerReference.h
index 9e373d2527e..43ad7e7fa58 100644
--- a/src/server/game/Movement/FollowerReference.h
+++ b/src/server/game/Movement/FollowerReference.h
@@ -32,4 +32,3 @@ class FollowerReference : public Reference<Unit, TargetedMovementGeneratorBase>
void sourceObjectDestroyLink();
};
#endif
-
diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp
index 277a5721c3d..c9ca7772186 100644
--- a/src/server/game/Movement/MotionMaster.cpp
+++ b/src/server/game/Movement/MotionMaster.cpp
@@ -87,7 +87,7 @@ void MotionMaster::UpdateMotion(uint32 diff)
ASSERT(!empty());
_cleanFlag |= MMCF_UPDATE;
- if (!top()->Update(*_owner, diff))
+ if (!top()->Update(_owner, diff))
{
_cleanFlag &= ~MMCF_UPDATE;
MovementExpired();
@@ -111,7 +111,7 @@ void MotionMaster::UpdateMotion(uint32 diff)
else if (needInitTop())
InitTop();
else if (_cleanFlag & MMCF_RESET)
- top()->Reset(*_owner);
+ top()->Reset(_owner);
_cleanFlag &= ~MMCF_RESET;
}
@@ -132,7 +132,7 @@ void MotionMaster::DirectClean(bool reset)
if (needInitTop())
InitTop();
else if (reset)
- top()->Reset(*_owner);
+ top()->Reset(_owner);
}
void MotionMaster::DelayedClean()
@@ -163,7 +163,7 @@ void MotionMaster::DirectExpire(bool reset)
else if (needInitTop())
InitTop();
else if (reset)
- top()->Reset(*_owner);
+ top()->Reset(_owner);
}
void MotionMaster::DelayedExpire()
@@ -199,19 +199,19 @@ void MotionMaster::MoveTargetedHome()
{
Clear(false);
- if (_owner->GetTypeId()==TYPEID_UNIT && !((Creature*)_owner)->GetCharmerOrOwnerGUID())
+ if (_owner->GetTypeId() == TYPEID_UNIT && !_owner->ToCreature()->GetCharmerOrOwnerGUID())
{
sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u GUID: %u) targeted home", _owner->GetEntry(), _owner->GetGUIDLow());
Mutate(new HomeMovementGenerator<Creature>(), MOTION_SLOT_ACTIVE);
}
- else if (_owner->GetTypeId()==TYPEID_UNIT && ((Creature*)_owner)->GetCharmerOrOwnerGUID())
+ else if (_owner->GetTypeId() == TYPEID_UNIT && _owner->ToCreature()->GetCharmerOrOwnerGUID())
{
sLog->outDebug(LOG_FILTER_GENERAL, "Pet or controlled creature (Entry: %u GUID: %u) targeting home", _owner->GetEntry(), _owner->GetGUIDLow());
- Unit* target = ((Creature*)_owner)->GetCharmerOrOwner();
+ Unit* target = _owner->ToCreature()->GetCharmerOrOwner();
if (target)
{
sLog->outDebug(LOG_FILTER_GENERAL, "Following %s (GUID: %u)", target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : ((Creature*)target)->GetDBTableGUIDLow());
- Mutate(new FollowMovementGenerator<Creature>(*target, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE), MOTION_SLOT_ACTIVE);
+ Mutate(new FollowMovementGenerator<Creature>(target, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE), MOTION_SLOT_ACTIVE);
}
}
else
@@ -248,7 +248,7 @@ void MotionMaster::MoveChase(Unit* target, float dist, float angle)
_owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
- Mutate(new ChaseMovementGenerator<Player>(*target, dist, angle), MOTION_SLOT_ACTIVE);
+ Mutate(new ChaseMovementGenerator<Player>(target, dist, angle), MOTION_SLOT_ACTIVE);
}
else
{
@@ -256,7 +256,7 @@ void MotionMaster::MoveChase(Unit* target, float dist, float angle)
_owner->GetEntry(), _owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
- Mutate(new ChaseMovementGenerator<Creature>(*target, dist, angle), MOTION_SLOT_ACTIVE);
+ Mutate(new ChaseMovementGenerator<Creature>(target, dist, angle), MOTION_SLOT_ACTIVE);
}
}
@@ -272,7 +272,7 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlo
sLog->outDebug(LOG_FILTER_GENERAL, "Player (GUID: %u) follow to %s (GUID: %u)", _owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
- Mutate(new FollowMovementGenerator<Player>(*target, dist, angle), slot);
+ Mutate(new FollowMovementGenerator<Player>(target, dist, angle), slot);
}
else
{
@@ -280,22 +280,22 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlo
_owner->GetEntry(), _owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
- Mutate(new FollowMovementGenerator<Creature>(*target, dist, angle), slot);
+ Mutate(new FollowMovementGenerator<Creature>(target, dist, angle), slot);
}
}
-void MotionMaster::MovePoint(uint32 id, float x, float y, float z)
+void MotionMaster::MovePoint(uint32 id, float x, float y, float z, bool generatePath)
{
if (_owner->GetTypeId() == TYPEID_PLAYER)
{
sLog->outDebug(LOG_FILTER_GENERAL, "Player (GUID: %u) targeted point (Id: %u X: %f Y: %f Z: %f)", _owner->GetGUIDLow(), id, x, y, z);
- Mutate(new PointMovementGenerator<Player>(id, x, y, z), MOTION_SLOT_ACTIVE);
+ Mutate(new PointMovementGenerator<Player>(id, x, y, z, generatePath), MOTION_SLOT_ACTIVE);
}
else
{
sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u GUID: %u) targeted point (ID: %u X: %f Y: %f Z: %f)",
_owner->GetEntry(), _owner->GetGUIDLow(), id, x, y, z);
- Mutate(new PointMovementGenerator<Creature>(id, x, y, z), MOTION_SLOT_ACTIVE);
+ Mutate(new PointMovementGenerator<Creature>(id, x, y, z, generatePath), MOTION_SLOT_ACTIVE);
}
}
@@ -306,7 +306,7 @@ void MotionMaster::MoveLand(uint32 id, Position const& pos)
sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", _owner->GetEntry(), id, x, y, z);
- Movement::MoveSplineInit init(*_owner);
+ Movement::MoveSplineInit init(_owner);
init.MoveTo(x, y, z);
init.SetAnimation(Movement::ToGround);
init.Launch();
@@ -320,7 +320,7 @@ void MotionMaster::MoveTakeoff(uint32 id, Position const& pos)
sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", _owner->GetEntry(), id, x, y, z);
- Movement::MoveSplineInit init(*_owner);
+ Movement::MoveSplineInit init(_owner);
init.MoveTo(x, y, z);
init.SetAnimation(Movement::ToFly);
init.Launch();
@@ -340,7 +340,7 @@ void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, floa
_owner->GetNearPoint(_owner, x, y, z, _owner->GetObjectSize(), dist, _owner->GetAngle(srcX, srcY) + M_PI);
- Movement::MoveSplineInit init(*_owner);
+ Movement::MoveSplineInit init(_owner);
init.MoveTo(x, y, z);
init.SetParabolic(max_height, 0);
init.SetOrientationFixed(true);
@@ -370,8 +370,8 @@ void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float spee
float moveTimeHalf = speedZ / Movement::gravity;
float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -speedZ);
- Movement::MoveSplineInit init(*_owner);
- init.MoveTo(x, y, z);
+ Movement::MoveSplineInit init(_owner);
+ init.MoveTo(x, y, z, false);
init.SetParabolic(max_height, 0);
init.SetVelocity(speedXY);
init.Launch();
@@ -399,14 +399,14 @@ void MotionMaster::MoveFall(uint32 id /*=0*/)
_owner->m_movementInfo.SetFallTime(0);
}
- Movement::MoveSplineInit init(*_owner);
- init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), tz);
+ Movement::MoveSplineInit init(_owner);
+ init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), tz, false);
init.SetFall();
init.Launch();
Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED);
}
-void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id)
+void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id, bool generatePath)
{
if (Impl[MOTION_SLOT_CONTROLLED] && Impl[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE)
return;
@@ -414,16 +414,28 @@ void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id)
if (_owner->GetTypeId() == TYPEID_PLAYER)
{
sLog->outDebug(LOG_FILTER_GENERAL, "Player (GUID: %u) charge point (X: %f Y: %f Z: %f)", _owner->GetGUIDLow(), x, y, z);
- Mutate(new PointMovementGenerator<Player>(id, x, y, z, speed), MOTION_SLOT_CONTROLLED);
+ Mutate(new PointMovementGenerator<Player>(id, x, y, z, generatePath, speed), MOTION_SLOT_CONTROLLED);
}
else
{
sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u GUID: %u) charge point (X: %f Y: %f Z: %f)",
_owner->GetEntry(), _owner->GetGUIDLow(), x, y, z);
- Mutate(new PointMovementGenerator<Creature>(id, x, y, z, speed), MOTION_SLOT_CONTROLLED);
+ Mutate(new PointMovementGenerator<Creature>(id, x, y, z, generatePath, speed), MOTION_SLOT_CONTROLLED);
}
}
+void MotionMaster::MoveCharge(PathGenerator path, float speed, uint32 id)
+{
+ Vector3 dest = path.GetActualEndPosition();
+
+ MoveCharge(dest.x, dest.y, dest.z, speed, id);
+
+ Movement::MoveSplineInit init(_owner);
+ init.MovebyPath(path.GetPath());
+ init.SetVelocity(speed);
+ init.Launch();
+}
+
void MotionMaster::MoveSeekAssistance(float x, float y, float z)
{
if (_owner->GetTypeId() == TYPEID_PLAYER)
@@ -546,7 +558,7 @@ void MotionMaster::Mutate(MovementGenerator *m, MovementSlot slot)
else
{
_needInit[slot] = false;
- m->Initialize(*_owner);
+ m->Initialize(_owner);
}
}
@@ -614,7 +626,7 @@ MovementGeneratorType MotionMaster::GetMotionSlotType(int slot) const
void MotionMaster::InitTop()
{
- top()->Initialize(*_owner);
+ top()->Initialize(_owner);
_needInit[_top] = false;
}
@@ -622,7 +634,7 @@ void MotionMaster::DirectDelete(_Ty curr)
{
if (isStatic(curr))
return;
- curr->Finalize(*_owner);
+ curr->Finalize(_owner);
delete curr;
}
@@ -639,9 +651,9 @@ void MotionMaster::DelayedDelete(_Ty curr)
bool MotionMaster::GetDestination(float &x, float &y, float &z)
{
if (_owner->movespline->Finalized())
- return false;
+ return false;
- const G3D::Vector3& dest = _owner->movespline->FinalDestination();
+ G3D::Vector3 const& dest = _owner->movespline->FinalDestination();
x = dest.x;
y = dest.y;
z = dest.z;
diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h
index f6f58afef22..4b6075aac10 100644
--- a/src/server/game/Movement/MotionMaster.h
+++ b/src/server/game/Movement/MotionMaster.h
@@ -26,6 +26,7 @@
class MovementGenerator;
class Unit;
+class PathGenerator;
// Creature Entry ID used for waypoints show, visible only for GMs
#define VISUAL_WAYPOINT 1
@@ -154,13 +155,14 @@ class MotionMaster //: private std::stack<MovementGenerator *>
void MoveFleeing(Unit* enemy, uint32 time = 0);
void MovePoint(uint32 id, const Position &pos)
{ MovePoint(id, pos.m_positionX, pos.m_positionY, pos.m_positionZ); }
- void MovePoint(uint32 id, float x, float y, float z);
+ void MovePoint(uint32 id, float x, float y, float z, bool generatePath = true);
// These two movement types should only be used with creatures having landing/takeoff animations
void MoveLand(uint32 id, Position const& pos);
void MoveTakeoff(uint32 id, Position const& pos);
- void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE);
+ void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE, bool generatePath = false);
+ void MoveCharge(PathGenerator path, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE);
void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ);
void MoveJumpTo(float angle, float speedXY, float speedZ);
void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = EVENT_JUMP)
@@ -199,4 +201,3 @@ class MotionMaster //: private std::stack<MovementGenerator *>
uint8 _cleanFlag;
};
#endif
-
diff --git a/src/server/game/Movement/MovementGenerator.h b/src/server/game/Movement/MovementGenerator.h
index 1c1c38bc72f..39394a75513 100644..100755
--- a/src/server/game/Movement/MovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerator.h
@@ -33,41 +33,47 @@ class MovementGenerator
public:
virtual ~MovementGenerator();
- virtual void Initialize(Unit &) = 0;
- virtual void Finalize(Unit &) = 0;
+ virtual void Initialize(Unit*) = 0;
+ virtual void Finalize(Unit*) = 0;
- virtual void Reset(Unit &) = 0;
+ virtual void Reset(Unit*) = 0;
- virtual bool Update(Unit &, uint32 time_diff) = 0;
+ virtual bool Update(Unit*, uint32 time_diff) = 0;
virtual MovementGeneratorType GetMovementGeneratorType() = 0;
virtual void unitSpeedChanged() { }
+
+ // used by Evade code for select point to evade with expected restart default movement
+ virtual bool GetResetPosition(Unit*, float& /*x*/, float& /*y*/, float& /*z*/) { return false; }
};
template<class T, class D>
class MovementGeneratorMedium : public MovementGenerator
{
public:
- void Initialize(Unit &u)
+ void Initialize(Unit* u)
{
//u->AssertIsType<T>();
- (static_cast<D*>(this))->DoInitialize(*((T*)&u));
+ (static_cast<D*>(this))->DoInitialize(static_cast<T*>(u));
}
- void Finalize(Unit &u)
+
+ void Finalize(Unit* u)
{
//u->AssertIsType<T>();
- (static_cast<D*>(this))->DoFinalize(*((T*)&u));
+ (static_cast<D*>(this))->DoFinalize(static_cast<T*>(u));
}
- void Reset(Unit &u)
+
+ void Reset(Unit* u)
{
//u->AssertIsType<T>();
- (static_cast<D*>(this))->DoReset(*((T*)&u));
+ (static_cast<D*>(this))->DoReset(static_cast<T*>(u));
}
- bool Update(Unit &u, uint32 time_diff)
+
+ bool Update(Unit* u, uint32 time_diff)
{
//u->AssertIsType<T>();
- return (static_cast<D*>(this))->DoUpdate(*((T*)&u), time_diff);
+ return (static_cast<D*>(this))->DoUpdate(static_cast<T*>(u), time_diff);
}
};
@@ -88,4 +94,3 @@ typedef FactoryHolder<MovementGenerator, MovementGeneratorType> MovementGenerato
typedef FactoryHolder<MovementGenerator, MovementGeneratorType>::FactoryHolderRegistry MovementGeneratorRegistry;
typedef FactoryHolder<MovementGenerator, MovementGeneratorType>::FactoryHolderRepository MovementGeneratorRepository;
#endif
-
diff --git a/src/server/game/Movement/MovementGeneratorImpl.h b/src/server/game/Movement/MovementGeneratorImpl.h
index 2618cadc14f..b77db7b5b9d 100644
--- a/src/server/game/Movement/MovementGeneratorImpl.h
+++ b/src/server/game/Movement/MovementGeneratorImpl.h
@@ -28,4 +28,3 @@ MovementGeneratorFactory<MOVEMENT_GEN>::Create(void * /*data*/) const
return (new MOVEMENT_GEN());
}
#endif
-
diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
index 482c16997a0..72537f0898c 100755
--- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
@@ -19,6 +19,7 @@
#include "Creature.h"
#include "MapManager.h"
#include "ConfusedMovementGenerator.h"
+#include "PathGenerator.h"
#include "VMapFactory.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
@@ -30,100 +31,44 @@
#endif
template<class T>
-void ConfusedMovementGenerator<T>::DoInitialize(T &unit)
+void ConfusedMovementGenerator<T>::DoInitialize(T* unit)
{
- unit.StopMoving();
- float const wander_distance = 4;
- float x = unit.GetPositionX();
- float y = unit.GetPositionY();
- float z = unit.GetPositionZ();
+ unit->AddUnitState(UNIT_STATE_CONFUSED);
+ unit->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
+ unit->GetPosition(i_x, i_y, i_z);
- Map const* map = unit.GetBaseMap();
+ if (!unit->isAlive() || unit->IsStopped())
+ return;
- i_nextMove = 1;
-
- bool is_water_ok, is_land_ok;
- _InitSpecific(unit, is_water_ok, is_land_ok);
-
- for (uint8 idx = 0; idx < MAX_CONF_WAYPOINTS + 1; ++idx)
- {
- float wanderX = x + (wander_distance * (float)rand_norm() - wander_distance/2);
- float wanderY = y + (wander_distance * (float)rand_norm() - wander_distance/2);
-
- // prevent invalid coordinates generation
- Trinity::NormalizeMapCoord(wanderX);
- Trinity::NormalizeMapCoord(wanderY);
-
- if (unit.IsWithinLOS(wanderX, wanderY, z))
- {
- bool is_water = map->IsInWater(wanderX, wanderY, z);
-
- if ((is_water && !is_water_ok) || (!is_water && !is_land_ok))
- {
- //! Cannot use coordinates outside our InhabitType. Use the current or previous position.
- wanderX = idx > 0 ? i_waypoints[idx-1][0] : x;
- wanderY = idx > 0 ? i_waypoints[idx-1][1] : y;
- }
- }
- else
- {
- //! Trying to access path outside line of sight. Skip this by using the current or previous position.
- wanderX = idx > 0 ? i_waypoints[idx-1][0] : x;
- wanderY = idx > 0 ? i_waypoints[idx-1][1] : y;
- }
-
- unit.UpdateAllowedPositionZ(wanderX, wanderY, z);
-
- //! Positions are fine - apply them to this waypoint
- i_waypoints[idx][0] = wanderX;
- i_waypoints[idx][1] = wanderY;
- i_waypoints[idx][2] = z;
- }
-
- unit.StopMoving();
- unit.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
- unit.AddUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
-}
-
-template<>
-void ConfusedMovementGenerator<Creature>::_InitSpecific(Creature &creature, bool &is_water_ok, bool &is_land_ok)
-{
- is_water_ok = creature.canSwim();
- is_land_ok = creature.canWalk();
-}
-
-template<>
-void ConfusedMovementGenerator<Player>::_InitSpecific(Player &, bool &is_water_ok, bool &is_land_ok)
-{
- is_water_ok = true;
- is_land_ok = true;
+ unit->StopMoving();
+ unit->AddUnitState(UNIT_STATE_CONFUSED_MOVE);
}
template<class T>
-void ConfusedMovementGenerator<T>::DoReset(T &unit)
+void ConfusedMovementGenerator<T>::DoReset(T* unit)
{
- i_nextMove = 1;
i_nextMoveTime.Reset(0);
- unit.StopMoving();
- unit.AddUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
+
+ if (!unit->isAlive() || unit->IsStopped())
+ return;
+
+ unit->StopMoving();
+ unit->AddUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
}
template<class T>
-bool ConfusedMovementGenerator<T>::DoUpdate(T &unit, uint32 diff)
+bool ConfusedMovementGenerator<T>::DoUpdate(T* unit, uint32 diff)
{
- if (unit.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
+ if (unit->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
return true;
if (i_nextMoveTime.Passed())
{
// currently moving, update location
- unit.AddUnitState(UNIT_STATE_CONFUSED_MOVE);
+ unit->AddUnitState(UNIT_STATE_CONFUSED_MOVE);
- if (unit.movespline->Finalized())
- {
- i_nextMove = urand(1, MAX_CONF_WAYPOINTS);
- i_nextMoveTime.Reset(urand(500, 1200)); // Guessed
- }
+ if (unit->movespline->Finalized())
+ i_nextMoveTime.Reset(urand(800, 1500));
}
else
{
@@ -132,14 +77,25 @@ bool ConfusedMovementGenerator<T>::DoUpdate(T &unit, uint32 diff)
if (i_nextMoveTime.Passed())
{
// start moving
- unit.AddUnitState(UNIT_STATE_CONFUSED_MOVE);
+ unit->AddUnitState(UNIT_STATE_CONFUSED_MOVE);
+
+ float dest = 4.0f * (float)rand_norm() - 2.0f;
+
+ Position pos;
+ pos.Relocate(i_x, i_y, i_z);
+ unit->MovePositionToFirstCollision(pos, dest, 0.0f);
+
+ PathGenerator path(unit);
+ path.SetPathLengthLimit(30.0f);
+ bool result = path.CalculatePath(pos.m_positionX, pos.m_positionY, pos.m_positionZ);
+ if (!result || (path.GetPathType() & PATHFIND_NOPATH))
+ {
+ i_nextMoveTime.Reset(100);
+ return true;
+ }
- ASSERT(i_nextMove <= MAX_CONF_WAYPOINTS);
- float x = i_waypoints[i_nextMove][0];
- float y = i_waypoints[i_nextMove][1];
- float z = i_waypoints[i_nextMove][2];
Movement::MoveSplineInit init(unit);
- init.MoveTo(x, y, z);
+ init.MovebyPath(path.GetPath());
init.SetWalk(true);
init.Launch();
}
@@ -149,25 +105,25 @@ bool ConfusedMovementGenerator<T>::DoUpdate(T &unit, uint32 diff)
}
template<>
-void ConfusedMovementGenerator<Player>::DoFinalize(Player &unit)
+void ConfusedMovementGenerator<Player>::DoFinalize(Player* unit)
{
- unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
- unit.ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
+ unit->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
+ unit->ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
+ unit->StopMoving();
}
template<>
-void ConfusedMovementGenerator<Creature>::DoFinalize(Creature &unit)
+void ConfusedMovementGenerator<Creature>::DoFinalize(Creature* unit)
{
- unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
- unit.ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
- if (unit.getVictim())
- unit.SetTarget(unit.getVictim()->GetGUID());
+ unit->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
+ unit->ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
+ if (unit->getVictim())
+ unit->SetTarget(unit->getVictim()->GetGUID());
}
-template void ConfusedMovementGenerator<Player>::DoInitialize(Player &player);
-template void ConfusedMovementGenerator<Creature>::DoInitialize(Creature &creature);
-template void ConfusedMovementGenerator<Player>::DoReset(Player &player);
-template void ConfusedMovementGenerator<Creature>::DoReset(Creature &creature);
-template bool ConfusedMovementGenerator<Player>::DoUpdate(Player &player, uint32 diff);
-template bool ConfusedMovementGenerator<Creature>::DoUpdate(Creature &creature, uint32 diff);
-
+template void ConfusedMovementGenerator<Player>::DoInitialize(Player*);
+template void ConfusedMovementGenerator<Creature>::DoInitialize(Creature*);
+template void ConfusedMovementGenerator<Player>::DoReset(Player*);
+template void ConfusedMovementGenerator<Creature>::DoReset(Creature*);
+template bool ConfusedMovementGenerator<Player>::DoUpdate(Player*, uint32 diff);
+template bool ConfusedMovementGenerator<Creature>::DoUpdate(Creature*, uint32 diff);
diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h
index 20e84f3a97f..da29b8aa12e 100755
--- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h
@@ -22,25 +22,20 @@
#include "MovementGenerator.h"
#include "Timer.h"
-#define MAX_CONF_WAYPOINTS 24 //! Allows a twelve second confusion if i_nextMove always is the absolute minimum timer.
-
template<class T>
class ConfusedMovementGenerator : public MovementGeneratorMedium< T, ConfusedMovementGenerator<T> >
{
public:
explicit ConfusedMovementGenerator() : i_nextMoveTime(0) {}
- void DoInitialize(T &);
- void DoFinalize(T &);
- void DoReset(T &);
- bool DoUpdate(T &, uint32);
+ void DoInitialize(T*);
+ void DoFinalize(T*);
+ void DoReset(T*);
+ bool DoUpdate(T*, uint32);
MovementGeneratorType GetMovementGeneratorType() { return CONFUSED_MOTION_TYPE; }
private:
- void _InitSpecific(T &, bool &, bool &);
TimeTracker i_nextMoveTime;
- float i_waypoints[MAX_CONF_WAYPOINTS+1][3];
- uint32 i_nextMove;
+ float i_x, i_y, i_z;
};
#endif
-
diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
index d9050e2b76a..216fffbfee1 100755..100644
--- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
@@ -20,6 +20,7 @@
#include "CreatureAI.h"
#include "MapManager.h"
#include "FleeingMovementGenerator.h"
+#include "PathGenerator.h"
#include "ObjectAccessor.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
@@ -29,384 +30,163 @@
#define MAX_QUIET_DISTANCE 43.0f
template<class T>
-void FleeingMovementGenerator<T>::_setTargetLocation(T &owner)
+void FleeingMovementGenerator<T>::_setTargetLocation(T* owner)
{
- if (!&owner)
+ if (!owner)
return;
- if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
+ if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
return;
- if (!_setMoveData(owner))
- return;
+ owner->AddUnitState(UNIT_STATE_FLEEING_MOVE);
float x, y, z;
- if (!_getPoint(owner, x, y, z))
- return;
+ _getPoint(owner, x, y, z);
- owner.AddUnitState(UNIT_STATE_FLEEING_MOVE);
+ PathGenerator path(owner);
+ path.SetPathLengthLimit(30.0f);
+ bool result = path.CalculatePath(x, y, z);
+ if (!result || (path.GetPathType() & PATHFIND_NOPATH))
+ {
+ i_nextCheckTime.Reset(100);
+ return;
+ }
Movement::MoveSplineInit init(owner);
- init.MoveTo(x, y, z);
+ init.MovebyPath(path.GetPath());
init.SetWalk(false);
- init.Launch();
+ int32 traveltime = init.Launch();
+ i_nextCheckTime.Reset(traveltime + urand(800, 1500));
}
template<class T>
-bool FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
+void FleeingMovementGenerator<T>::_getPoint(T* owner, float &x, float &y, float &z)
{
- if (!&owner)
- return false;
-
- x = owner.GetPositionX();
- y = owner.GetPositionY();
- z = owner.GetPositionZ();
-
- float temp_x, temp_y, angle;
- const Map* _map = owner.GetBaseMap();
- // primitive path-finding
- for (uint8 i = 0; i < 18; ++i)
+ float dist_from_caster, angle_to_caster;
+ if (Unit* fright = ObjectAccessor::GetUnit(*owner, i_frightGUID))
{
- if (i_only_forward && i > 2)
- break;
-
- float distance = 5.0f;
-
- switch (i)
- {
- case 0:
- angle = i_cur_angle;
- break;
- case 1:
- angle = i_cur_angle;
- distance /= 2;
- break;
- case 2:
- angle = i_cur_angle;
- distance /= 4;
- break;
- case 3:
- angle = i_cur_angle + static_cast<float>(M_PI/4);
- break;
- case 4:
- angle = i_cur_angle - static_cast<float>(M_PI/4);
- break;
- case 5:
- angle = i_cur_angle + static_cast<float>(M_PI/4);
- distance /= 2;
- break;
- case 6:
- angle = i_cur_angle - static_cast<float>(M_PI/4);
- distance /= 2;
- break;
- case 7:
- angle = i_cur_angle + static_cast<float>(M_PI/2);
- break;
- case 8:
- angle = i_cur_angle - static_cast<float>(M_PI/2);
- break;
- case 9:
- angle = i_cur_angle + static_cast<float>(M_PI/2);
- distance /= 2;
- break;
- case 10:
- angle = i_cur_angle - static_cast<float>(M_PI/2);
- distance /= 2;
- break;
- case 11:
- angle = i_cur_angle + static_cast<float>(M_PI/4);
- distance /= 4;
- break;
- case 12:
- angle = i_cur_angle - static_cast<float>(M_PI/4);
- distance /= 4;
- break;
- case 13:
- angle = i_cur_angle + static_cast<float>(M_PI/2);
- distance /= 4;
- break;
- case 14:
- angle = i_cur_angle - static_cast<float>(M_PI/2);
- distance /= 4;
- break;
- case 15:
- angle = i_cur_angle + static_cast<float>(3*M_PI/4);
- distance /= 2;
- break;
- case 16:
- angle = i_cur_angle - static_cast<float>(3*M_PI/4);
- distance /= 2;
- break;
- case 17:
- angle = i_cur_angle + static_cast<float>(M_PI);
- distance /= 2;
- break;
- default:
- angle = 0.0f;
- distance = 0.0f;
- break;
- }
-
- temp_x = x + distance * std::cos(angle);
- temp_y = y + distance * std::sin(angle);
- Trinity::NormalizeMapCoord(temp_x);
- Trinity::NormalizeMapCoord(temp_y);
- if (owner.IsWithinLOS(temp_x, temp_y, z))
- {
- bool is_water_now = _map->IsInWater(x, y, z);
-
- if (is_water_now && _map->IsInWater(temp_x, temp_y, z))
- {
- x = temp_x;
- y = temp_y;
- return true;
- }
- float new_z = _map->GetHeight(owner.GetPhaseMask(), temp_x, temp_y, z, true);
-
- if (new_z <= INVALID_HEIGHT)
- continue;
-
- bool is_water_next = _map->IsInWater(temp_x, temp_y, new_z);
-
- if ((is_water_now && !is_water_next && !is_land_ok) || (!is_water_now && is_water_next && !is_water_ok))
- continue;
-
- if (!(new_z - z) || distance / fabs(new_z - z) > 1.0f)
- {
- float new_z_left = _map->GetHeight(owner.GetPhaseMask(), temp_x + 1.0f * std::cos(angle+static_cast<float>(M_PI/2)), temp_y + 1.0f * std::sin(angle+static_cast<float>(M_PI/2)), z, true);
- float new_z_right = _map->GetHeight(owner.GetPhaseMask(), temp_x + 1.0f * std::cos(angle-static_cast<float>(M_PI/2)), temp_y + 1.0f * std::sin(angle-static_cast<float>(M_PI/2)), z, true);
- if (fabs(new_z_left - new_z) < 1.2f && fabs(new_z_right - new_z) < 1.2f)
- {
- x = temp_x;
- y = temp_y;
- z = new_z;
- return true;
- }
- }
- }
- }
- i_to_distance_from_caster = 0.0f;
- i_nextCheckTime.Reset(urand(500, 1000));
- return false;
-}
-
-template<class T>
-bool FleeingMovementGenerator<T>::_setMoveData(T &owner)
-{
- float cur_dist_xyz = owner.GetDistance(i_caster_x, i_caster_y, i_caster_z);
-
- if (i_to_distance_from_caster > 0.0f)
- {
- if ((i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz < i_to_distance_from_caster) ||
- // if we reach lower distance
- (i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz > i_last_distance_from_caster) ||
- // if we can't be close
- (i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster) ||
- // if we reach bigger distance
- (cur_dist_xyz > MAX_QUIET_DISTANCE) || // if we are too far
- (i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE))
- // if we leave 'quiet zone'
- {
- // we are very far or too close, stopping
- i_to_distance_from_caster = 0.0f;
- i_nextCheckTime.Reset(urand(500, 1000));
- return false;
- }
+ dist_from_caster = fright->GetDistance(owner);
+ if (dist_from_caster > 0.2f)
+ angle_to_caster = fright->GetAngle(owner);
else
- {
- // now we are running, continue
- i_last_distance_from_caster = cur_dist_xyz;
- return true;
- }
- }
-
- float cur_dist;
- float angle_to_caster;
-
- if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
- {
- cur_dist = fright->GetDistance(&owner);
- if (cur_dist < cur_dist_xyz)
- {
- i_caster_x = fright->GetPositionX();
- i_caster_y = fright->GetPositionY();
- i_caster_z = fright->GetPositionZ();
- angle_to_caster = fright->GetAngle(&owner);
- }
- else
- {
- cur_dist = cur_dist_xyz;
- angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + static_cast<float>(M_PI);
- }
+ angle_to_caster = frand(0, 2 * static_cast<float>(M_PI));
}
else
{
- cur_dist = cur_dist_xyz;
- angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + static_cast<float>(M_PI);
+ dist_from_caster = 0.0f;
+ angle_to_caster = frand(0, 2 * static_cast<float>(M_PI));
}
- // if we too close may use 'path-finding' else just stop
- i_only_forward = cur_dist >= MIN_QUIET_DISTANCE/3;
-
- //get angle and 'distance from caster' to run
- float angle;
-
- if (i_cur_angle == 0.0f && i_last_distance_from_caster == 0.0f) //just started, first time
+ float dist, angle;
+ if (dist_from_caster < MIN_QUIET_DISTANCE)
{
- angle = (float)rand_norm()*(1.0f - cur_dist/MIN_QUIET_DISTANCE) * static_cast<float>(M_PI/3) + (float)rand_norm()*static_cast<float>(M_PI*2/3);
- i_to_distance_from_caster = MIN_QUIET_DISTANCE;
- i_only_forward = true;
+ dist = frand(0.4f, 1.3f)*(MIN_QUIET_DISTANCE - dist_from_caster);
+ angle = angle_to_caster + frand(-static_cast<float>(M_PI)/8, static_cast<float>(M_PI)/8);
}
- else if (cur_dist < MIN_QUIET_DISTANCE)
+ else if (dist_from_caster > MAX_QUIET_DISTANCE)
{
- angle = static_cast<float>(M_PI/6) + (float)rand_norm()*static_cast<float>(M_PI*2/3);
- i_to_distance_from_caster = cur_dist*2/3 + (float)rand_norm()*(MIN_QUIET_DISTANCE - cur_dist*2/3);
+ dist = frand(0.4f, 1.0f)*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
+ angle = -angle_to_caster + frand(-static_cast<float>(M_PI)/4, static_cast<float>(M_PI)/4);
}
- else if (cur_dist > MAX_QUIET_DISTANCE)
+ else // we are inside quiet range
{
- angle = (float)rand_norm()*static_cast<float>(M_PI/3) + static_cast<float>(M_PI*2/3);
- i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + (float)rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
+ dist = frand(0.6f, 1.2f)*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
+ angle = frand(0, 2*static_cast<float>(M_PI));
}
- else
- {
- angle = (float)rand_norm()*static_cast<float>(M_PI);
- i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + (float)rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
- }
-
- int8 sign = (float)rand_norm() > 0.5f ? 1 : -1;
- i_cur_angle = sign*angle + angle_to_caster;
- // current distance
- i_last_distance_from_caster = cur_dist;
-
- return true;
+ Position pos;
+ owner->GetFirstCollisionPosition(pos, dist, angle);
+ x = pos.m_positionX;
+ y = pos.m_positionY;
+ z = pos.m_positionZ;
}
template<class T>
-void FleeingMovementGenerator<T>::DoInitialize(T &owner)
+void FleeingMovementGenerator<T>::DoInitialize(T* owner)
{
- if (!&owner)
+ if (!owner)
return;
- owner.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
- owner.AddUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
-
- _Init(owner);
-
- if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
- {
- i_caster_x = fright->GetPositionX();
- i_caster_y = fright->GetPositionY();
- i_caster_z = fright->GetPositionZ();
- }
- else
- {
- i_caster_x = owner.GetPositionX();
- i_caster_y = owner.GetPositionY();
- i_caster_z = owner.GetPositionZ();
- }
-
- i_only_forward = true;
- i_cur_angle = 0.0f;
- i_last_distance_from_caster = 0.0f;
- i_to_distance_from_caster = 0.0f;
+ owner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
+ owner->AddUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE);
_setTargetLocation(owner);
}
template<>
-void FleeingMovementGenerator<Creature>::_Init(Creature &owner)
+void FleeingMovementGenerator<Player>::DoFinalize(Player* owner)
{
- if (!&owner)
- return;
-
- //owner.SetTargetGuid(ObjectGuid());
- is_water_ok = owner.canSwim();
- is_land_ok = owner.canWalk();
+ owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
+ owner->ClearUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE);
+ owner->StopMoving();
}
template<>
-void FleeingMovementGenerator<Player>::_Init(Player &)
+void FleeingMovementGenerator<Creature>::DoFinalize(Creature* owner)
{
- is_water_ok = true;
- is_land_ok = true;
-}
-
-template<>
-void FleeingMovementGenerator<Player>::DoFinalize(Player &owner)
-{
- owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
- owner.ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
- owner.StopMoving();
-}
-
-template<>
-void FleeingMovementGenerator<Creature>::DoFinalize(Creature &owner)
-{
- owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
- owner.ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
- if (owner.getVictim())
- owner.SetTarget(owner.getVictim()->GetGUID());
+ owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
+ owner->ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
+ if (owner->getVictim())
+ owner->SetTarget(owner->getVictim()->GetGUID());
}
template<class T>
-void FleeingMovementGenerator<T>::DoReset(T &owner)
+void FleeingMovementGenerator<T>::DoReset(T* owner)
{
DoInitialize(owner);
}
template<class T>
-bool FleeingMovementGenerator<T>::DoUpdate(T &owner, uint32 time_diff)
+bool FleeingMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
{
- if (!&owner || !owner.isAlive())
+ if (!owner || !owner->isAlive())
return false;
- if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
+
+ if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
{
- owner.ClearUnitState(UNIT_STATE_FLEEING_MOVE);
+ owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE);
return true;
}
i_nextCheckTime.Update(time_diff);
- if (i_nextCheckTime.Passed() && owner.movespline->Finalized())
+ if (i_nextCheckTime.Passed() && owner->movespline->Finalized())
_setTargetLocation(owner);
return true;
}
-template void FleeingMovementGenerator<Player>::DoInitialize(Player &);
-template void FleeingMovementGenerator<Creature>::DoInitialize(Creature &);
-template bool FleeingMovementGenerator<Player>::_setMoveData(Player &);
-template bool FleeingMovementGenerator<Creature>::_setMoveData(Creature &);
-template bool FleeingMovementGenerator<Player>::_getPoint(Player &, float &, float &, float &);
-template bool FleeingMovementGenerator<Creature>::_getPoint(Creature &, float &, float &, float &);
-template void FleeingMovementGenerator<Player>::_setTargetLocation(Player &);
-template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature &);
-template void FleeingMovementGenerator<Player>::DoReset(Player &);
-template void FleeingMovementGenerator<Creature>::DoReset(Creature &);
-template bool FleeingMovementGenerator<Player>::DoUpdate(Player &, uint32);
-template bool FleeingMovementGenerator<Creature>::DoUpdate(Creature &, uint32);
-
-void TimedFleeingMovementGenerator::Finalize(Unit &owner)
+template void FleeingMovementGenerator<Player>::DoInitialize(Player*);
+template void FleeingMovementGenerator<Creature>::DoInitialize(Creature*);
+template void FleeingMovementGenerator<Player>::_getPoint(Player*, float&, float&, float&);
+template void FleeingMovementGenerator<Creature>::_getPoint(Creature*, float&, float&, float&);
+template void FleeingMovementGenerator<Player>::_setTargetLocation(Player*);
+template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature*);
+template void FleeingMovementGenerator<Player>::DoReset(Player*);
+template void FleeingMovementGenerator<Creature>::DoReset(Creature*);
+template bool FleeingMovementGenerator<Player>::DoUpdate(Player*, uint32);
+template bool FleeingMovementGenerator<Creature>::DoUpdate(Creature*, uint32);
+
+void TimedFleeingMovementGenerator::Finalize(Unit* owner)
{
- owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
- owner.ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
- if (Unit* victim = owner.getVictim())
+ owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
+ owner->ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
+ if (Unit* victim = owner->getVictim())
{
- if (owner.isAlive())
+ if (owner->isAlive())
{
- owner.AttackStop();
- owner.ToCreature()->AI()->AttackStart(victim);
+ owner->AttackStop();
+ owner->ToCreature()->AI()->AttackStart(victim);
}
}
}
-bool TimedFleeingMovementGenerator::Update(Unit & owner, uint32 time_diff)
+bool TimedFleeingMovementGenerator::Update(Unit* owner, uint32 time_diff)
{
- if (!owner.isAlive())
+ if (!owner->isAlive())
return false;
- if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
+ if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
{
- owner.ClearUnitState(UNIT_STATE_FLEEING_MOVE);
+ owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE);
return true;
}
@@ -418,4 +198,3 @@ bool TimedFleeingMovementGenerator::Update(Unit & owner, uint32 time_diff)
// This is done instead of casting Unit& to Creature& and call parent method, then we can use Unit directly
return MovementGeneratorMedium< Creature, FleeingMovementGenerator<Creature> >::Update(owner, time_diff);
}
-
diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h
index 8ad165c8206..33a7c705564 100755
--- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h
@@ -27,29 +27,17 @@ class FleeingMovementGenerator : public MovementGeneratorMedium< T, FleeingMovem
public:
FleeingMovementGenerator(uint64 fright) : i_frightGUID(fright), i_nextCheckTime(0) {}
- void DoInitialize(T &);
- void DoFinalize(T &);
- void DoReset(T &);
- bool DoUpdate(T &, uint32);
+ void DoInitialize(T*);
+ void DoFinalize(T*);
+ void DoReset(T*);
+ bool DoUpdate(T*, uint32);
MovementGeneratorType GetMovementGeneratorType() { return FLEEING_MOTION_TYPE; }
private:
- void _setTargetLocation(T &owner);
- bool _getPoint(T &owner, float &x, float &y, float &z);
- bool _setMoveData(T &owner);
- void _Init(T &);
+ void _setTargetLocation(T*);
+ void _getPoint(T*, float &x, float &y, float &z);
- bool is_water_ok :1;
- bool is_land_ok :1;
- bool i_only_forward:1;
-
- float i_caster_x;
- float i_caster_y;
- float i_caster_z;
- float i_last_distance_from_caster;
- float i_to_distance_from_caster;
- float i_cur_angle;
uint64 i_frightGUID;
TimeTracker i_nextCheckTime;
};
@@ -62,12 +50,11 @@ class TimedFleeingMovementGenerator : public FleeingMovementGenerator<Creature>
i_totalFleeTime(time) {}
MovementGeneratorType GetMovementGeneratorType() { return TIMED_FLEEING_MOTION_TYPE; }
- bool Update(Unit &, uint32);
- void Finalize(Unit &);
+ bool Update(Unit*, uint32);
+ void Finalize(Unit*);
private:
TimeTracker i_totalFleeTime;
};
#endif
-
diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
index 4f0a620c303..a94ef5d4f87 100644
--- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
@@ -23,49 +23,50 @@
#include "MoveSplineInit.h"
#include "MoveSpline.h"
-void HomeMovementGenerator<Creature>::DoInitialize(Creature & owner)
+void HomeMovementGenerator<Creature>::DoInitialize(Creature* owner)
{
_setTargetLocation(owner);
}
-void HomeMovementGenerator<Creature>::DoReset(Creature &)
+void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner)
+{
+ if (arrived)
+ {
+ owner->ClearUnitState(UNIT_STATE_EVADE);
+ owner->SetWalk(true);
+ owner->LoadCreaturesAddon(true);
+ owner->AI()->JustReachedHome();
+ }
+}
+
+void HomeMovementGenerator<Creature>::DoReset(Creature*)
{
}
-void HomeMovementGenerator<Creature>::_setTargetLocation(Creature & owner)
+void HomeMovementGenerator<Creature>::_setTargetLocation(Creature* owner)
{
- if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
+ if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
return;
Movement::MoveSplineInit init(owner);
float x, y, z, o;
// at apply we can select more nice return points base at current movegen
- //if (owner.GetMotionMaster()->empty() || !owner.GetMotionMaster()->top()->GetResetPosition(owner, x, y, z))
- //{
- owner.GetHomePosition(x, y, z, o);
- init.SetFacing(o);
- //}
+ if (owner->GetMotionMaster()->empty() || !owner->GetMotionMaster()->top()->GetResetPosition(owner, x, y, z))
+ {
+ owner->GetHomePosition(x, y, z, o);
+ init.SetFacing(o);
+ }
init.MoveTo(x, y, z);
init.SetWalk(false);
init.Launch();
arrived = false;
- owner.ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~UNIT_STATE_EVADE));
-}
-bool HomeMovementGenerator<Creature>::DoUpdate(Creature &owner, const uint32 /*time_diff*/)
-{
- arrived = owner.movespline->Finalized();
- return !arrived;
+ owner->ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~UNIT_STATE_EVADE));
}
-void HomeMovementGenerator<Creature>::DoFinalize(Creature& owner)
+bool HomeMovementGenerator<Creature>::DoUpdate(Creature* owner, const uint32 /*time_diff*/)
{
- if (arrived)
- {
- owner.ClearUnitState(UNIT_STATE_EVADE);
- owner.SetWalk(true);
- owner.LoadCreaturesAddon(true);
- owner.AI()->JustReachedHome();
- }
+ arrived = owner->movespline->Finalized();
+ return !arrived;
}
diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h
index c93241b82db..3d6c6ab18c9 100644
--- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h
@@ -34,15 +34,14 @@ class HomeMovementGenerator<Creature> : public MovementGeneratorMedium< Creature
HomeMovementGenerator() : arrived(false) {}
~HomeMovementGenerator() {}
- void DoInitialize(Creature &);
- void DoFinalize(Creature &);
- void DoReset(Creature &);
- bool DoUpdate(Creature &, const uint32);
+ void DoInitialize(Creature*);
+ void DoFinalize(Creature*);
+ void DoReset(Creature*);
+ bool DoUpdate(Creature*, const uint32);
MovementGeneratorType GetMovementGeneratorType() { return HOME_MOTION_TYPE; }
private:
- void _setTargetLocation(Creature &);
+ void _setTargetLocation(Creature*);
bool arrived;
};
#endif
-
diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp
index c952ad9ba94..81442570940 100755
--- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp
@@ -24,33 +24,33 @@ IdleMovementGenerator si_idleMovement;
// StopMoving is needed to make unit stop if its last movement generator expires
// But it should not be sent otherwise there are many redundent packets
-void IdleMovementGenerator::Initialize(Unit &owner)
+void IdleMovementGenerator::Initialize(Unit* owner)
{
Reset(owner);
}
-void IdleMovementGenerator::Reset(Unit& owner)
+void IdleMovementGenerator::Reset(Unit* owner)
{
- if (!owner.IsStopped())
- owner.StopMoving();
+ if (!owner->IsStopped())
+ owner->StopMoving();
}
-void RotateMovementGenerator::Initialize(Unit& owner)
+void RotateMovementGenerator::Initialize(Unit* owner)
{
- if (!owner.IsStopped())
- owner.StopMoving();
+ if (!owner->IsStopped())
+ owner->StopMoving();
- if (owner.getVictim())
- owner.SetInFront(owner.getVictim());
+ if (owner->getVictim())
+ owner->SetInFront(owner->getVictim());
- owner.AddUnitState(UNIT_STATE_ROTATING);
+ owner->AddUnitState(UNIT_STATE_ROTATING);
- owner.AttackStop();
+ owner->AttackStop();
}
-bool RotateMovementGenerator::Update(Unit& owner, uint32 diff)
+bool RotateMovementGenerator::Update(Unit* owner, uint32 diff)
{
- float angle = owner.GetOrientation();
+ float angle = owner->GetOrientation();
if (m_direction == ROTATE_DIRECTION_LEFT)
{
angle += (float)diff * static_cast<float>(M_PI * 2) / m_maxDuration;
@@ -61,8 +61,8 @@ bool RotateMovementGenerator::Update(Unit& owner, uint32 diff)
angle -= (float)diff * static_cast<float>(M_PI * 2) / m_maxDuration;
while (angle < 0) angle += static_cast<float>(M_PI * 2);
}
- owner.SetOrientation(angle);
- owner.SendMovementFlagUpdate(); // this is a hack. we do not have anything correct to send in the beginning
+ owner->SetOrientation(angle);
+ owner->SendMovementFlagUpdate(); // this is a hack. we do not have anything correct to send in the beginning
if (m_duration > diff)
m_duration -= diff;
@@ -72,24 +72,24 @@ bool RotateMovementGenerator::Update(Unit& owner, uint32 diff)
return true;
}
-void RotateMovementGenerator::Finalize(Unit &unit)
+void RotateMovementGenerator::Finalize(Unit* unit)
{
- unit.ClearUnitState(UNIT_STATE_ROTATING);
- if (unit.GetTypeId() == TYPEID_UNIT)
- unit.ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, 0);
+ unit->ClearUnitState(UNIT_STATE_ROTATING);
+ if (unit->GetTypeId() == TYPEID_UNIT)
+ unit->ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, 0);
}
-void DistractMovementGenerator::Initialize(Unit& owner)
+void DistractMovementGenerator::Initialize(Unit* owner)
{
- owner.AddUnitState(UNIT_STATE_DISTRACTED);
+ owner->AddUnitState(UNIT_STATE_DISTRACTED);
}
-void DistractMovementGenerator::Finalize(Unit& owner)
+void DistractMovementGenerator::Finalize(Unit* owner)
{
- owner.ClearUnitState(UNIT_STATE_DISTRACTED);
+ owner->ClearUnitState(UNIT_STATE_DISTRACTED);
}
-bool DistractMovementGenerator::Update(Unit& /*owner*/, uint32 time_diff)
+bool DistractMovementGenerator::Update(Unit* /*owner*/, uint32 time_diff)
{
if (time_diff > m_timer)
return false;
@@ -98,9 +98,8 @@ bool DistractMovementGenerator::Update(Unit& /*owner*/, uint32 time_diff)
return true;
}
-void AssistanceDistractMovementGenerator::Finalize(Unit &unit)
+void AssistanceDistractMovementGenerator::Finalize(Unit* unit)
{
- unit.ClearUnitState(UNIT_STATE_DISTRACTED);
- unit.ToCreature()->SetReactState(REACT_AGGRESSIVE);
+ unit->ClearUnitState(UNIT_STATE_DISTRACTED);
+ unit->ToCreature()->SetReactState(REACT_AGGRESSIVE);
}
-
diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h
index bbcc2413cae..0043891db2c 100644..100755
--- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h
@@ -25,10 +25,10 @@ class IdleMovementGenerator : public MovementGenerator
{
public:
- void Initialize(Unit &);
- void Finalize(Unit &) { }
- void Reset(Unit &);
- bool Update(Unit &, uint32) { return true; }
+ void Initialize(Unit*);
+ void Finalize(Unit*) { }
+ void Reset(Unit*);
+ bool Update(Unit*, uint32) { return true; }
MovementGeneratorType GetMovementGeneratorType() { return IDLE_MOTION_TYPE; }
};
@@ -39,10 +39,10 @@ class RotateMovementGenerator : public MovementGenerator
public:
explicit RotateMovementGenerator(uint32 time, RotateDirection direction) : m_duration(time), m_maxDuration(time), m_direction(direction) {}
- void Initialize(Unit& owner);
- void Finalize(Unit& owner);
- void Reset(Unit& owner) { Initialize(owner); }
- bool Update(Unit& owner, uint32 time_diff);
+ void Initialize(Unit*);
+ void Finalize(Unit*);
+ void Reset(Unit* owner) { Initialize(owner); }
+ bool Update(Unit*, uint32);
MovementGeneratorType GetMovementGeneratorType() { return ROTATE_MOTION_TYPE; }
private:
@@ -55,10 +55,10 @@ class DistractMovementGenerator : public MovementGenerator
public:
explicit DistractMovementGenerator(uint32 timer) : m_timer(timer) {}
- void Initialize(Unit& owner);
- void Finalize(Unit& owner);
- void Reset(Unit& owner) { Initialize(owner); }
- bool Update(Unit& owner, uint32 time_diff);
+ void Initialize(Unit*);
+ void Finalize(Unit*);
+ void Reset(Unit* owner) { Initialize(owner); }
+ bool Update(Unit*, uint32);
MovementGeneratorType GetMovementGeneratorType() { return DISTRACT_MOTION_TYPE; }
private:
@@ -72,8 +72,7 @@ class AssistanceDistractMovementGenerator : public DistractMovementGenerator
DistractMovementGenerator(timer) {}
MovementGeneratorType GetMovementGeneratorType() { return ASSISTANCE_DISTRACT_MOTION_TYPE; }
- void Finalize(Unit& unit);
+ void Finalize(Unit*);
};
#endif
-
diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp
index 68f62d28899..1f5503948c8 100644..100755
--- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp
@@ -27,111 +27,116 @@
//----- Point Movement Generator
template<class T>
-void PointMovementGenerator<T>::DoInitialize(T &unit)
+void PointMovementGenerator<T>::DoInitialize(T* unit)
{
- if (!unit.IsStopped())
- unit.StopMoving();
+ if (!unit->IsStopped())
+ unit->StopMoving();
+
+ unit->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+
+ if (id == EVENT_CHARGE)
+ return;
- unit.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
- i_recalculateSpeed = false;
Movement::MoveSplineInit init(unit);
- init.MoveTo(i_x, i_y, i_z);
+ init.MoveTo(i_x, i_y, i_z, m_generatePath);
if (speed > 0.0f)
init.SetVelocity(speed);
init.Launch();
}
template<class T>
-bool PointMovementGenerator<T>::DoUpdate(T &unit, uint32 /*diff*/)
+bool PointMovementGenerator<T>::DoUpdate(T* unit, uint32 /*diff*/)
{
- if (!&unit)
+ if (!unit)
return false;
- if (unit.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
+ if (unit->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
{
- unit.ClearUnitState(UNIT_STATE_ROAMING_MOVE);
+ unit->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
return true;
}
- unit.AddUnitState(UNIT_STATE_ROAMING_MOVE);
+ unit->AddUnitState(UNIT_STATE_ROAMING_MOVE);
- if (i_recalculateSpeed && !unit.movespline->Finalized())
+ if (id != EVENT_CHARGE && i_recalculateSpeed && !unit->movespline->Finalized())
{
i_recalculateSpeed = false;
Movement::MoveSplineInit init(unit);
- init.MoveTo(i_x, i_y, i_z);
+ init.MoveTo(i_x, i_y, i_z, m_generatePath);
if (speed > 0.0f) // Default value for point motion type is 0.0, if 0.0 spline will use GetSpeed on unit
init.SetVelocity(speed);
init.Launch();
}
- return !unit.movespline->Finalized();
+ return !unit->movespline->Finalized();
}
template<class T>
-void PointMovementGenerator<T>::DoFinalize(T &unit)
+void PointMovementGenerator<T>::DoFinalize(T* unit)
{
- unit.ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ if (unit->HasUnitState(UNIT_STATE_CHARGING))
+ unit->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
- if (unit.movespline->Finalized())
+ if (unit->movespline->Finalized())
MovementInform(unit);
}
template<class T>
-void PointMovementGenerator<T>::DoReset(T &unit)
+void PointMovementGenerator<T>::DoReset(T* unit)
{
- if (!unit.IsStopped())
- unit.StopMoving();
+ if (!unit->IsStopped())
+ unit->StopMoving();
- unit.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ unit->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
}
template<class T>
-void PointMovementGenerator<T>::MovementInform(T & /*unit*/)
+void PointMovementGenerator<T>::MovementInform(T* /*unit*/)
{
}
-template <> void PointMovementGenerator<Creature>::MovementInform(Creature &unit)
+template <> void PointMovementGenerator<Creature>::MovementInform(Creature* unit)
{
- if (unit.AI())
- unit.AI()->MovementInform(POINT_MOTION_TYPE, id);
+ if (unit->AI())
+ unit->AI()->MovementInform(POINT_MOTION_TYPE, id);
}
-template void PointMovementGenerator<Player>::DoInitialize(Player&);
-template void PointMovementGenerator<Creature>::DoInitialize(Creature&);
-template void PointMovementGenerator<Player>::DoFinalize(Player&);
-template void PointMovementGenerator<Creature>::DoFinalize(Creature&);
-template void PointMovementGenerator<Player>::DoReset(Player&);
-template void PointMovementGenerator<Creature>::DoReset(Creature&);
-template bool PointMovementGenerator<Player>::DoUpdate(Player &, uint32);
-template bool PointMovementGenerator<Creature>::DoUpdate(Creature&, uint32);
+template void PointMovementGenerator<Player>::DoInitialize(Player*);
+template void PointMovementGenerator<Creature>::DoInitialize(Creature*);
+template void PointMovementGenerator<Player>::DoFinalize(Player*);
+template void PointMovementGenerator<Creature>::DoFinalize(Creature*);
+template void PointMovementGenerator<Player>::DoReset(Player*);
+template void PointMovementGenerator<Creature>::DoReset(Creature*);
+template bool PointMovementGenerator<Player>::DoUpdate(Player*, uint32);
+template bool PointMovementGenerator<Creature>::DoUpdate(Creature*, uint32);
-void AssistanceMovementGenerator::Finalize(Unit &unit)
+void AssistanceMovementGenerator::Finalize(Unit* unit)
{
- unit.ToCreature()->SetNoCallAssistance(false);
- unit.ToCreature()->CallAssistance();
- if (unit.isAlive())
- unit.GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY));
+ unit->ToCreature()->SetNoCallAssistance(false);
+ unit->ToCreature()->CallAssistance();
+ if (unit->isAlive())
+ unit->GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY));
}
-bool EffectMovementGenerator::Update(Unit &unit, uint32)
+bool EffectMovementGenerator::Update(Unit* unit, uint32)
{
- return !unit.movespline->Finalized();
+ return !unit->movespline->Finalized();
}
-void EffectMovementGenerator::Finalize(Unit &unit)
+void EffectMovementGenerator::Finalize(Unit* unit)
{
- if (unit.GetTypeId() != TYPEID_UNIT)
+ if (unit->GetTypeId() != TYPEID_UNIT)
return;
- if (((Creature&)unit).AI())
- ((Creature&)unit).AI()->MovementInform(EFFECT_MOTION_TYPE, m_Id);
// Need restore previous movement since we have no proper states system
- //if (unit.isAlive() && !unit.HasUnitState(UNIT_STATE_CONFUSED|UNIT_STATE_FLEEING))
- //{
- // if (Unit* victim = unit.getVictim())
- // unit.GetMotionMaster()->MoveChase(victim);
- // else
- // unit.GetMotionMaster()->Initialize();
- //}
+ if (unit->isAlive() && !unit->HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_FLEEING))
+ {
+ if (Unit* victim = unit->getVictim())
+ unit->GetMotionMaster()->MoveChase(victim);
+ else
+ unit->GetMotionMaster()->Initialize();
+ }
+
+ if (unit->ToCreature()->AI())
+ unit->ToCreature()->AI()->MovementInform(EFFECT_MOTION_TYPE, m_Id);
}
diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h
index f9a51d0c5f3..421736ca4ec 100644
--- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h
@@ -26,25 +26,26 @@ template<class T>
class PointMovementGenerator : public MovementGeneratorMedium< T, PointMovementGenerator<T> >
{
public:
- PointMovementGenerator(uint32 _id, float _x, float _y, float _z, float _speed = 0.0f) : id(_id),
- i_x(_x), i_y(_y), i_z(_z), speed(_speed) {}
+ PointMovementGenerator(uint32 _id, float _x, float _y, float _z, bool _generatePath, float _speed = 0.0f) : id(_id),
+ i_x(_x), i_y(_y), i_z(_z), speed(_speed), m_generatePath(_generatePath), i_recalculateSpeed(false) {}
- void DoInitialize(T &);
- void DoFinalize(T &);
- void DoReset(T &);
- bool DoUpdate(T &, uint32);
+ void DoInitialize(T*);
+ void DoFinalize(T*);
+ void DoReset(T*);
+ bool DoUpdate(T*, uint32);
- void MovementInform(T &);
+ void MovementInform(T*);
void unitSpeedChanged() { i_recalculateSpeed = true; }
MovementGeneratorType GetMovementGeneratorType() { return POINT_MOTION_TYPE; }
- bool GetDestination(float& x, float& y, float& z) const { x=i_x; y=i_y; z=i_z; return true; }
+ void GetDestination(float& x, float& y, float& z) const { x = i_x; y = i_y; z = i_z; }
private:
uint32 id;
float i_x, i_y, i_z;
float speed;
+ bool m_generatePath;
bool i_recalculateSpeed;
};
@@ -52,10 +53,10 @@ class AssistanceMovementGenerator : public PointMovementGenerator<Creature>
{
public:
AssistanceMovementGenerator(float _x, float _y, float _z) :
- PointMovementGenerator<Creature>(0, _x, _y, _z) {}
+ PointMovementGenerator<Creature>(0, _x, _y, _z, true) {}
MovementGeneratorType GetMovementGeneratorType() { return ASSISTANCE_MOTION_TYPE; }
- void Finalize(Unit &);
+ void Finalize(Unit*);
};
// Does almost nothing - just doesn't allows previous movegen interrupt current effect.
@@ -63,14 +64,13 @@ class EffectMovementGenerator : public MovementGenerator
{
public:
explicit EffectMovementGenerator(uint32 Id) : m_Id(Id) {}
- void Initialize(Unit &) {}
- void Finalize(Unit &unit);
- void Reset(Unit &) {}
- bool Update(Unit &u, uint32);
+ void Initialize(Unit*) {}
+ void Finalize(Unit*);
+ void Reset(Unit*) {}
+ bool Update(Unit*, uint32);
MovementGeneratorType GetMovementGeneratorType() { return EFFECT_MOTION_TYPE; }
private:
uint32 m_Id;
};
#endif
-
diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
index 94819e87213..723b0748494 100644
--- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
@@ -33,16 +33,16 @@
#endif
template<>
-void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
+void RandomMovementGenerator<Creature>::_setRandomLocation(Creature* creature)
{
float respX, respY, respZ, respO, destX, destY, destZ, travelDistZ;
- creature.GetHomePosition(respX, respY, respZ, respO);
- Map const* map = creature.GetBaseMap();
+ creature->GetHomePosition(respX, respY, respZ, respO);
+ Map const* map = creature->GetBaseMap();
// For 2D/3D system selection
//bool is_land_ok = creature.CanWalk(); // not used?
//bool is_water_ok = creature.CanSwim(); // not used?
- bool is_air_ok = creature.CanFly();
+ bool is_air_ok = creature->CanFly();
const float angle = float(rand_norm()) * static_cast<float>(M_PI*2.0f);
const float range = float(rand_norm()) * wander_distance;
@@ -77,17 +77,17 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
// The fastest way to get an accurate result 90% of the time.
// Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
- destZ = map->GetHeight(creature.GetPhaseMask(), destX, destY, respZ+travelDistZ-2.0f, false);
+ destZ = map->GetHeight(creature->GetPhaseMask(), destX, destY, respZ+travelDistZ-2.0f, false);
if (fabs(destZ - respZ) > travelDistZ) // Map check
{
// Vmap Horizontal or above
- destZ = map->GetHeight(creature.GetPhaseMask(), destX, destY, respZ - 2.0f, true);
+ destZ = map->GetHeight(creature->GetPhaseMask(), destX, destY, respZ - 2.0f, true);
if (fabs(destZ - respZ) > travelDistZ)
{
// Vmap Higher
- destZ = map->GetHeight(creature.GetPhaseMask(), destX, destY, respZ+travelDistZ-2.0f, true);
+ destZ = map->GetHeight(creature->GetPhaseMask(), destX, destY, respZ+travelDistZ-2.0f, true);
// let's forget this bad coords where a z cannot be find and retry at next tick
if (fabs(destZ - respZ) > travelDistZ)
@@ -101,7 +101,7 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
else
i_nextMoveTime.Reset(urand(500, 10000));
- creature.AddUnitState(UNIT_STATE_ROAMING_MOVE);
+ creature->AddUnitState(UNIT_STATE_ROAMING_MOVE);
Movement::MoveSplineInit init(creature);
init.MoveTo(destX, destY, destZ);
@@ -109,47 +109,47 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
init.Launch();
//Call for creature group update
- if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature)
- creature.GetFormation()->LeaderMoveTo(destX, destY, destZ);
+ if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature)
+ creature->GetFormation()->LeaderMoveTo(destX, destY, destZ);
}
template<>
-void RandomMovementGenerator<Creature>::DoInitialize(Creature &creature)
+void RandomMovementGenerator<Creature>::DoInitialize(Creature* creature)
{
- if (!creature.isAlive())
+ if (!creature->isAlive())
return;
if (!wander_distance)
- wander_distance = creature.GetRespawnRadius();
+ wander_distance = creature->GetRespawnRadius();
- creature.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ creature->AddUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
_setRandomLocation(creature);
}
template<>
-void RandomMovementGenerator<Creature>::DoReset(Creature &creature)
+void RandomMovementGenerator<Creature>::DoReset(Creature* creature)
{
DoInitialize(creature);
}
template<>
-void RandomMovementGenerator<Creature>::DoFinalize(Creature &creature)
+void RandomMovementGenerator<Creature>::DoFinalize(Creature* creature)
{
- creature.ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
- creature.SetWalk(false);
+ creature->ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ creature->SetWalk(false);
}
template<>
-bool RandomMovementGenerator<Creature>::DoUpdate(Creature &creature, const uint32 diff)
+bool RandomMovementGenerator<Creature>::DoUpdate(Creature* creature, const uint32 diff)
{
- if (creature.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
+ if (creature->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
{
i_nextMoveTime.Reset(0); // Expire the timer
- creature.ClearUnitState(UNIT_STATE_ROAMING_MOVE);
+ creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
return true;
}
- if (creature.movespline->Finalized())
+ if (creature->movespline->Finalized())
{
i_nextMoveTime.Update(diff);
if (i_nextMoveTime.Passed())
@@ -159,14 +159,14 @@ bool RandomMovementGenerator<Creature>::DoUpdate(Creature &creature, const uint3
}
template<>
-bool RandomMovementGenerator<Creature>::GetResetPosition(Creature &creature, float& x, float& y, float& z)
+bool RandomMovementGenerator<Creature>::GetResetPos(Creature* creature, float& x, float& y, float& z)
{
float radius;
- creature.GetRespawnPosition(x, y, z, NULL, &radius);
+ creature->GetRespawnPosition(x, y, z, NULL, &radius);
// use current if in range
- if (creature.IsWithinDist2d(x, y, radius))
- creature.GetPosition(x, y, z);
+ if (creature->IsWithinDist2d(x, y, radius))
+ creature->GetPosition(x, y, z);
return true;
}
diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
index 3e74753bc91..a6159e995fe 100644
--- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
@@ -27,12 +27,12 @@ class RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovemen
public:
RandomMovementGenerator(float spawn_dist = 0.0f) : i_nextMoveTime(0), wander_distance(spawn_dist) {}
- void _setRandomLocation(T &);
- void DoInitialize(T &);
- void DoFinalize(T &);
- void DoReset(T &);
- bool DoUpdate(T &, const uint32);
- bool GetResetPosition(T&, float& x, float& y, float& z);
+ void _setRandomLocation(T*);
+ void DoInitialize(T*);
+ void DoFinalize(T*);
+ void DoReset(T*);
+ bool DoUpdate(T*, const uint32);
+ bool GetResetPos(T*, float& x, float& y, float& z);
MovementGeneratorType GetMovementGeneratorType() { return RANDOM_MOTION_TYPE; }
private:
TimeTrackerSmall i_nextMoveTime;
@@ -41,4 +41,3 @@ class RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovemen
float wander_distance;
};
#endif
-
diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
index c1a4c5f70a3..abb4ac9964b 100755
--- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
@@ -26,89 +26,87 @@
#include "MoveSpline.h"
#include "Player.h"
-#include <cmath>
-
template<class T, typename D>
-void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T &owner)
+void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool updateDestination)
{
if (!i_target.isValid() || !i_target->IsInWorld())
return;
- if (owner.HasUnitState(UNIT_STATE_NOT_MOVE))
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE))
+ return;
+
+ if (owner->GetTypeId() == TYPEID_UNIT && !i_target->isInAccessiblePlaceFor(owner->ToCreature()))
return;
float x, y, z;
- //! Following block of code deleted by MrSmite in issue 4891
- //! Code kept for learning and diagnostical purposes
-//
-// if (i_offset && i_target->IsWithinDistInMap(&owner, 2*i_offset))
-// {
-// if (!owner.movespline->Finalized())
-// return;
-//
-// owner.GetPosition(x, y, z);
-// }
-// else
- if (!i_offset)
- {
- if (i_target->IsWithinMeleeRange(&owner))
- return;
- // to nearest random contact position
- i_target->GetRandomContactPoint(&owner, x, y, z, 0, MELEE_RANGE - 0.5f);
- }
- else
+ if (updateDestination || !i_path)
{
- float dist;
- float size;
-
- // Pets need special handling.
- // We need to subtract GetObjectSize() because it gets added back further down the chain
- // and that makes pets too far away. Subtracting it allows pets to properly
- // be (GetCombatReach() + i_offset) away.
- // Only applies when i_target is pet's owner otherwise pets and mobs end up
- // doing a "dance" while fighting
- if (owner.isPet() && i_target->GetTypeId() == TYPEID_PLAYER)
+ if (!i_offset)
{
- dist = i_target->GetCombatReach();
- size = i_target->GetCombatReach() - i_target->GetObjectSize();
+ // to nearest contact position
+ i_target->GetContactPoint(owner, x, y, z);
}
else
{
- dist = i_offset + 1.0f;
- size = owner.GetObjectSize();
+ float dist;
+ float size;
+
+ // Pets need special handling.
+ // We need to subtract GetObjectSize() because it gets added back further down the chain
+ // and that makes pets too far away. Subtracting it allows pets to properly
+ // be (GetCombatReach() + i_offset) away.
+ // Only applies when i_target is pet's owner otherwise pets and mobs end up
+ // doing a "dance" while fighting
+ if (owner->isPet() && i_target->GetTypeId() == TYPEID_PLAYER)
+ {
+ dist = i_target->GetCombatReach();
+ size = i_target->GetCombatReach() - i_target->GetObjectSize();
+ }
+ else
+ {
+ dist = i_offset + 1.0f;
+ size = owner->GetObjectSize();
+ }
+
+ if (i_target->IsWithinDistInMap(owner, dist))
+ return;
+
+ // to at i_offset distance from target and i_angle from target facing
+ i_target->GetClosePoint(x, y, z, size, i_offset, i_angle);
}
+ }
+ else
+ {
+ // the destination has not changed, we just need to refresh the path (usually speed change)
+ G3D::Vector3 end = i_path->GetEndPosition();
+ x = end.x;
+ y = end.y;
+ z = end.z;
+ }
- if (i_target->IsWithinDistInMap(&owner, dist))
- return;
+ if (!i_path)
+ i_path = new PathGenerator(owner);
- // to at i_offset distance from target and i_angle from target facing
- i_target->GetClosePoint(x, y, z, size, i_offset, i_angle);
- }
+ // allow pets to use shortcut if no path found when following their master
+ bool forceDest = (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->isPet()
+ && owner->HasUnitState(UNIT_STATE_FOLLOW));
- /*
- We MUST not check the distance difference and avoid setting the new location for smaller distances.
- By that we risk having far too many GetContactPoint() calls freezing the whole system.
- In TargetedMovementGenerator<T>::Update() we check the distance to the target and at
- some range we calculate a new position. The calculation takes some processor cycles due to vmaps.
- If the distance to the target it too large to ignore,
- but the distance to the new contact point is short enough to be ignored,
- we will calculate a new contact point each update loop, but will never move to it.
- The system will freeze.
- ralf
-
- //We don't update Mob Movement, if the difference between New destination and last destination is < BothObjectSize
- float bothObjectSize = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + CONTACT_DISTANCE;
- if ( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x, y, z) < bothObjectSize )
- return;
- */
+ bool result = i_path->CalculatePath(x, y, z, forceDest);
+ if (!result || (i_path->GetPathType() & PATHFIND_NOPATH))
+ {
+ // Cant reach target
+ i_recalculateTravel = true;
+ return;
+ }
D::_addUnitStateMove(owner);
i_targetReached = false;
i_recalculateTravel = false;
+ owner->AddUnitState(UNIT_STATE_CHASE);
Movement::MoveSplineInit init(owner);
- init.MoveTo(x, y, z);
+ init.MovebyPath(i_path->GetPath());
init.SetWalk(((D*)this)->EnableWalking());
// Using the same condition for facing target as the one that is used for SetInFront on movement end
// - applies to ChaseMovementGenerator mostly
@@ -118,52 +116,26 @@ void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T &owner)
init.Launch();
}
-template<>
-void TargetedMovementGeneratorMedium<Player, ChaseMovementGenerator<Player> >::UpdateFinalDistance(float /*fDistance*/)
-{
- // nothing to do for Player
-}
-
-template<>
-void TargetedMovementGeneratorMedium<Player, FollowMovementGenerator<Player> >::UpdateFinalDistance(float /*fDistance*/)
-{
- // nothing to do for Player
-}
-
-template<>
-void TargetedMovementGeneratorMedium<Creature, ChaseMovementGenerator<Creature> >::UpdateFinalDistance(float fDistance)
-{
- i_offset = fDistance;
- i_recalculateTravel = true;
-}
-
-template<>
-void TargetedMovementGeneratorMedium<Creature, FollowMovementGenerator<Creature> >::UpdateFinalDistance(float fDistance)
-{
- i_offset = fDistance;
- i_recalculateTravel = true;
-}
-
template<class T, typename D>
-bool TargetedMovementGeneratorMedium<T, D>::DoUpdate(T &owner, uint32 time_diff)
+bool TargetedMovementGeneratorMedium<T,D>::DoUpdate(T* owner, uint32 time_diff)
{
if (!i_target.isValid() || !i_target->IsInWorld())
return false;
- if (!owner.isAlive())
- return true;
+ if (!owner || !owner->isAlive())
+ return false;
- if (owner.HasUnitState(UNIT_STATE_NOT_MOVE))
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE))
{
D::_clearUnitStateMove(owner);
return true;
}
// prevent movement while casting spells with cast time or channel time
- if (owner.HasUnitState(UNIT_STATE_CASTING))
+ if (owner->HasUnitState(UNIT_STATE_CASTING))
{
- if (!owner.IsStopped())
- owner.StopMoving();
+ if (!owner->IsStopped())
+ owner->StopMoving();
return true;
}
@@ -174,22 +146,29 @@ bool TargetedMovementGeneratorMedium<T, D>::DoUpdate(T &owner, uint32 time_diff)
return true;
}
+ bool targetMoved = false;
i_recheckDistance.Update(time_diff);
if (i_recheckDistance.Passed())
{
- i_recheckDistance.Reset(50);
+ i_recheckDistance.Reset(100);
//More distance let have better performance, less distance let have more sensitive reaction at target move.
- float allowed_dist = i_target->GetObjectSize() + owner.GetObjectSize() + MELEE_RANGE - 0.5f;
- float dist = (owner.movespline->FinalDestination() - G3D::Vector3(i_target->GetPositionX(), i_target->GetPositionY(), i_target->GetPositionZ())).squaredLength();
- if (dist >= allowed_dist * allowed_dist)
- _setTargetLocation(owner);
+ float allowed_dist = owner->GetCombatReach() + sWorld->getRate(RATE_TARGET_POS_RECALCULATION_RANGE);
+ G3D::Vector3 dest = owner->movespline->FinalDestination();
+
+ if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->CanFly())
+ targetMoved = !i_target->IsWithinDist3d(dest.x, dest.y, dest.z, allowed_dist);
+ else
+ targetMoved = !i_target->IsWithinDist2d(dest.x, dest.y, allowed_dist);
}
- if (owner.movespline->Finalized())
+ if (i_recalculateTravel || targetMoved)
+ _setTargetLocation(owner, targetMoved);
+
+ if (owner->movespline->Finalized())
{
static_cast<D*>(this)->MovementInform(owner);
- if (i_angle == 0.f && !owner.HasInArc(0.01f, i_target.getTarget()))
- owner.SetInFront(i_target.getTarget());
+ if (i_angle == 0.f && !owner->HasInArc(0.01f, i_target.getTarget()))
+ owner->SetInFront(i_target.getTarget());
if (!i_targetReached)
{
@@ -197,60 +176,56 @@ bool TargetedMovementGeneratorMedium<T, D>::DoUpdate(T &owner, uint32 time_diff)
static_cast<D*>(this)->_reachTarget(owner);
}
}
- else
- {
- if (i_recalculateTravel)
- _setTargetLocation(owner);
- }
+
return true;
}
//-----------------------------------------------//
template<class T>
-void ChaseMovementGenerator<T>::_reachTarget(T &owner)
+void ChaseMovementGenerator<T>::_reachTarget(T* owner)
{
- if (owner.IsWithinMeleeRange(this->i_target.getTarget()))
- owner.Attack(this->i_target.getTarget(), true);
+ if (owner->IsWithinMeleeRange(this->i_target.getTarget()))
+ owner->Attack(this->i_target.getTarget(),true);
}
template<>
-void ChaseMovementGenerator<Player>::DoInitialize(Player &owner)
+void ChaseMovementGenerator<Player>::DoInitialize(Player* owner)
{
- owner.AddUnitState(UNIT_STATE_CHASE|UNIT_STATE_CHASE_MOVE);
- _setTargetLocation(owner);
+ owner->AddUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE);
+ _setTargetLocation(owner, true);
}
template<>
-void ChaseMovementGenerator<Creature>::DoInitialize(Creature &owner)
+void ChaseMovementGenerator<Creature>::DoInitialize(Creature* owner)
{
- owner.SetWalk(false);
- owner.AddUnitState(UNIT_STATE_CHASE|UNIT_STATE_CHASE_MOVE);
- _setTargetLocation(owner);
+ owner->SetWalk(false);
+ owner->AddUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE);
+ _setTargetLocation(owner, true);
}
template<class T>
-void ChaseMovementGenerator<T>::DoFinalize(T &owner)
+void ChaseMovementGenerator<T>::DoFinalize(T* owner)
{
- owner.ClearUnitState(UNIT_STATE_CHASE|UNIT_STATE_CHASE_MOVE);
+ owner->ClearUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE);
}
template<class T>
-void ChaseMovementGenerator<T>::DoReset(T &owner)
+void ChaseMovementGenerator<T>::DoReset(T* owner)
{
DoInitialize(owner);
}
template<class T>
-void ChaseMovementGenerator<T>::MovementInform(T & /*unit*/)
+void ChaseMovementGenerator<T>::MovementInform(T* /*unit*/)
{
}
template<>
-void ChaseMovementGenerator<Creature>::MovementInform(Creature &unit)
+void ChaseMovementGenerator<Creature>::MovementInform(Creature* unit)
{
// Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
- if (unit.AI())
- unit.AI()->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
+ if (unit->AI())
+ unit->AI()->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
}
//-----------------------------------------------//
@@ -267,85 +242,86 @@ bool FollowMovementGenerator<Player>::EnableWalking() const
}
template<>
-void FollowMovementGenerator<Player>::_updateSpeed(Player &/*u*/)
+void FollowMovementGenerator<Player>::_updateSpeed(Player* /*owner*/)
{
// nothing to do for Player
}
template<>
-void FollowMovementGenerator<Creature>::_updateSpeed(Creature &u)
+void FollowMovementGenerator<Creature>::_updateSpeed(Creature* owner)
{
// pet only sync speed with owner
- if (!((Creature&)u).isPet() || !i_target.isValid() || i_target->GetGUID() != u.GetOwnerGUID())
+ /// Make sure we are not in the process of a map change (IsInWorld)
+ if (!owner->isPet() || !owner->IsInWorld() || !i_target.isValid() || i_target->GetGUID() != owner->GetOwnerGUID())
return;
- u.UpdateSpeed(MOVE_RUN, true);
- u.UpdateSpeed(MOVE_WALK, true);
- u.UpdateSpeed(MOVE_SWIM, true);
+ owner->UpdateSpeed(MOVE_RUN, true);
+ owner->UpdateSpeed(MOVE_WALK, true);
+ owner->UpdateSpeed(MOVE_SWIM, true);
}
template<>
-void FollowMovementGenerator<Player>::DoInitialize(Player &owner)
+void FollowMovementGenerator<Player>::DoInitialize(Player* owner)
{
- owner.AddUnitState(UNIT_STATE_FOLLOW|UNIT_STATE_FOLLOW_MOVE);
+ owner->AddUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE);
_updateSpeed(owner);
- _setTargetLocation(owner);
+ _setTargetLocation(owner, true);
}
template<>
-void FollowMovementGenerator<Creature>::DoInitialize(Creature &owner)
+void FollowMovementGenerator<Creature>::DoInitialize(Creature* owner)
{
- owner.AddUnitState(UNIT_STATE_FOLLOW|UNIT_STATE_FOLLOW_MOVE);
+ owner->AddUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE);
_updateSpeed(owner);
- _setTargetLocation(owner);
+ _setTargetLocation(owner, true);
}
template<class T>
-void FollowMovementGenerator<T>::DoFinalize(T &owner)
+void FollowMovementGenerator<T>::DoFinalize(T* owner)
{
- owner.ClearUnitState(UNIT_STATE_FOLLOW|UNIT_STATE_FOLLOW_MOVE);
+ owner->ClearUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE);
_updateSpeed(owner);
}
template<class T>
-void FollowMovementGenerator<T>::DoReset(T &owner)
+void FollowMovementGenerator<T>::DoReset(T* owner)
{
DoInitialize(owner);
}
template<class T>
-void FollowMovementGenerator<T>::MovementInform(T & /*unit*/)
+void FollowMovementGenerator<T>::MovementInform(T* /*unit*/)
{
}
template<>
-void FollowMovementGenerator<Creature>::MovementInform(Creature &unit)
+void FollowMovementGenerator<Creature>::MovementInform(Creature* unit)
{
// Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
- if (unit.AI())
- unit.AI()->MovementInform(FOLLOW_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
+ if (unit->AI())
+ unit->AI()->MovementInform(FOLLOW_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
}
//-----------------------------------------------//
-template void TargetedMovementGeneratorMedium<Player, ChaseMovementGenerator<Player> >::_setTargetLocation(Player &);
-template void TargetedMovementGeneratorMedium<Player, FollowMovementGenerator<Player> >::_setTargetLocation(Player &);
-template void TargetedMovementGeneratorMedium<Creature, ChaseMovementGenerator<Creature> >::_setTargetLocation(Creature &);
-template void TargetedMovementGeneratorMedium<Creature, FollowMovementGenerator<Creature> >::_setTargetLocation(Creature &);
-template bool TargetedMovementGeneratorMedium<Player, ChaseMovementGenerator<Player> >::DoUpdate(Player &, uint32);
-template bool TargetedMovementGeneratorMedium<Player, FollowMovementGenerator<Player> >::DoUpdate(Player &, uint32);
-template bool TargetedMovementGeneratorMedium<Creature, ChaseMovementGenerator<Creature> >::DoUpdate(Creature &, uint32);
-template bool TargetedMovementGeneratorMedium<Creature, FollowMovementGenerator<Creature> >::DoUpdate(Creature &, uint32);
-
-template void ChaseMovementGenerator<Player>::_reachTarget(Player &);
-template void ChaseMovementGenerator<Creature>::_reachTarget(Creature &);
-template void ChaseMovementGenerator<Player>::DoFinalize(Player &);
-template void ChaseMovementGenerator<Creature>::DoFinalize(Creature &);
-template void ChaseMovementGenerator<Player>::DoReset(Player &);
-template void ChaseMovementGenerator<Creature>::DoReset(Creature &);
-template void ChaseMovementGenerator<Player>::MovementInform(Player &unit);
-
-template void FollowMovementGenerator<Player>::DoFinalize(Player &);
-template void FollowMovementGenerator<Creature>::DoFinalize(Creature &);
-template void FollowMovementGenerator<Player>::DoReset(Player &);
-template void FollowMovementGenerator<Creature>::DoReset(Creature &);
-template void FollowMovementGenerator<Player>::MovementInform(Player &unit);
+template void TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::_setTargetLocation(Player*, bool);
+template void TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::_setTargetLocation(Player*, bool);
+template void TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::_setTargetLocation(Creature*, bool);
+template void TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::_setTargetLocation(Creature*, bool);
+template bool TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::DoUpdate(Player*, uint32);
+template bool TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::DoUpdate(Player*, uint32);
+template bool TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::DoUpdate(Creature*, uint32);
+template bool TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::DoUpdate(Creature*, uint32);
+
+template void ChaseMovementGenerator<Player>::_reachTarget(Player*);
+template void ChaseMovementGenerator<Creature>::_reachTarget(Creature*);
+template void ChaseMovementGenerator<Player>::DoFinalize(Player*);
+template void ChaseMovementGenerator<Creature>::DoFinalize(Creature*);
+template void ChaseMovementGenerator<Player>::DoReset(Player*);
+template void ChaseMovementGenerator<Creature>::DoReset(Creature*);
+template void ChaseMovementGenerator<Player>::MovementInform(Player*);
+
+template void FollowMovementGenerator<Player>::DoFinalize(Player*);
+template void FollowMovementGenerator<Creature>::DoFinalize(Creature*);
+template void FollowMovementGenerator<Player>::DoReset(Player*);
+template void FollowMovementGenerator<Creature>::DoReset(Creature*);
+template void FollowMovementGenerator<Player>::MovementInform(Player*);
diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h
index 4105668838d..3edeb348d54 100755
--- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h
@@ -23,11 +23,12 @@
#include "FollowerReference.h"
#include "Timer.h"
#include "Unit.h"
+#include "PathGenerator.h"
class TargetedMovementGeneratorBase
{
public:
- TargetedMovementGeneratorBase(Unit &target) { i_target.link(&target, this); }
+ TargetedMovementGeneratorBase(Unit* target) { i_target.link(target, this); }
void stopFollowing() { }
protected:
FollowerReference i_target;
@@ -37,24 +38,24 @@ template<class T, typename D>
class TargetedMovementGeneratorMedium : public MovementGeneratorMedium< T, D >, public TargetedMovementGeneratorBase
{
protected:
- TargetedMovementGeneratorMedium(Unit &target, float offset, float angle) :
- TargetedMovementGeneratorBase(target), i_recheckDistance(0),
- i_offset(offset), i_angle(angle),
+ TargetedMovementGeneratorMedium(Unit* target, float offset, float angle) :
+ TargetedMovementGeneratorBase(target), i_path(NULL),
+ i_recheckDistance(0), i_offset(offset), i_angle(angle),
i_recalculateTravel(false), i_targetReached(false)
{
}
- ~TargetedMovementGeneratorMedium() {}
+ ~TargetedMovementGeneratorMedium() { delete i_path; }
public:
- bool DoUpdate(T &, uint32);
+ bool DoUpdate(T*, uint32);
Unit* GetTarget() const { return i_target.getTarget(); }
- void unitSpeedChanged() { i_recalculateTravel=true; }
- void UpdateFinalDistance(float fDistance);
-
+ void unitSpeedChanged() { i_recalculateTravel = true; }
+ bool IsReachable() const { return (i_path) ? (i_path->GetPathType() & PATHFIND_NORMAL) : true; }
protected:
- void _setTargetLocation(T &);
+ void _setTargetLocation(T* owner, bool updateDestination);
+ PathGenerator* i_path;
TimeTrackerSmall i_recheckDistance;
float i_offset;
float i_angle;
@@ -66,50 +67,50 @@ template<class T>
class ChaseMovementGenerator : public TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >
{
public:
- ChaseMovementGenerator(Unit &target)
+ ChaseMovementGenerator(Unit* target)
: TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target) {}
- ChaseMovementGenerator(Unit &target, float offset, float angle)
+ ChaseMovementGenerator(Unit* target, float offset, float angle)
: TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target, offset, angle) {}
~ChaseMovementGenerator() {}
MovementGeneratorType GetMovementGeneratorType() { return CHASE_MOTION_TYPE; }
- void DoInitialize(T &);
- void DoFinalize(T &);
- void DoReset(T &);
- void MovementInform(T &);
+ void DoInitialize(T*);
+ void DoFinalize(T*);
+ void DoReset(T*);
+ void MovementInform(T*);
- static void _clearUnitStateMove(T &u) { u.ClearUnitState(UNIT_STATE_CHASE_MOVE); }
- static void _addUnitStateMove(T &u) { u.AddUnitState(UNIT_STATE_CHASE_MOVE); }
+ static void _clearUnitStateMove(T* u) { u->ClearUnitState(UNIT_STATE_CHASE_MOVE); }
+ static void _addUnitStateMove(T* u) { u->AddUnitState(UNIT_STATE_CHASE_MOVE); }
bool EnableWalking() const { return false;}
- bool _lostTarget(T &u) const { return u.getVictim() != this->GetTarget(); }
- void _reachTarget(T &);
+ bool _lostTarget(T* u) const { return u->getVictim() != this->GetTarget(); }
+ void _reachTarget(T*);
};
template<class T>
class FollowMovementGenerator : public TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >
{
public:
- FollowMovementGenerator(Unit &target)
+ FollowMovementGenerator(Unit* target)
: TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >(target){}
- FollowMovementGenerator(Unit &target, float offset, float angle)
+ FollowMovementGenerator(Unit* target, float offset, float angle)
: TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >(target, offset, angle) {}
~FollowMovementGenerator() {}
MovementGeneratorType GetMovementGeneratorType() { return FOLLOW_MOTION_TYPE; }
- void DoInitialize(T &);
- void DoFinalize(T &);
- void DoReset(T &);
- void MovementInform(T &);
+ void DoInitialize(T*);
+ void DoFinalize(T*);
+ void DoReset(T*);
+ void MovementInform(T*);
- static void _clearUnitStateMove(T &u) { u.ClearUnitState(UNIT_STATE_FOLLOW_MOVE); }
- static void _addUnitStateMove(T &u) { u.AddUnitState(UNIT_STATE_FOLLOW_MOVE); }
+ static void _clearUnitStateMove(T* u) { u->ClearUnitState(UNIT_STATE_FOLLOW_MOVE); }
+ static void _addUnitStateMove(T* u) { u->AddUnitState(UNIT_STATE_FOLLOW_MOVE); }
bool EnableWalking() const;
- bool _lostTarget(T &) const { return false; }
- void _reachTarget(T &) {}
+ bool _lostTarget(T*) const { return false; }
+ void _reachTarget(T*) {}
private:
- void _updateSpeed(T &u);
+ void _updateSpeed(T* owner);
};
#endif
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index 2add3439575..626039ed2d5 100644..100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -31,64 +31,64 @@
#include "MoveSplineInit.h"
#include "MoveSpline.h"
-void WaypointMovementGenerator<Creature>::LoadPath(Creature &creature)
+void WaypointMovementGenerator<Creature>::LoadPath(Creature* creature)
{
if (!path_id)
- path_id = creature.GetWaypointPath();
+ path_id = creature->GetWaypointPath();
i_path = sWaypointMgr->GetPath(path_id);
if (!i_path)
{
// No movement found for entry
- sLog->outError(LOG_FILTER_SQL, "WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path id: %u", creature.GetName().c_str(), creature.GetEntry(), creature.GetGUIDLow(), path_id);
+ sLog->outError(LOG_FILTER_SQL, "WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path id: %u", creature->GetName().c_str(), creature->GetEntry(), creature->GetGUIDLow(), path_id);
return;
}
StartMoveNow(creature);
}
-void WaypointMovementGenerator<Creature>::DoInitialize(Creature &creature)
+void WaypointMovementGenerator<Creature>::DoInitialize(Creature* creature)
{
LoadPath(creature);
- creature.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ creature->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
}
-void WaypointMovementGenerator<Creature>::DoFinalize(Creature &creature)
+void WaypointMovementGenerator<Creature>::DoFinalize(Creature* creature)
{
- creature.ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
- creature.SetWalk(false);
+ creature->ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ creature->SetWalk(false);
}
-void WaypointMovementGenerator<Creature>::DoReset(Creature &creature)
+void WaypointMovementGenerator<Creature>::DoReset(Creature* creature)
{
- creature.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ creature->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
StartMoveNow(creature);
}
-void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature)
+void WaypointMovementGenerator<Creature>::OnArrived(Creature* creature)
{
if (!i_path || i_path->empty())
return;
if (m_isArrivalDone)
return;
- creature.ClearUnitState(UNIT_STATE_ROAMING_MOVE);
+ creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
m_isArrivalDone = true;
if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance)
{
- sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for "UI64FMTD".", i_path->at(i_currentNode)->event_id, i_currentNode, creature.GetGUID());
- creature.GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, &creature, NULL);
+ sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for "UI64FMTD".", i_path->at(i_currentNode)->event_id, i_currentNode, creature->GetGUID());
+ creature->GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, creature, NULL);
}
// Inform script
MovementInform(creature);
- creature.UpdateWaypointID(i_currentNode);
+ creature->UpdateWaypointID(i_currentNode);
Stop(i_path->at(i_currentNode)->delay);
}
-bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature)
+bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
{
if (!i_path || i_path->empty())
return false;
@@ -99,8 +99,8 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature)
{
if ((i_currentNode == i_path->size() - 1) && !repeating) // If that's our last waypoint
{
- creature.SetHomePosition(i_path->at(i_currentNode)->x, i_path->at(i_currentNode)->y, i_path->at(i_currentNode)->z, creature.GetOrientation());
- creature.GetMotionMaster()->Initialize();
+ creature->SetHomePosition(i_path->at(i_currentNode)->x, i_path->at(i_currentNode)->y, i_path->at(i_currentNode)->z, creature->GetOrientation());
+ creature->GetMotionMaster()->Initialize();
return false;
}
@@ -111,7 +111,7 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature)
m_isArrivalDone = false;
- creature.AddUnitState(UNIT_STATE_ROAMING_MOVE);
+ creature->AddUnitState(UNIT_STATE_ROAMING_MOVE);
Movement::MoveSplineInit init(creature);
init.MoveTo(node->x, node->y, node->z);
@@ -124,19 +124,19 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature)
init.Launch();
//Call for creature group update
- if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature)
- creature.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
+ if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature)
+ creature->GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
return true;
}
-bool WaypointMovementGenerator<Creature>::DoUpdate(Creature &creature, uint32 diff)
+bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 diff)
{
// Waypoint movement can be switched on/off
// This is quite handy for escort quests and other stuff
- if (creature.HasUnitState(UNIT_STATE_NOT_MOVE))
+ if (creature->HasUnitState(UNIT_STATE_NOT_MOVE))
{
- creature.ClearUnitState(UNIT_STATE_ROAMING_MOVE);
+ creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
return true;
}
// prevent a crash at empty waypoint path.
@@ -150,9 +150,9 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature &creature, uint32 di
}
else
{
- if (creature.IsStopped())
+ if (creature->IsStopped())
Stop(STOP_TIME_FOR_PLAYER);
- else if (creature.movespline->Finalized())
+ else if (creature->movespline->Finalized())
{
OnArrived(creature);
return StartMove(creature);
@@ -161,13 +161,13 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature &creature, uint32 di
return true;
}
-void WaypointMovementGenerator<Creature>::MovementInform(Creature &creature)
+void WaypointMovementGenerator<Creature>::MovementInform(Creature* creature)
{
- if (creature.AI())
- creature.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
+ if (creature->AI())
+ creature->AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
}
-bool WaypointMovementGenerator<Creature>::GetResetPosition(Creature&, float& x, float& y, float& z)
+bool WaypointMovementGenerator<Creature>::GetResetPos(Creature*, float& x, float& y, float& z)
{
// prevent a crash at empty waypoint path.
if (!i_path || i_path->empty())
@@ -196,37 +196,37 @@ uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const
return i_path->size();
}
-void FlightPathMovementGenerator::DoInitialize(Player &player)
+void FlightPathMovementGenerator::DoInitialize(Player* player)
{
- DoReset(player);
+ Reset(player);
InitEndGridInfo();
}
-void FlightPathMovementGenerator::DoFinalize(Player& player)
+void FlightPathMovementGenerator::DoFinalize(Player* player)
{
// remove flag to prevent send object build movement packets for flight state and crash (movement generator already not at top of stack)
- player.ClearUnitState(UNIT_STATE_IN_FLIGHT);
+ player->ClearUnitState(UNIT_STATE_IN_FLIGHT);
- player.Dismount();
- player.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
+ player->Dismount();
+ player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
- if (player.m_taxi.empty())
+ if (player->m_taxi.empty())
{
- player.getHostileRefManager().setOnlineOfflineState(true);
+ player->getHostileRefManager().setOnlineOfflineState(true);
// update z position to ground and orientation for landing point
// this prevent cheating with landing point at lags
// when client side flight end early in comparison server side
- player.StopMoving();
+ player->StopMoving();
}
}
#define PLAYER_FLIGHT_SPEED 32.0f
-void FlightPathMovementGenerator::DoReset(Player & player)
+void FlightPathMovementGenerator::DoReset(Player* player)
{
- player.getHostileRefManager().setOnlineOfflineState(false);
- player.AddUnitState(UNIT_STATE_IN_FLIGHT);
- player.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
+ player->getHostileRefManager().setOnlineOfflineState(false);
+ player->AddUnitState(UNIT_STATE_IN_FLIGHT);
+ player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
Movement::MoveSplineInit init(player);
uint32 end = GetPathAtMapEnd();
@@ -243,9 +243,9 @@ void FlightPathMovementGenerator::DoReset(Player & player)
init.Launch();
}
-bool FlightPathMovementGenerator::DoUpdate(Player &player, uint32 /*diff*/)
+bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/)
{
- uint32 pointId = (uint32)player.movespline->currentPathIdx();
+ uint32 pointId = (uint32)player->movespline->currentPathIdx();
if (pointId > i_currentNode)
{
bool departureEvent = true;
@@ -281,16 +281,16 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
}
}
-void FlightPathMovementGenerator::DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure)
+void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry const& node, bool departure)
{
if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID)
{
- sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "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());
- player.GetMap()->ScriptsStart(sEventScripts, eventid, &player, &player);
+ sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "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());
+ player->GetMap()->ScriptsStart(sEventScripts, eventid, player, player);
}
}
-bool FlightPathMovementGenerator::GetResetPosition(Player&, float& x, float& y, float& z)
+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;
@@ -322,331 +322,3 @@ void FlightPathMovementGenerator::PreloadEndGrid()
else
sLog->outInfo(LOG_FILTER_GENERAL, "Unable to determine map to preload flightmaster grid");
}
-
-
-//
-// Unique1's ASTAR Pathfinding Code... For future use & reference...
-//
-
-#ifdef __PATHFINDING__
-
-int GetFCost(int to, int num, int parentNum, float *gcost); // Below...
-
-int ShortenASTARRoute(short int *pathlist, int number)
-{ // Wrote this to make the routes a little smarter (shorter)... No point looping back to the same places... Unique1
- short int temppathlist[MAX_PATHLIST_NODES];
- int count = 0;
- // int count2 = 0;
- int temp, temp2;
- int link;
- int upto = 0;
-
- for (temp = number; temp >= 0; temp--)
- {
- qboolean shortened = qfalse;
-
- for (temp2 = 0; temp2 < temp; temp2++)
- {
- for (link = 0; link < nodes[pathlist[temp]].enodenum; link++)
- {
- if (nodes[pathlist[temp]].links[link].flags & PATH_BLOCKED)
- continue;
-
- //if ((bot->client->ps.eFlags & EF_TANK) && nodes[bot->current_node].links[link].flags & PATH_NOTANKS) //if this path is blocked, skip it
- // continue;
-
- //if (nodes[nodes[pathlist[temp]].links[link].targetNode].origin[2] > nodes[pathlist[temp]].origin[2] + 32)
- // continue;
-
- if (nodes[pathlist[temp]].links[link].targetNode == pathlist[temp2])
- { // Found a shorter route...
- //if (OrgVisible(nodes[pathlist[temp2]].origin, nodes[pathlist[temp]].origin, -1))
- {
- temppathlist[count] = pathlist[temp2];
- temp = temp2;
- ++count;
- shortened = qtrue;
- }
- }
- }
- }
-
- if (!shortened)
- {
- temppathlist[count] = pathlist[temp];
- ++count;
- }
- }
-
- upto = count;
-
- for (temp = 0; temp < count; temp++)
- {
- pathlist[temp] = temppathlist[upto];
- --upto;
- }
-
- G_Printf("ShortenASTARRoute: Path size reduced from %i to %i nodes...n", number, count);
- return count;
-}
-
-/*
-===========================================================================
-CreatePathAStar
-This function uses the A* pathfinding algorithm to determine the
-shortest path between any two nodes.
-It's fairly complex, so I'm not really going to explain it much.
-Look up A* and binary heaps for more info.
-pathlist stores the ideal path between the nodes, in reverse order,
-and the return value is the number of nodes in that path
-===========================================================================
-*/
-int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
-{
- //all the data we have to hold...since we can't do dynamic allocation, has to be MAX_NODES
- //we can probably lower this later - eg, the open list should never have more than at most a few dozen items on it
- short int openlist[MAX_NODES+1]; //add 1 because it's a binary heap, and they don't use 0 - 1 is the first used index
- float gcost[MAX_NODES];
- int fcost[MAX_NODES];
- char list[MAX_NODES]; //0 is neither, 1 is open, 2 is closed - char because it's the smallest data type
- short int parent[MAX_NODES];
-
- short int numOpen = 0;
- short int atNode, temp, newnode=-1;
- qboolean found = qfalse;
- int count = -1;
- float gc;
- int i, u, v, m;
- vec3_t vec;
-
- //clear out all the arrays
- memset(openlist, 0, sizeof(short int)*(MAX_NODES+1));
- memset(fcost, 0, sizeof(int)*MAX_NODES);
- memset(list, 0, sizeof(char)*MAX_NODES);
- memset(parent, 0, sizeof(short int)*MAX_NODES);
- memset(gcost, -1, sizeof(float)*MAX_NODES);
-
- //make sure we have valid data before calculating everything
- if ((from == NODE_INVALID) || (to == NODE_INVALID) || (from >= MAX_NODES) || (to >= MAX_NODES) || (from == to))
- return -1;
-
- openlist[1] = from; //add the starting node to the open list
- ++numOpen;
- gcost[from] = 0; //its f and g costs are obviously 0
- fcost[from] = 0;
-
- while (1)
- {
- if (numOpen != 0) //if there are still items in the open list
- {
- //pop the top item off of the list
- atNode = openlist[1];
- list[atNode] = 2; //put the node on the closed list so we don't check it again
- --numOpen;
-
- openlist[1] = openlist[numOpen+1]; //move the last item in the list to the top position
- v = 1;
-
- //this while loop reorders the list so that the new lowest fcost is at the top again
- while (1)
- {
- u = v;
- if ((2*u+1) < numOpen) //if both children exist
- {
- if (fcost[openlist[u]] >= fcost[openlist[2*u]])
- v = 2*u;
- if (fcost[openlist[v]] >= fcost[openlist[2*u+1]])
- v = 2*u+1;
- }
- else
- {
- if ((2*u) < numOpen) //if only one child exists
- {
- if (fcost[openlist[u]] >= fcost[openlist[2*u]])
- v = 2*u;
- }
- }
-
- if (u != v) //if they're out of order, swap this item with its parent
- {
- temp = openlist[u];
- openlist[u] = openlist[v];
- openlist[v] = temp;
- }
- else
- break;
- }
-
- for (i = 0; i < nodes[atNode].enodenum; ++i) //loop through all the links for this node
- {
- newnode = nodes[atNode].links[i].targetNode;
-
- //if this path is blocked, skip it
- if (nodes[atNode].links[i].flags & PATH_BLOCKED)
- continue;
- //if this path is blocked, skip it
- if (bot->client && (bot->client->ps.eFlags & EF_TANK) && nodes[atNode].links[i].flags & PATH_NOTANKS)
- continue;
- //skip any unreachable nodes
- if (bot->client && (nodes[newnode].type & NODE_ALLY_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_ALLIES))
- continue;
- if (bot->client && (nodes[newnode].type & NODE_AXIS_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_AXIS))
- continue;
-
- if (list[newnode] == 2) //if this node is on the closed list, skip it
- continue;
-
- if (list[newnode] != 1) //if this node is not already on the open list
- {
- openlist[++numOpen] = newnode; //add the new node to the open list
- list[newnode] = 1;
- parent[newnode] = atNode; //record the node's parent
-
- if (newnode == to) //if we've found the goal, don't keep computing paths!
- break; //this will break the 'for' and go all the way to 'if (list[to] == 1)'
-
- //store it's f cost value
- fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost);
-
- //this loop re-orders the heap so that the lowest fcost is at the top
- m = numOpen;
- while (m != 1) //while this item isn't at the top of the heap already
- {
- //if it has a lower fcost than its parent
- if (fcost[openlist[m]] <= fcost[openlist[m/2]])
- {
- temp = openlist[m/2];
- openlist[m/2] = openlist[m];
- openlist[m] = temp; //swap them
- m /= 2;
- }
- else
- break;
- }
- }
- else //if this node is already on the open list
- {
- gc = gcost[atNode];
- VectorSubtract(nodes[newnode].origin, nodes[atNode].origin, vec);
- gc += VectorLength(vec); //calculate what the gcost would be if we reached this node along the current path
-
- if (gc < gcost[newnode]) //if the new gcost is less (ie, this path is shorter than what we had before)
- {
- parent[newnode] = atNode; //set the new parent for this node
- gcost[newnode] = gc; //and the new g cost
-
- for (i = 1; i < numOpen; ++i) //loop through all the items on the open list
- {
- if (openlist[i] == newnode) //find this node in the list
- {
- //calculate the new fcost and store it
- fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost);
-
- //reorder the list again, with the lowest fcost item on top
- m = i;
- while (m != 1)
- {
- //if the item has a lower fcost than it's parent
- if (fcost[openlist[m]] < fcost[openlist[m/2]])
- {
- temp = openlist[m/2];
- openlist[m/2] = openlist[m];
- openlist[m] = temp; //swap them
- m /= 2;
- }
- else
- break;
- }
- break; //exit the 'for' loop because we already changed this node
- } //if
- } //for
- } //if (gc < gcost[newnode])
- } //if (list[newnode] != 1) --> else
- } //for (loop through links)
- } //if (numOpen != 0)
- else
- {
- found = qfalse; //there is no path between these nodes
- break;
- }
-
- if (list[to] == 1) //if the destination node is on the open list, we're done
- {
- found = qtrue;
- break;
- }
- } //while (1)
-
- if (found == qtrue) //if we found a path
- {
- //G_Printf("%s - path found!n", bot->client->pers.netname);
- count = 0;
-
- temp = to; //start at the end point
- while (temp != from) //travel along the path (backwards) until we reach the starting point
- {
- pathlist[count++] = temp; //add the node to the pathlist and increment the count
- temp = parent[temp]; //move to the parent of this node to continue the path
- }
-
- pathlist[count++] = from; //add the beginning node to the end of the pathlist
-
- #ifdef __BOT_SHORTEN_ROUTING__
- count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1
- #endif //__BOT_SHORTEN_ROUTING__
- }
- else
- {
- //G_Printf("^1*** ^4BOT DEBUG^5: (CreatePathAStar) There is no route between node ^7%i^5 and node ^7%i^5.n", from, to);
- count = CreateDumbRoute(from, to, pathlist);
-
- if (count > 0)
- {
- #ifdef __BOT_SHORTEN_ROUTING__
- count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1
- #endif //__BOT_SHORTEN_ROUTING__
- return count;
- }
- }
-
- return count; //return the number of nodes in the path, -1 if not found
-}
-
-/*
-===========================================================================
-GetFCost
-Utility function used by A* pathfinding to calculate the
-cost to move between nodes towards a goal. Using the A*
-algorithm F = G + H, G here is the distance along the node
-paths the bot must travel, and H is the straight-line distance
-to the goal node.
-Returned as an int because more precision is unnecessary and it
-will slightly speed up heap access
-===========================================================================
-*/
-int GetFCost(int to, int num, int parentNum, float *gcost)
-{
- float gc = 0;
- float hc = 0;
- vec3_t v;
-
- if (gcost[num] == -1)
- {
- if (parentNum != -1)
- {
- gc = gcost[parentNum];
- VectorSubtract(nodes[num].origin, nodes[parentNum].origin, v);
- gc += VectorLength(v);
- }
- gcost[num] = gc;
- }
- else
- gc = gcost[num];
-
- VectorSubtract(nodes[to].origin, nodes[num].origin, v);
- hc = VectorLength(v);
-
- return (int)(gc + hc);
-}
-#endif //__PATHFINDING__
-
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
index 319a5c66a03..72650570e12 100644..100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
@@ -65,19 +65,19 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Crea
WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true)
: i_nextMoveTime(0), m_isArrivalDone(false), path_id(_path_id), repeating(_repeating) {}
~WaypointMovementGenerator() { i_path = NULL; }
- void DoInitialize(Creature &);
- void DoFinalize(Creature &);
- void DoReset(Creature &);
- bool DoUpdate(Creature &, uint32 diff);
+ void DoInitialize(Creature*);
+ void DoFinalize(Creature*);
+ void DoReset(Creature*);
+ bool DoUpdate(Creature*, uint32 diff);
- void MovementInform(Creature &);
+ void MovementInform(Creature*);
MovementGeneratorType GetMovementGeneratorType() { return WAYPOINT_MOTION_TYPE; }
// now path movement implmementation
- void LoadPath(Creature &c);
+ void LoadPath(Creature*);
- bool GetResetPosition(Creature&, float& x, float& y, float& z);
+ bool GetResetPos(Creature*, float& x, float& y, float& z);
private:
@@ -91,10 +91,10 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Crea
return i_nextMoveTime.Passed();
}
- void OnArrived(Creature&);
- bool StartMove(Creature&);
+ void OnArrived(Creature*);
+ bool StartMove(Creature*);
- void StartMoveNow(Creature& creature)
+ void StartMoveNow(Creature* creature)
{
i_nextMoveTime.Reset(0);
StartMove(creature);
@@ -118,10 +118,10 @@ class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, Flig
i_path = &pathnodes;
i_currentNode = startNode;
}
- void DoInitialize(Player &);
- void DoReset(Player &);
- void DoFinalize(Player &);
- bool DoUpdate(Player &, uint32);
+ void DoInitialize(Player*);
+ void DoReset(Player*);
+ void DoFinalize(Player*);
+ bool DoUpdate(Player*, uint32);
MovementGeneratorType GetMovementGeneratorType() { return FLIGHT_MOTION_TYPE; }
TaxiPathNodeList const& GetPath() { return *i_path; }
@@ -129,9 +129,9 @@ class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, Flig
bool HasArrived() const { return (i_currentNode >= i_path->size()); }
void SetCurrentNodeAfterTeleport();
void SkipCurrentNode() { ++i_currentNode; }
- void DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure);
+ void DoEventIfAny(Player* player, TaxiPathNodeEntry const& node, bool departure);
- bool GetResetPosition(Player&, float& x, float& y, float& z);
+ bool GetResetPos(Player*, float& x, float& y, float& z);
void InitEndGridInfo();
void PreloadEndGrid();
@@ -143,4 +143,3 @@ class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, Flig
uint32 _preloadTargetNode; //! node index where preloading starts
};
#endif
-
diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp
new file mode 100644
index 00000000000..dbda4aa2411
--- /dev/null
+++ b/src/server/game/Movement/PathGenerator.cpp
@@ -0,0 +1,803 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "PathGenerator.h"
+#include "Map.h"
+#include "Creature.h"
+#include "MMapFactory.h"
+#include "MMapManager.h"
+#include "Log.h"
+
+#include "DetourCommon.h"
+#include "DetourNavMeshQuery.h"
+
+////////////////// PathGenerator //////////////////
+PathGenerator::PathGenerator(const Unit* owner) :
+ _polyLength(0), _type(PATHFIND_BLANK),
+ _useStraightPath(false), _forceDestination(false), _pointPathLimit(MAX_POINT_PATH_LENGTH),
+ _endPosition(Vector3::zero()), _sourceUnit(owner), _navMesh(NULL), _navMeshQuery(NULL)
+{
+ sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::PathGenerator for %u \n", _sourceUnit->GetGUIDLow());
+
+ uint32 mapId = _sourceUnit->GetMapId();
+ if (MMAP::MMapFactory::IsPathfindingEnabled(mapId))
+ {
+ MMAP::MMapManager* mmap = MMAP::MMapFactory::createOrGetMMapManager();
+ _navMesh = mmap->GetNavMesh(mapId);
+ _navMeshQuery = mmap->GetNavMeshQuery(mapId, _sourceUnit->GetInstanceId());
+ }
+
+ CreateFilter();
+}
+
+PathGenerator::~PathGenerator()
+{
+ sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::~PathGenerator() for %u \n", _sourceUnit->GetGUIDLow());
+}
+
+bool PathGenerator::CalculatePath(float destX, float destY, float destZ, bool forceDest)
+{
+ float x, y, z;
+ _sourceUnit->GetPosition(x, y, z);
+
+ if (!Trinity::IsValidMapCoord(destX, destY, destZ) || !Trinity::IsValidMapCoord(x, y, z))
+ return false;
+
+ Vector3 dest(destX, destY, destZ);
+ SetEndPosition(dest);
+
+ Vector3 start(x, y, z);
+ SetStartPosition(start);
+
+ _forceDestination = forceDest;
+
+ sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::CalculatePath() for %u \n", _sourceUnit->GetGUIDLow());
+
+ // make sure navMesh works - we can run on map w/o mmap
+ // check if the start and end point have a .mmtile loaded (can we pass via not loaded tile on the way?)
+ if (!_navMesh || !_navMeshQuery || _sourceUnit->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING) ||
+ !HaveTile(start) || !HaveTile(dest))
+ {
+ BuildShortcut();
+ _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
+ return true;
+ }
+
+ UpdateFilter();
+
+ BuildPolyPath(start, dest);
+ return true;
+}
+
+dtPolyRef PathGenerator::GetPathPolyByPosition(dtPolyRef const* polyPath, uint32 polyPathSize, float const* point, float* distance) const
+{
+ if (!polyPath || !polyPathSize)
+ return INVALID_POLYREF;
+
+ dtPolyRef nearestPoly = INVALID_POLYREF;
+ float minDist2d = FLT_MAX;
+ float minDist3d = 0.0f;
+
+ for (uint32 i = 0; i < polyPathSize; ++i)
+ {
+ float closestPoint[VERTEX_SIZE];
+ if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(polyPath[i], point, closestPoint))
+ continue;
+
+ float d = dtVdist2DSqr(point, closestPoint);
+ if (d < minDist2d)
+ {
+ minDist2d = d;
+ nearestPoly = polyPath[i];
+ minDist3d = dtVdistSqr(point, closestPoint);
+ }
+
+ if (minDist2d < 1.0f) // shortcut out - close enough for us
+ break;
+ }
+
+ if (distance)
+ *distance = dtSqrt(minDist3d);
+
+ return (minDist2d < 3.0f) ? nearestPoly : INVALID_POLYREF;
+}
+
+dtPolyRef PathGenerator::GetPolyByLocation(float const* point, float* distance) const
+{
+ // first we check the current path
+ // if the current path doesn't contain the current poly,
+ // we need to use the expensive navMesh.findNearestPoly
+ dtPolyRef polyRef = GetPathPolyByPosition(_pathPolyRefs, _polyLength, point, distance);
+ if (polyRef != INVALID_POLYREF)
+ return polyRef;
+
+ // we don't have it in our old path
+ // try to get it by findNearestPoly()
+ // first try with low search box
+ float extents[VERTEX_SIZE] = {3.0f, 5.0f, 3.0f}; // bounds of poly search area
+ float closestPoint[VERTEX_SIZE] = {0.0f, 0.0f, 0.0f};
+ dtStatus result = _navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint);
+ if (DT_SUCCESS == result && polyRef != INVALID_POLYREF)
+ {
+ *distance = dtVdist(closestPoint, point);
+ return polyRef;
+ }
+
+ // still nothing ..
+ // try with bigger search box
+ extents[1] = 200.0f;
+ result = _navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint);
+ if (DT_SUCCESS == result && polyRef != INVALID_POLYREF)
+ {
+ *distance = dtVdist(closestPoint, point);
+ return polyRef;
+ }
+
+ return INVALID_POLYREF;
+}
+
+void PathGenerator::BuildPolyPath(Vector3 const& startPos, Vector3 const& endPos)
+{
+ // *** getting start/end poly logic ***
+
+ float distToStartPoly, distToEndPoly;
+ float startPoint[VERTEX_SIZE] = {startPos.y, startPos.z, startPos.x};
+ float endPoint[VERTEX_SIZE] = {endPos.y, endPos.z, endPos.x};
+
+ dtPolyRef startPoly = GetPolyByLocation(startPoint, &distToStartPoly);
+ dtPolyRef endPoly = GetPolyByLocation(endPoint, &distToEndPoly);
+
+ // we have a hole in our mesh
+ // make shortcut path and mark it as NOPATH ( with flying and swimming exception )
+ // its up to caller how he will use this info
+ if (startPoly == INVALID_POLYREF || endPoly == INVALID_POLYREF)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (startPoly == 0 || endPoly == 0)\n");
+ BuildShortcut();
+ bool path = _sourceUnit->GetTypeId() == TYPEID_UNIT && _sourceUnit->ToCreature()->CanFly();
+
+ bool waterPath = _sourceUnit->GetTypeId() == TYPEID_UNIT && _sourceUnit->ToCreature()->canSwim();
+ if (waterPath)
+ {
+ // Check both start and end points, if they're both in water, then we can *safely* let the creature move
+ for (uint32 i = 0; i < _pathPoints.size(); ++i)
+ {
+ ZLiquidStatus status = _sourceUnit->GetBaseMap()->getLiquidStatus(_pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z, MAP_ALL_LIQUIDS, NULL);
+ // One of the points is not in the water, cancel movement.
+ if (status == LIQUID_MAP_NO_WATER)
+ {
+ waterPath = false;
+ break;
+ }
+ }
+ }
+
+ _type = (path || waterPath) ? PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH) : PATHFIND_NOPATH;
+ return;
+ }
+
+ // we may need a better number here
+ bool farFromPoly = (distToStartPoly > 7.0f || distToEndPoly > 7.0f);
+ if (farFromPoly)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: farFromPoly distToStartPoly=%.3f distToEndPoly=%.3f\n", distToStartPoly, distToEndPoly);
+
+ bool buildShotrcut = false;
+ if (_sourceUnit->GetTypeId() == TYPEID_UNIT)
+ {
+ Creature* owner = (Creature*)_sourceUnit;
+
+ Vector3 p = (distToStartPoly > 7.0f) ? startPos : endPos;
+ if (_sourceUnit->GetBaseMap()->IsUnderWater(p.x, p.y, p.z))
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: underWater case\n");
+ if (owner->canSwim())
+ buildShotrcut = true;
+ }
+ else
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: flying case\n");
+ if (owner->CanFly())
+ buildShotrcut = true;
+ }
+ }
+
+ if (buildShotrcut)
+ {
+ BuildShortcut();
+ _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
+ return;
+ }
+ else
+ {
+ float closestPoint[VERTEX_SIZE];
+ // we may want to use closestPointOnPolyBoundary instead
+ if (DT_SUCCESS == _navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint))
+ {
+ dtVcopy(endPoint, closestPoint);
+ SetActualEndPosition(Vector3(endPoint[2], endPoint[0], endPoint[1]));
+ }
+
+ _type = PATHFIND_INCOMPLETE;
+ }
+ }
+
+ // *** poly path generating logic ***
+
+ // start and end are on same polygon
+ // just need to move in straight line
+ if (startPoly == endPoly)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (startPoly == endPoly)\n");
+
+ BuildShortcut();
+
+ _pathPolyRefs[0] = startPoly;
+ _polyLength = 1;
+
+ _type = farFromPoly ? PATHFIND_INCOMPLETE : PATHFIND_NORMAL;
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: path type %d\n", _type);
+ return;
+ }
+
+ // look for startPoly/endPoly in current path
+ // TODO: we can merge it with getPathPolyByPosition() loop
+ bool startPolyFound = false;
+ bool endPolyFound = false;
+ uint32 pathStartIndex = 0;
+ uint32 pathEndIndex = 0;
+
+ if (_polyLength)
+ {
+ for (; pathStartIndex < _polyLength; ++pathStartIndex)
+ {
+ // here to carch few bugs
+ ASSERT(_pathPolyRefs[pathStartIndex] != INVALID_POLYREF);
+
+ if (_pathPolyRefs[pathStartIndex] == startPoly)
+ {
+ startPolyFound = true;
+ break;
+ }
+ }
+
+ for (pathEndIndex = _polyLength-1; pathEndIndex > pathStartIndex; --pathEndIndex)
+ if (_pathPolyRefs[pathEndIndex] == endPoly)
+ {
+ endPolyFound = true;
+ break;
+ }
+ }
+
+ if (startPolyFound && endPolyFound)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (startPolyFound && endPolyFound)\n");
+
+ // we moved along the path and the target did not move out of our old poly-path
+ // our path is a simple subpath case, we have all the data we need
+ // just "cut" it out
+
+ _polyLength = pathEndIndex - pathStartIndex + 1;
+ memmove(_pathPolyRefs, _pathPolyRefs + pathStartIndex, _polyLength * sizeof(dtPolyRef));
+ }
+ else if (startPolyFound && !endPolyFound)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (startPolyFound && !endPolyFound)\n");
+
+ // we are moving on the old path but target moved out
+ // so we have atleast part of poly-path ready
+
+ _polyLength -= pathStartIndex;
+
+ // try to adjust the suffix of the path instead of recalculating entire length
+ // at given interval the target cannot get too far from its last location
+ // thus we have less poly to cover
+ // sub-path of optimal path is optimal
+
+ // take ~80% of the original length
+ // TODO : play with the values here
+ uint32 prefixPolyLength = uint32(_polyLength * 0.8f + 0.5f);
+ memmove(_pathPolyRefs, _pathPolyRefs+pathStartIndex, prefixPolyLength * sizeof(dtPolyRef));
+
+ dtPolyRef suffixStartPoly = _pathPolyRefs[prefixPolyLength-1];
+
+ // we need any point on our suffix start poly to generate poly-path, so we need last poly in prefix data
+ float suffixEndPoint[VERTEX_SIZE];
+ if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint))
+ {
+ // we can hit offmesh connection as last poly - closestPointOnPoly() don't like that
+ // try to recover by using prev polyref
+ --prefixPolyLength;
+ suffixStartPoly = _pathPolyRefs[prefixPolyLength-1];
+ if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint))
+ {
+ // suffixStartPoly is still invalid, error state
+ BuildShortcut();
+ _type = PATHFIND_NOPATH;
+ return;
+ }
+ }
+
+ // generate suffix
+ uint32 suffixPolyLength = 0;
+ dtStatus dtResult = _navMeshQuery->findPath(
+ suffixStartPoly, // start polygon
+ endPoly, // end polygon
+ suffixEndPoint, // start position
+ endPoint, // end position
+ &_filter, // polygon search filter
+ _pathPolyRefs + prefixPolyLength - 1, // [out] path
+ (int*)&suffixPolyLength,
+ MAX_PATH_LENGTH-prefixPolyLength); // max number of polygons in output path
+
+ if (!suffixPolyLength || dtResult != DT_SUCCESS)
+ {
+ // this is probably an error state, but we'll leave it
+ // and hopefully recover on the next Update
+ // we still need to copy our preffix
+ sLog->outError(LOG_FILTER_MAPS, "%u's Path Build failed: 0 length path", _sourceUnit->GetGUIDLow());
+ }
+
+ sLog->outDebug(LOG_FILTER_MAPS, "++ m_polyLength=%u prefixPolyLength=%u suffixPolyLength=%u \n", _polyLength, prefixPolyLength, suffixPolyLength);
+
+ // new path = prefix + suffix - overlap
+ _polyLength = prefixPolyLength + suffixPolyLength - 1;
+ }
+ else
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (!startPolyFound && !endPolyFound)\n");
+
+ // either we have no path at all -> first run
+ // or something went really wrong -> we aren't moving along the path to the target
+ // just generate new path
+
+ // free and invalidate old path data
+ Clear();
+
+ dtStatus dtResult = _navMeshQuery->findPath(
+ startPoly, // start polygon
+ endPoly, // end polygon
+ startPoint, // start position
+ endPoint, // end position
+ &_filter, // polygon search filter
+ _pathPolyRefs, // [out] path
+ (int*)&_polyLength,
+ MAX_PATH_LENGTH); // max number of polygons in output path
+
+ if (!_polyLength || dtResult != DT_SUCCESS)
+ {
+ // only happens if we passed bad data to findPath(), or navmesh is messed up
+ sLog->outError(LOG_FILTER_MAPS, "%u's Path Build failed: 0 length path", _sourceUnit->GetGUIDLow());
+ BuildShortcut();
+ _type = PATHFIND_NOPATH;
+ return;
+ }
+ }
+
+ // by now we know what type of path we can get
+ if (_pathPolyRefs[_polyLength - 1] == endPoly && !(_type & PATHFIND_INCOMPLETE))
+ _type = PATHFIND_NORMAL;
+ else
+ _type = PATHFIND_INCOMPLETE;
+
+ // generate the point-path out of our up-to-date poly-path
+ BuildPointPath(startPoint, endPoint);
+}
+
+void PathGenerator::BuildPointPath(const float *startPoint, const float *endPoint)
+{
+ float pathPoints[MAX_POINT_PATH_LENGTH*VERTEX_SIZE];
+ uint32 pointCount = 0;
+ dtStatus dtResult = DT_FAILURE;
+ if (_useStraightPath)
+ {
+ dtResult = _navMeshQuery->findStraightPath(
+ startPoint, // start position
+ endPoint, // end position
+ _pathPolyRefs, // current path
+ _polyLength, // lenth of current path
+ pathPoints, // [out] path corner points
+ NULL, // [out] flags
+ NULL, // [out] shortened path
+ (int*)&pointCount,
+ _pointPathLimit); // maximum number of points/polygons to use
+ }
+ else
+ {
+ dtResult = FindSmoothPath(
+ startPoint, // start position
+ endPoint, // end position
+ _pathPolyRefs, // current path
+ _polyLength, // length of current path
+ pathPoints, // [out] path corner points
+ (int*)&pointCount,
+ _pointPathLimit); // maximum number of points
+ }
+
+ if (pointCount < 2 || dtResult != DT_SUCCESS)
+ {
+ // only happens if pass bad data to findStraightPath or navmesh is broken
+ // single point paths can be generated here
+ // TODO : check the exact cases
+ sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::BuildPointPath FAILED! path sized %d returned\n", pointCount);
+ BuildShortcut();
+ _type = PATHFIND_NOPATH;
+ return;
+ }
+ else if (pointCount == _pointPathLimit)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::BuildPointPath FAILED! path sized %d returned, lower than limit set to %d\n", pointCount, _pointPathLimit);
+ BuildShortcut();
+ _type = PATHFIND_SHORT;
+ return;
+ }
+
+ _pathPoints.resize(pointCount);
+ for (uint32 i = 0; i < pointCount; ++i)
+ _pathPoints[i] = Vector3(pathPoints[i*VERTEX_SIZE+2], pathPoints[i*VERTEX_SIZE], pathPoints[i*VERTEX_SIZE+1]);
+
+ NormalizePath();
+
+ // first point is always our current location - we need the next one
+ SetActualEndPosition(_pathPoints[pointCount-1]);
+
+ // force the given destination, if needed
+ if (_forceDestination &&
+ (!(_type & PATHFIND_NORMAL) || !InRange(GetEndPosition(), GetActualEndPosition(), 1.0f, 1.0f)))
+ {
+ // we may want to keep partial subpath
+ if (Dist3DSqr(GetActualEndPosition(), GetEndPosition()) < 0.3f * Dist3DSqr(GetStartPosition(), GetEndPosition()))
+ {
+ SetActualEndPosition(GetEndPosition());
+ _pathPoints[_pathPoints.size()-1] = GetEndPosition();
+ }
+ else
+ {
+ SetActualEndPosition(GetEndPosition());
+ BuildShortcut();
+ }
+
+ _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
+ }
+
+ sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::BuildPointPath path type %d size %d poly-size %d\n", _type, pointCount, _polyLength);
+}
+
+void PathGenerator::NormalizePath()
+{
+ for (uint32 i = 0; i < _pathPoints.size(); ++i)
+ _sourceUnit->UpdateAllowedPositionZ(_pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z);
+}
+
+void PathGenerator::BuildShortcut()
+{
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildShortcut :: making shortcut\n");
+
+ Clear();
+
+ // make two point path, our curr pos is the start, and dest is the end
+ _pathPoints.resize(2);
+
+ // set start and a default next position
+ _pathPoints[0] = GetStartPosition();
+ _pathPoints[1] = GetActualEndPosition();
+
+ NormalizePath();
+
+ _type = PATHFIND_SHORTCUT;
+}
+
+void PathGenerator::CreateFilter()
+{
+ uint16 includeFlags = 0;
+ uint16 excludeFlags = 0;
+
+ if (_sourceUnit->GetTypeId() == TYPEID_UNIT)
+ {
+ Creature* creature = (Creature*)_sourceUnit;
+ if (creature->canWalk())
+ includeFlags |= NAV_GROUND; // walk
+
+ // creatures don't take environmental damage
+ if (creature->canSwim())
+ includeFlags |= (NAV_WATER | NAV_MAGMA | NAV_SLIME); // swim
+ }
+ else // assume Player
+ {
+ // perfect support not possible, just stay 'safe'
+ includeFlags |= (NAV_GROUND | NAV_WATER | NAV_MAGMA | NAV_SLIME);
+ }
+
+ _filter.setIncludeFlags(includeFlags);
+ _filter.setExcludeFlags(excludeFlags);
+
+ UpdateFilter();
+}
+
+void PathGenerator::UpdateFilter()
+{
+ // allow creatures to cheat and use different movement types if they are moved
+ // forcefully into terrain they can't normally move in
+ if (_sourceUnit->IsInWater() || _sourceUnit->IsUnderWater())
+ {
+ uint16 includedFlags = _filter.getIncludeFlags();
+ includedFlags |= GetNavTerrain(_sourceUnit->GetPositionX(),
+ _sourceUnit->GetPositionY(),
+ _sourceUnit->GetPositionZ());
+
+ _filter.setIncludeFlags(includedFlags);
+ }
+}
+
+NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z)
+{
+ LiquidData data;
+ _sourceUnit->GetBaseMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &data);
+
+ switch (data.type_flags)
+ {
+ case MAP_LIQUID_TYPE_WATER:
+ case MAP_LIQUID_TYPE_OCEAN:
+ return NAV_WATER;
+ case MAP_LIQUID_TYPE_MAGMA:
+ return NAV_MAGMA;
+ case MAP_LIQUID_TYPE_SLIME:
+ return NAV_SLIME;
+ default:
+ return NAV_GROUND;
+ }
+}
+
+bool PathGenerator::HaveTile(const Vector3& p) const
+{
+ int tx = -1, ty = -1;
+ float point[VERTEX_SIZE] = {p.y, p.z, p.x};
+
+ _navMesh->calcTileLoc(point, &tx, &ty);
+
+ /// Workaround
+ /// For some reason, often the tx and ty variables wont get a valid value
+ /// Use this check to prevent getting negative tile coords and crashing on getTileAt
+ if (tx < 0 || ty < 0)
+ return false;
+
+ return (_navMesh->getTileAt(tx, ty) != NULL);
+}
+
+uint32 PathGenerator::FixupCorridor(dtPolyRef* path, uint32 npath, uint32 maxPath, dtPolyRef const* visited, uint32 nvisited)
+{
+ int32 furthestPath = -1;
+ int32 furthestVisited = -1;
+
+ // Find furthest common polygon.
+ for (int32 i = npath-1; i >= 0; --i)
+ {
+ bool found = false;
+ for (int32 j = nvisited-1; j >= 0; --j)
+ {
+ if (path[i] == visited[j])
+ {
+ furthestPath = i;
+ furthestVisited = j;
+ found = true;
+ }
+ }
+ if (found)
+ break;
+ }
+
+ // If no intersection found just return current path.
+ if (furthestPath == -1 || furthestVisited == -1)
+ return npath;
+
+ // Concatenate paths.
+
+ // Adjust beginning of the buffer to include the visited.
+ uint32 req = nvisited - furthestVisited;
+ uint32 orig = uint32(furthestPath + 1) < npath ? furthestPath + 1 : npath;
+ uint32 size = npath > orig ? npath - orig : 0;
+ if (req + size > maxPath)
+ size = maxPath-req;
+
+ if (size)
+ memmove(path + req, path + orig, size * sizeof(dtPolyRef));
+
+ // Store visited
+ for (uint32 i = 0; i < req; ++i)
+ path[i] = visited[(nvisited - 1) - i];
+
+ return req+size;
+}
+
+bool PathGenerator::GetSteerTarget(float const* startPos, float const* endPos,
+ float minTargetDist, dtPolyRef const* path, uint32 pathSize,
+ float* steerPos, unsigned char& steerPosFlag, dtPolyRef& steerPosRef)
+{
+ // Find steer target.
+ static const uint32 MAX_STEER_POINTS = 3;
+ float steerPath[MAX_STEER_POINTS*VERTEX_SIZE];
+ unsigned char steerPathFlags[MAX_STEER_POINTS];
+ dtPolyRef steerPathPolys[MAX_STEER_POINTS];
+ uint32 nsteerPath = 0;
+ dtStatus dtResult = _navMeshQuery->findStraightPath(startPos, endPos, path, pathSize,
+ steerPath, steerPathFlags, steerPathPolys, (int*)&nsteerPath, MAX_STEER_POINTS);
+ if (!nsteerPath || DT_SUCCESS != dtResult)
+ return false;
+
+ // Find vertex far enough to steer to.
+ uint32 ns = 0;
+ while (ns < nsteerPath)
+ {
+ // Stop at Off-Mesh link or when point is further than slop away.
+ if ((steerPathFlags[ns] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) ||
+ !InRangeYZX(&steerPath[ns*VERTEX_SIZE], startPos, minTargetDist, 1000.0f))
+ break;
+ ns++;
+ }
+ // Failed to find good point to steer to.
+ if (ns >= nsteerPath)
+ return false;
+
+ dtVcopy(steerPos, &steerPath[ns*VERTEX_SIZE]);
+ steerPos[1] = startPos[1]; // keep Z value
+ steerPosFlag = steerPathFlags[ns];
+ steerPosRef = steerPathPolys[ns];
+
+ return true;
+}
+
+dtStatus PathGenerator::FindSmoothPath(float const* startPos, float const* endPos,
+ dtPolyRef const* polyPath, uint32 polyPathSize,
+ float* smoothPath, int* smoothPathSize, uint32 maxSmoothPathSize)
+{
+ *smoothPathSize = 0;
+ uint32 nsmoothPath = 0;
+
+ dtPolyRef polys[MAX_PATH_LENGTH];
+ memcpy(polys, polyPath, sizeof(dtPolyRef)*polyPathSize);
+ uint32 npolys = polyPathSize;
+
+ float iterPos[VERTEX_SIZE], targetPos[VERTEX_SIZE];
+ if (DT_SUCCESS != _navMeshQuery->closestPointOnPolyBoundary(polys[0], startPos, iterPos))
+ return DT_FAILURE;
+
+ if (DT_SUCCESS != _navMeshQuery->closestPointOnPolyBoundary(polys[npolys-1], endPos, targetPos))
+ return DT_FAILURE;
+
+ dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos);
+ nsmoothPath++;
+
+ // Move towards target a small advancement at a time until target reached or
+ // when ran out of memory to store the path.
+ while (npolys && nsmoothPath < maxSmoothPathSize)
+ {
+ // Find location to steer towards.
+ float steerPos[VERTEX_SIZE];
+ unsigned char steerPosFlag;
+ dtPolyRef steerPosRef = INVALID_POLYREF;
+
+ if (!GetSteerTarget(iterPos, targetPos, SMOOTH_PATH_SLOP, polys, npolys, steerPos, steerPosFlag, steerPosRef))
+ break;
+
+ bool endOfPath = (steerPosFlag & DT_STRAIGHTPATH_END);
+ bool offMeshConnection = (steerPosFlag & DT_STRAIGHTPATH_OFFMESH_CONNECTION);
+
+ // Find movement delta.
+ float delta[VERTEX_SIZE];
+ dtVsub(delta, steerPos, iterPos);
+ float len = dtSqrt(dtVdot(delta,delta));
+ // If the steer target is end of path or off-mesh link, do not move past the location.
+ if ((endOfPath || offMeshConnection) && len < SMOOTH_PATH_STEP_SIZE)
+ len = 1.0f;
+ else
+ len = SMOOTH_PATH_STEP_SIZE / len;
+
+ float moveTgt[VERTEX_SIZE];
+ dtVmad(moveTgt, iterPos, delta, len);
+
+ // Move
+ float result[VERTEX_SIZE];
+ const static uint32 MAX_VISIT_POLY = 16;
+ dtPolyRef visited[MAX_VISIT_POLY];
+
+ uint32 nvisited = 0;
+ _navMeshQuery->moveAlongSurface(polys[0], iterPos, moveTgt, &_filter, result, visited, (int*)&nvisited, MAX_VISIT_POLY);
+ npolys = FixupCorridor(polys, npolys, MAX_PATH_LENGTH, visited, nvisited);
+
+ _navMeshQuery->getPolyHeight(polys[0], result, &result[1]);
+ result[1] += 0.5f;
+ dtVcopy(iterPos, result);
+
+ // Handle end of path and off-mesh links when close enough.
+ if (endOfPath && InRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 1.0f))
+ {
+ // Reached end of path.
+ dtVcopy(iterPos, targetPos);
+ if (nsmoothPath < maxSmoothPathSize)
+ {
+ dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos);
+ nsmoothPath++;
+ }
+ break;
+ }
+ else if (offMeshConnection && InRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 1.0f))
+ {
+ // Advance the path up to and over the off-mesh connection.
+ dtPolyRef prevRef = INVALID_POLYREF;
+ dtPolyRef polyRef = polys[0];
+ uint32 npos = 0;
+ while (npos < npolys && polyRef != steerPosRef)
+ {
+ prevRef = polyRef;
+ polyRef = polys[npos];
+ npos++;
+ }
+
+ for (uint32 i = npos; i < npolys; ++i)
+ polys[i-npos] = polys[i];
+
+ npolys -= npos;
+
+ // Handle the connection.
+ float startPos[VERTEX_SIZE], endPos[VERTEX_SIZE];
+ if (DT_SUCCESS == _navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, startPos, endPos))
+ {
+ if (nsmoothPath < maxSmoothPathSize)
+ {
+ dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], startPos);
+ nsmoothPath++;
+ }
+ // Move position at the other side of the off-mesh link.
+ dtVcopy(iterPos, endPos);
+ _navMeshQuery->getPolyHeight(polys[0], iterPos, &iterPos[1]);
+ iterPos[1] += 0.5f;
+ }
+ }
+
+ // Store results.
+ if (nsmoothPath < maxSmoothPathSize)
+ {
+ dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos);
+ nsmoothPath++;
+ }
+ }
+
+ *smoothPathSize = nsmoothPath;
+
+ // this is most likely a loop
+ return nsmoothPath < MAX_POINT_PATH_LENGTH ? DT_SUCCESS : DT_FAILURE;
+}
+
+bool PathGenerator::InRangeYZX(const float* v1, const float* v2, float r, float h) const
+{
+ const float dx = v2[0] - v1[0];
+ const float dy = v2[1] - v1[1]; // elevation
+ const float dz = v2[2] - v1[2];
+ return (dx * dx + dz * dz) < r * r && fabsf(dy) < h;
+}
+
+bool PathGenerator::InRange(Vector3 const& p1, Vector3 const& p2, float r, float h) const
+{
+ Vector3 d = p1 - p2;
+ return (d.x * d.x + d.y * d.y) < r * r && fabsf(d.z) < h;
+}
+
+float PathGenerator::Dist3DSqr(Vector3 const& p1, Vector3 const& p2) const
+{
+ return (p1 - p2).squaredLength();
+}
diff --git a/src/server/game/Movement/PathGenerator.h b/src/server/game/Movement/PathGenerator.h
new file mode 100644
index 00000000000..a20f900b584
--- /dev/null
+++ b/src/server/game/Movement/PathGenerator.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _PATH_GENERATOR_H
+#define _PATH_GENERATOR_H
+
+#include "SharedDefines.h"
+#include "DetourNavMesh.h"
+#include "DetourNavMeshQuery.h"
+#include "MoveSplineInitArgs.h"
+
+using Movement::Vector3;
+using Movement::PointsArray;
+
+class Unit;
+
+// 74*4.0f=296y number_of_points*interval = max_path_len
+// this is way more than actual evade range
+// I think we can safely cut those down even more
+#define MAX_PATH_LENGTH 74
+#define MAX_POINT_PATH_LENGTH 74
+
+#define SMOOTH_PATH_STEP_SIZE 4.0f
+#define SMOOTH_PATH_SLOP 0.3f
+
+#define VERTEX_SIZE 3
+#define INVALID_POLYREF 0
+
+enum PathType
+{
+ PATHFIND_BLANK = 0x00, // path not built yet
+ PATHFIND_NORMAL = 0x01, // normal path
+ PATHFIND_SHORTCUT = 0x02, // travel through obstacles, terrain, air, etc (old behavior)
+ PATHFIND_INCOMPLETE = 0x04, // we have partial path to follow - getting closer to target
+ PATHFIND_NOPATH = 0x08, // no valid path at all or error in generating one
+ PATHFIND_NOT_USING_PATH = 0x10, // used when we are either flying/swiming or on map w/o mmaps
+ PATHFIND_SHORT = 0x20, // path is longer or equal to its limited path length
+};
+
+class PathGenerator
+{
+ public:
+ PathGenerator(Unit const* owner);
+ ~PathGenerator();
+
+ // Calculate the path from owner to given destination
+ // return: true if new path was calculated, false otherwise (no change needed)
+ bool CalculatePath(float destX, float destY, float destZ, bool forceDest = false);
+
+ // option setters - use optional
+ void SetUseStraightPath(bool useStraightPath) { _useStraightPath = useStraightPath; };
+ void SetPathLengthLimit(float distance) { _pointPathLimit = std::min<uint32>(uint32(distance/SMOOTH_PATH_STEP_SIZE), MAX_POINT_PATH_LENGTH); };
+
+ // result getters
+ Vector3 const& GetStartPosition() const { return _startPosition; }
+ Vector3 const& GetEndPosition() const { return _endPosition; }
+ Vector3 const& GetActualEndPosition() const { return _actualEndPosition; }
+
+ PointsArray& GetPath() { return _pathPoints; }
+ PathType GetPathType() const { return _type; }
+
+ private:
+
+ dtPolyRef _pathPolyRefs[MAX_PATH_LENGTH]; // array of detour polygon references
+ uint32 _polyLength; // number of polygons in the path
+
+ PointsArray _pathPoints; // our actual (x,y,z) path to the target
+ PathType _type; // tells what kind of path this is
+
+ bool _useStraightPath; // type of path will be generated
+ bool _forceDestination; // when set, we will always arrive at given point
+ uint32 _pointPathLimit; // limit point path size; min(this, MAX_POINT_PATH_LENGTH)
+
+ Vector3 _startPosition; // {x, y, z} of current location
+ Vector3 _endPosition; // {x, y, z} of the destination
+ Vector3 _actualEndPosition;// {x, y, z} of the closest possible point to given destination
+
+ Unit const* const _sourceUnit; // the unit that is moving
+ dtNavMesh const* _navMesh; // the nav mesh
+ dtNavMeshQuery const* _navMeshQuery; // the nav mesh query used to find the path
+
+ dtQueryFilter _filter; // use single filter for all movements, update it when needed
+
+ void SetStartPosition(Vector3 Point) { _startPosition = Point; }
+ void SetEndPosition(Vector3 Point) { _actualEndPosition = Point; _endPosition = Point; }
+ void SetActualEndPosition(Vector3 Point) { _actualEndPosition = Point; }
+ void NormalizePath();
+
+ void Clear()
+ {
+ _polyLength = 0;
+ _pathPoints.clear();
+ }
+
+ bool InRange(Vector3 const& p1, Vector3 const& p2, float r, float h) const;
+ float Dist3DSqr(Vector3 const& p1, Vector3 const& p2) const;
+ bool InRangeYZX(float const* v1, float const* v2, float r, float h) const;
+
+ dtPolyRef GetPathPolyByPosition(dtPolyRef const* polyPath, uint32 polyPathSize, float const* Point, float* Distance = NULL) const;
+ dtPolyRef GetPolyByLocation(float const* Point, float* Distance) const;
+ bool HaveTile(Vector3 const& p) const;
+
+ void BuildPolyPath(Vector3 const& startPos, Vector3 const& endPos);
+ void BuildPointPath(float const* startPoint, float const* endPoint);
+ void BuildShortcut();
+
+ NavTerrain GetNavTerrain(float x, float y, float z);
+ void CreateFilter();
+ void UpdateFilter();
+
+ // smooth path aux functions
+ uint32 FixupCorridor(dtPolyRef* path, uint32 npath, uint32 maxPath, dtPolyRef const* visited, uint32 nvisited);
+ bool GetSteerTarget(float const* startPos, float const* endPos, float minTargetDist, dtPolyRef const* path, uint32 pathSize, float* steerPos,
+ unsigned char& steerPosFlag, dtPolyRef& steerPosRef);
+ dtStatus FindSmoothPath(float const* startPos, float const* endPos,
+ dtPolyRef const* polyPath, uint32 polyPathSize,
+ float* smoothPath, int* smoothPathSize, uint32 smoothPathMaxSize);
+};
+
+#endif
diff --git a/src/server/game/Movement/Spline/MoveSpline.h b/src/server/game/Movement/Spline/MoveSpline.h
index 8e51e2678dd..b18166ea615 100644
--- a/src/server/game/Movement/Spline/MoveSpline.h
+++ b/src/server/game/Movement/Spline/MoveSpline.h
@@ -78,18 +78,17 @@ namespace Movement
UpdateResult _updateState(int32& ms_time_diff);
int32 next_timestamp() const { return spline.length(point_Idx+1); }
int32 segment_time_elapsed() const { return next_timestamp()-time_passed; }
- int32 Duration() const { return spline.length(); }
int32 timeElapsed() const { return Duration() - time_passed; }
int32 timePassed() const { return time_passed; }
public:
+ int32 Duration() const { return spline.length(); }
const MySpline& _Spline() const { return spline; }
int32 _currentSplineIdx() const { return point_Idx; }
void _Finalize();
void _Interrupt() { splineflags.done = true;}
public:
-
void Initialize(const MoveSplineInitArgs&);
bool Initialized() const { return !spline.empty(); }
diff --git a/src/server/game/Movement/Spline/MoveSplineInit.cpp b/src/server/game/Movement/Spline/MoveSplineInit.cpp
index 61178f3f9ad..249f25a6353 100644
--- a/src/server/game/Movement/Spline/MoveSplineInit.cpp
+++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp
@@ -58,36 +58,36 @@ namespace Movement
return MOVE_RUN;
}
- void MoveSplineInit::Launch()
+ int32 MoveSplineInit::Launch()
{
- MoveSpline& move_spline = *unit.movespline;
+ MoveSpline& move_spline = *unit->movespline;
- Location real_position(unit.GetPositionX(), unit.GetPositionY(), unit.GetPositionZMinusOffset(), unit.GetOrientation());
+ Location real_position(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZMinusOffset(), unit->GetOrientation());
// Elevators also use MOVEMENTFLAG_ONTRANSPORT but we do not keep track of their position changes
- if (unit.GetTransGUID())
+ if (unit->GetTransGUID())
{
- real_position.x = unit.GetTransOffsetX();
- real_position.y = unit.GetTransOffsetY();
- real_position.z = unit.GetTransOffsetZ();
- real_position.orientation = unit.GetTransOffsetO();
+ real_position.x = unit->GetTransOffsetX();
+ real_position.y = unit->GetTransOffsetY();
+ real_position.z = unit->GetTransOffsetZ();
+ real_position.orientation = unit->GetTransOffsetO();
}
// there is a big chance that current position is unknown if current state is not finalized, need compute it
// this also allows calculate spline position and update map position in much greater intervals
// Don't compute for transport movement if the unit is in a motion between two transports
- if (!move_spline.Finalized() && move_spline.onTransport == (unit.GetTransGUID() != 0))
+ if (!move_spline.Finalized() && move_spline.onTransport == (unit->GetTransGUID() != 0))
real_position = move_spline.ComputePosition();
// should i do the things that user should do? - no.
if (args.path.empty())
- return;
+ return 0;
// correct first vertex
args.path[0] = real_position;
args.initialOrientation = real_position.orientation;
- move_spline.onTransport = (unit.GetTransGUID() != 0);
+ move_spline.onTransport = (unit->GetTransGUID() != 0);
- uint32 moveFlags = unit.m_movementInfo.GetMovementFlags();
+ uint32 moveFlags = unit->m_movementInfo.GetMovementFlags();
if (args.flags.walkmode)
moveFlags |= MOVEMENTFLAG_WALKING;
else
@@ -96,33 +96,35 @@ namespace Movement
moveFlags |= MOVEMENTFLAG_FORWARD;
if (!args.HasVelocity)
- args.velocity = unit.GetSpeed(SelectSpeedType(moveFlags));
+ args.velocity = unit->GetSpeed(SelectSpeedType(moveFlags));
- if (!args.Validate(&unit))
- return;
+ if (!args.Validate(unit))
+ return 0;
if (moveFlags & MOVEMENTFLAG_ROOT)
moveFlags &= ~MOVEMENTFLAG_MASK_MOVING;
- unit.m_movementInfo.SetMovementFlags(moveFlags);
+ unit->m_movementInfo.SetMovementFlags(moveFlags);
move_spline.Initialize(args);
WorldPacket data(SMSG_MONSTER_MOVE, 64);
- data.append(unit.GetPackGUID());
- if (unit.GetTransGUID())
+ data.append(unit->GetPackGUID());
+ if (unit->GetTransGUID())
{
data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT);
- data.appendPackGUID(unit.GetTransGUID());
- data << int8(unit.GetTransSeat());
+ data.appendPackGUID(unit->GetTransGUID());
+ data << int8(unit->GetTransSeat());
}
PacketBuilder::WriteMonsterMove(move_spline, data);
- unit.SendMessageToSet(&data, true);
+ unit->SendMessageToSet(&data, true);
+
+ return move_spline.Duration();
}
void MoveSplineInit::Stop()
{
- MoveSpline& move_spline = *unit.movespline;
+ MoveSpline& move_spline = *unit->movespline;
// No need to stop if we are not moving
if (move_spline.Finalized())
@@ -130,30 +132,30 @@ namespace Movement
Location loc = move_spline.ComputePosition();
args.flags = MoveSplineFlag::Done;
- unit.m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_FORWARD);
+ unit->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_FORWARD);
move_spline.Initialize(args);
WorldPacket data(SMSG_MONSTER_MOVE, 64);
- data.append(unit.GetPackGUID());
- if (unit.GetTransGUID())
+ data.append(unit->GetPackGUID());
+ if (unit->GetTransGUID())
{
data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT);
- data.appendPackGUID(unit.GetTransGUID());
- data << int8(unit.GetTransSeat());
+ data.appendPackGUID(unit->GetTransGUID());
+ data << int8(unit->GetTransSeat());
}
PacketBuilder::WriteStopMovement(loc, args.splineId, data);
- unit.SendMessageToSet(&data, true);
+ unit->SendMessageToSet(&data, true);
}
- MoveSplineInit::MoveSplineInit(Unit& m) : unit(m)
+ MoveSplineInit::MoveSplineInit(Unit* m) : unit(m)
{
args.splineId = splineIdGen.NewId();
// Elevators also use MOVEMENTFLAG_ONTRANSPORT but we do not keep track of their position changes
- args.TransformForTransport = unit.GetTransGUID();
+ args.TransformForTransport = unit->GetTransGUID();
// mix existing state into new
- args.flags.walkmode = unit.m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING);
- args.flags.flying = unit.m_movementInfo.HasMovementFlag(MovementFlags(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY));
+ args.flags.walkmode = unit->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING);
+ args.flags.flying = unit->m_movementInfo.HasMovementFlag(MovementFlags(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY));
args.flags.smoothGroundPath = true; // enabled by default, CatmullRom mode or client config "pathSmoothing" will disable this
}
@@ -167,9 +169,9 @@ namespace Movement
{
if (args.TransformForTransport)
{
- if (Unit* vehicle = unit.GetVehicleBase())
+ if (Unit* vehicle = unit->GetVehicleBase())
angle -= vehicle->GetOrientation();
- else if (Transport* transport = unit.GetTransport())
+ else if (Transport* transport = unit->GetTransport())
angle -= transport->GetOrientation();
}
@@ -177,8 +179,19 @@ namespace Movement
args.flags.EnableFacingAngle();
}
- void MoveSplineInit::MoveTo(Vector3 const& dest)
+ void MoveSplineInit::MoveTo(const Vector3& dest, bool generatePath, bool forceDestination)
{
+ if (generatePath)
+ {
+ PathGenerator path(unit);
+ bool result = path.CalculatePath(dest.x, dest.y, dest.z, forceDestination);
+ if (result && path.GetPathType() & ~PATHFIND_NOPATH)
+ {
+ MovebyPath(path.GetPath());
+ return;
+ }
+ }
+
args.path_Idx_offset = 0;
args.path.resize(2);
TransportPathTransform transform(unit, args.TransformForTransport);
@@ -188,14 +201,14 @@ namespace Movement
void MoveSplineInit::SetFall()
{
args.flags.EnableFalling();
- args.flags.fallingSlow = unit.HasUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW);
+ args.flags.fallingSlow = unit->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW);
}
Vector3 TransportPathTransform::operator()(Vector3 input)
{
if (_transformForTransport)
{
- if (TransportBase* transport = _owner.GetDirectTransport())
+ if (TransportBase* transport = _owner->GetDirectTransport())
{
float unused = 0.0f; // need reference
transport->CalculatePassengerOffset(input.x, input.y, input.z, unused);
diff --git a/src/server/game/Movement/Spline/MoveSplineInit.h b/src/server/game/Movement/Spline/MoveSplineInit.h
index 74e5cdfa9f4..79e0f085d44 100644
--- a/src/server/game/Movement/Spline/MoveSplineInit.h
+++ b/src/server/game/Movement/Spline/MoveSplineInit.h
@@ -20,6 +20,7 @@
#define TRINITYSERVER_MOVESPLINEINIT_H
#include "MoveSplineInitArgs.h"
+#include "PathGenerator.h"
class Unit;
@@ -37,12 +38,12 @@ namespace Movement
class TransportPathTransform
{
public:
- TransportPathTransform(Unit& owner, bool transformForTransport)
+ TransportPathTransform(Unit* owner, bool transformForTransport)
: _owner(owner), _transformForTransport(transformForTransport) { }
Vector3 operator()(Vector3 input);
private:
- Unit& _owner;
+ Unit* _owner;
bool _transformForTransport;
};
@@ -52,11 +53,11 @@ namespace Movement
{
public:
- explicit MoveSplineInit(Unit& m);
+ explicit MoveSplineInit(Unit* m);
/* Final pass of initialization that launches spline movement.
*/
- void Launch();
+ int32 Launch();
/* Final pass of initialization that stops movement.
*/
@@ -87,10 +88,10 @@ namespace Movement
*/
void MovebyPath(const PointsArray& path, int32 pointId = 0);
- /* Initializes simple A to B mition, A is current unit's position, B is destination
+ /* Initializes simple A to B motion, A is current unit's position, B is destination
*/
- void MoveTo(const Vector3& destination);
- void MoveTo(float x, float y, float z);
+ void MoveTo(const Vector3& destination, bool generatePath = true, bool forceDestination = false);
+ void MoveTo(float x, float y, float z, bool generatePath = true, bool forceDestination = false);
/* Sets Id of fisrt point of the path. When N-th path point will be done ILisener will notify that pointId + N done
* Needed for waypoint movement where path splitten into parts
@@ -145,7 +146,7 @@ namespace Movement
protected:
MoveSplineInitArgs args;
- Unit& unit;
+ Unit* unit;
};
inline void MoveSplineInit::SetFly() { args.flags.flying = true; }
@@ -165,9 +166,9 @@ namespace Movement
std::transform(controls.begin(), controls.end(), args.path.begin(), TransportPathTransform(unit, args.TransformForTransport));
}
- inline void MoveSplineInit::MoveTo(float x, float y, float z)
+ inline void MoveSplineInit::MoveTo(float x, float y, float z, bool generatePath, bool forceDestination)
{
- MoveTo(G3D::Vector3(x, y, z));
+ MoveTo(G3D::Vector3(x, y, z), generatePath, forceDestination);
}
inline void MoveSplineInit::SetParabolic(float amplitude, float time_shift)
diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp
index f2dc8897532..eb3d45bb0ec 100644
--- a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp
+++ b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp
@@ -192,7 +192,7 @@ namespace Movement
{
if (!moveSpline.Finalized())
{
- MoveSplineFlag splineFlags = moveSpline.splineflags;
+ MoveSplineFlag const& splineFlags = moveSpline.splineflags;
if ((splineFlags & MoveSplineFlag::Parabolic) && moveSpline.effect_start_time < moveSpline.Duration())
data << moveSpline.vertical_acceleration; // added in 3.1
diff --git a/src/server/game/Movement/Waypoints/Path.h b/src/server/game/Movement/Waypoints/Path.h
index 3f78a640384..39f05184cf6 100644
--- a/src/server/game/Movement/Waypoints/Path.h
+++ b/src/server/game/Movement/Waypoints/Path.h
@@ -20,10 +20,12 @@
#define TRINITYCORE_PATH_H
#include "Common.h"
-#include <vector>
+#include <deque>
-struct SimplePathNode
+struct PathNode
{
+ PathNode(): x(0.0f), y(0.0f), z(0.0f) { }
+ PathNode(float _x, float _y, float _z): x(_x), y(_y), z(_z) { }
float x, y, z;
};
template<typename PathElem, typename PathNode = PathElem>
@@ -36,6 +38,20 @@ class Path
void resize(unsigned int sz) { i_nodes.resize(sz); }
void clear() { i_nodes.clear(); }
void erase(uint32 idx) { i_nodes.erase(i_nodes.begin()+idx); }
+ void crop(unsigned int start, unsigned int end)
+ {
+ while(start && !i_nodes.empty())
+ {
+ i_nodes.pop_front();
+ --start;
+ }
+
+ while(end && !i_nodes.empty())
+ {
+ i_nodes.pop_back();
+ --end;
+ }
+ }
float GetTotalLength(uint32 start, uint32 end) const
{
@@ -76,10 +92,9 @@ class Path
void set(size_t idx, PathElem elem) { i_nodes[idx] = elem; }
protected:
- std::vector<PathElem> i_nodes;
+ std::deque<PathElem> i_nodes;
};
-typedef Path<SimplePathNode> SimplePath;
+typedef Path<PathNode> SimplePath;
#endif
-
diff --git a/src/server/game/Movement/Waypoints/WaypointManager.cpp b/src/server/game/Movement/Waypoints/WaypointManager.cpp
index 937a2ddef72..6fba8308077 100644
--- a/src/server/game/Movement/Waypoints/WaypointManager.cpp
+++ b/src/server/game/Movement/Waypoints/WaypointManager.cpp
@@ -49,7 +49,6 @@ void WaypointMgr::Load()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 waypoints. DB table `waypoint_data` is empty!");
-
return;
}
@@ -87,7 +86,6 @@ void WaypointMgr::Load()
while (result->NextRow());
sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u waypoints in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
-
}
void WaypointMgr::ReloadPath(uint32 id)
diff --git a/src/server/game/Movement/Waypoints/WaypointManager.h b/src/server/game/Movement/Waypoints/WaypointManager.h
index 07f855380f9..b17714f1a51 100644
--- a/src/server/game/Movement/Waypoints/WaypointManager.h
+++ b/src/server/game/Movement/Waypoints/WaypointManager.h
@@ -68,4 +68,3 @@ class WaypointMgr
#define sWaypointMgr ACE_Singleton<WaypointMgr, ACE_Null_Mutex>::instance()
#endif
-
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index 8cbc4b62424..245ca7fd41d 100644
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -66,9 +66,11 @@ void AddSC_list_commandscript();
void AddSC_lookup_commandscript();
void AddSC_message_commandscript();
void AddSC_misc_commandscript();
+void AddSC_mmaps_commandscript();
void AddSC_modify_commandscript();
void AddSC_npc_commandscript();
void AddSC_quest_commandscript();
+void AddSC_rbac_commandscript();
void AddSC_reload_commandscript();
void AddSC_reset_commandscript();
void AddSC_server_commandscript();
@@ -695,9 +697,11 @@ void AddCommandScripts()
AddSC_list_commandscript();
AddSC_message_commandscript();
AddSC_misc_commandscript();
+ AddSC_mmaps_commandscript();
AddSC_modify_commandscript();
AddSC_npc_commandscript();
AddSC_quest_commandscript();
+ AddSC_rbac_commandscript();
AddSC_reload_commandscript();
AddSC_reset_commandscript();
AddSC_server_commandscript();
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index bdbfa46ba5d..5a973395c68 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -580,6 +580,8 @@ void ScriptMgr::OnPlayerEnterMap(Map* map, Player* player)
ASSERT(map);
ASSERT(player);
+ FOREACH_SCRIPT(PlayerScript)->OnMapChanged(player);
+
SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap);
itr->second->OnPlayerEnter(map, player);
SCR_MAP_END;
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index 92b5e8299e1..e9d040200e4 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -753,6 +753,9 @@ class PlayerScript : public UnitScript
// Called when a player switches to a new zone
virtual void OnUpdateZone(Player* /*player*/, uint32 /*newZone*/, uint32 /*newArea*/) { }
+
+ // Called when a player changes to a new map (after moving to new map)
+ virtual void OnMapChanged(Player* /*player*/) { }
};
class GuildScript : public ScriptObject
diff --git a/src/server/game/Server/Protocol/PacketLog.cpp b/src/server/game/Server/Protocol/PacketLog.cpp
index 649f4130c06..fe8b6804020 100644
--- a/src/server/game/Server/Protocol/PacketLog.cpp
+++ b/src/server/game/Server/Protocol/PacketLog.cpp
@@ -55,7 +55,7 @@ void PacketLog::LogPacket(WorldPacket const& packet, Direction direction)
data << uint8(direction);
for (uint32 i = 0; i < packet.size(); i++)
- data << const_cast<WorldPacket&>(packet)[i];
+ data << packet[i];
fwrite(data.contents(), 1, data.size(), _file);
fflush(_file);
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index bb108b0d1fa..d12128b11c1 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -22,6 +22,7 @@
#include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it
#include <zlib.h>
+#include "Config.h"
#include "Common.h"
#include "DatabaseEnv.h"
#include "Log.h"
@@ -119,7 +120,8 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8
_filterAddonMessages(false),
recruiterId(recruiter),
isRecruiter(isARecruiter),
- timeLastWhoCommand(0)
+ timeLastWhoCommand(0),
+ _RBACData(NULL)
{
if (sock)
{
@@ -160,8 +162,8 @@ WorldSession::~WorldSession()
m_Socket = NULL;
}
- if (_warden)
- delete _warden;
+ delete _warden;
+ delete _RBACData;
///- empty incoming packet queue
WorldPacket* packet = NULL;
@@ -862,7 +864,7 @@ void WorldSession::ReadAddonsInfo(WorldPacket &data)
ByteBuffer addonInfo;
addonInfo.resize(size);
- if (uncompress(const_cast<uint8*>(addonInfo.contents()), &uSize, const_cast<uint8*>(data.contents() + pos), data.size() - pos) == Z_OK)
+ if (uncompress(addonInfo.contents(), &uSize, data.contents() + pos, data.size() - pos) == Z_OK)
{
uint32 addonsCount;
addonInfo >> addonsCount; // addons count
@@ -1152,3 +1154,24 @@ void WorldSession::InitWarden(BigNumber* k, std::string const& os)
// _warden->Init(this, k);
}
}
+
+void WorldSession::LoadPermissions()
+{
+ uint32 id = GetAccountId();
+ std::string name;
+ int32 realmId = ConfigMgr::GetIntDefault("RealmID", 0);
+ AccountMgr::GetName(id, name);
+
+ _RBACData = new RBACData(id, name, realmId);
+ _RBACData->LoadFromDB();
+}
+
+RBACData* WorldSession::GetRBACData()
+{
+ return _RBACData;
+}
+
+bool WorldSession::HasPermission(uint32 permission)
+{
+ return _RBACData->HasPermission(permission);
+}
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index d2ef4c4eea5..419de3a466e 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -24,6 +24,7 @@
#define __WORLDSESSION_H
#include "Common.h"
+#include "AccountMgr.h"
#include "SharedDefines.h"
#include "AddonMgr.h"
#include "DatabaseEnv.h"
@@ -49,15 +50,18 @@ struct AreaTableEntry;
struct AuctionEntry;
struct DeclinedName;
struct ItemTemplate;
+struct MovementInfo;
+
+namespace lfg
+{
struct LfgJoinResultData;
-struct LfgLockStatus;
struct LfgPlayerBoot;
struct LfgProposal;
struct LfgQueueStatusData;
struct LfgPlayerRewardData;
struct LfgRoleCheck;
struct LfgUpdateData;
-struct MovementInfo;
+}
enum AccountDataType
{
@@ -218,6 +222,10 @@ class WorldSession
void SendAuthResponse(uint8 code, bool queued, uint32 queuePos = 0);
void SendClientCacheVersion(uint32 version);
+ RBACData* GetRBACData();
+ bool HasPermission(uint32 permissionId);
+ void LoadPermissions();
+
AccountTypes GetSecurity() const { return _security; }
uint32 GetAccountId() const { return _accountId; }
Player* GetPlayer() const { return _player; }
@@ -811,16 +819,16 @@ class WorldSession
void HandleLfrLeaveOpcode(WorldPacket& recvData);
void HandleLfgGetStatus(WorldPacket& recvData);
- void SendLfgUpdatePlayer(LfgUpdateData const& updateData);
- void SendLfgUpdateParty(LfgUpdateData const& updateData);
+ void SendLfgUpdatePlayer(lfg::LfgUpdateData const& updateData);
+ void SendLfgUpdateParty(lfg::LfgUpdateData const& updateData);
void SendLfgRoleChosen(uint64 guid, uint8 roles);
- void SendLfgRoleCheckUpdate(LfgRoleCheck const& pRoleCheck);
+ void SendLfgRoleCheckUpdate(lfg::LfgRoleCheck const& pRoleCheck);
void SendLfgLfrList(bool update);
- void SendLfgJoinResult(LfgJoinResultData const& joinData);
- void SendLfgQueueStatus(LfgQueueStatusData const& queueData);
- void SendLfgPlayerReward(LfgPlayerRewardData const& lfgPlayerRewardData);
- void SendLfgBootProposalUpdate(LfgPlayerBoot const& boot);
- void SendLfgUpdateProposal(LfgProposal const& proposal);
+ void SendLfgJoinResult(lfg::LfgJoinResultData const& joinData);
+ void SendLfgQueueStatus(lfg::LfgQueueStatusData const& queueData);
+ void SendLfgPlayerReward(lfg::LfgPlayerRewardData const& lfgPlayerRewardData);
+ void SendLfgBootProposalUpdate(lfg::LfgPlayerBoot const& boot);
+ void SendLfgUpdateProposal(lfg::LfgProposal const& proposal);
void SendLfgDisabled();
void SendLfgOfferContinue(uint32 dungeonEntry);
void SendLfgTeleportError(uint8 err);
@@ -1009,6 +1017,7 @@ class WorldSession
ACE_Based::LockedQueue<WorldPacket*, ACE_Thread_Mutex> _recvQueue;
time_t timeLastWhoCommand;
z_stream_s* _compressionStream;
+ RBACData* _RBACData;
};
#endif
/// @}
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index 24406cdbdab..295432dc956 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -844,6 +844,8 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
}
// Get the account information from the realmd database
+ // 0 1 2 3 4 5 6 7 8
+ // SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME);
stmt->setString(0, account);
@@ -860,15 +862,11 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
Field* fields = result->Fetch();
- uint8 expansion = fields[6].GetUInt8();
+ uint8 expansion = fields[4].GetUInt8();
uint32 world_expansion = sWorld->getIntConfig(CONFIG_EXPANSION);
if (expansion > world_expansion)
expansion = world_expansion;
- sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSocket::HandleAuthSession: (s, v) check s: %s v: %s",
- fields[5].GetCString(),
- fields[4].GetCString());
-
///- Re-check ip locking (same check as in realmd).
if (fields[3].GetUInt8() == 1) // if ip is locked
{
@@ -884,13 +882,13 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
k.SetHexStr(fields[1].GetCString());
- int64 mutetime = fields[7].GetInt64();
+ int64 mutetime = fields[5].GetInt64();
//! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now.
if (mutetime < 0)
{
mutetime = time(NULL) + llabs(mutetime);
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME);
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN);
stmt->setInt64(0, mutetime);
stmt->setUInt32(1, id);
@@ -898,12 +896,12 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
LoginDatabase.Execute(stmt);
}
- locale = LocaleConstant (fields[8].GetUInt8());
+ locale = LocaleConstant (fields[6].GetUInt8());
if (locale >= TOTAL_LOCALES)
locale = LOCALE_enUS;
- uint32 recruiter = fields[9].GetUInt32();
- std::string os = fields[10].GetString();
+ uint32 recruiter = fields[7].GetUInt32();
+ std::string os = fields[8].GetString();
// Must be done before WorldSession is created
if (sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED) && os != "Win" && os != "OSX")
@@ -1006,6 +1004,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
m_Session->LoadGlobalAccountData();
m_Session->LoadTutorialsData();
m_Session->ReadAddonsInfo(addonsData);
+ m_Session->LoadPermissions();
// Initialize Warden system only if it is enabled by config
if (sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED))
diff --git a/src/server/game/Skills/SkillDiscovery.cpp b/src/server/game/Skills/SkillDiscovery.cpp
index 9fc426323d1..e6ba28d5f1c 100644
--- a/src/server/game/Skills/SkillDiscovery.cpp
+++ b/src/server/game/Skills/SkillDiscovery.cpp
@@ -56,7 +56,6 @@ void LoadSkillDiscoveryTable()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 skill discovery definitions. DB table `skill_discovery_template` is empty.");
-
return;
}
@@ -154,7 +153,6 @@ void LoadSkillDiscoveryTable()
}
sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u skill discovery definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
-
}
uint32 GetExplicitDiscoverySpell(uint32 spellId, Player* player)
diff --git a/src/server/game/Skills/SkillExtraItems.cpp b/src/server/game/Skills/SkillExtraItems.cpp
index 170cf0e57a2..5c3b69e48d2 100644
--- a/src/server/game/Skills/SkillExtraItems.cpp
+++ b/src/server/game/Skills/SkillExtraItems.cpp
@@ -61,7 +61,6 @@ void LoadSkillExtraItemTable()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 spell specialization definitions. DB table `skill_extra_item_template` is empty.");
-
return;
}
@@ -75,28 +74,28 @@ void LoadSkillExtraItemTable()
if (!sSpellMgr->GetSpellInfo(spellId))
{
- sLog->outError(LOG_FILTER_GENERAL, "Skill specialization %u has non-existent spell id in `skill_extra_item_template`!", spellId);
+ sLog->outError(LOG_FILTER_SQL, "Skill specialization %u has non-existent spell id in `skill_extra_item_template`!", spellId);
continue;
}
uint32 requiredSpecialization = fields[1].GetUInt32();
if (!sSpellMgr->GetSpellInfo(requiredSpecialization))
{
- sLog->outError(LOG_FILTER_GENERAL, "Skill specialization %u have not existed required specialization spell id %u in `skill_extra_item_template`!", spellId, requiredSpecialization);
+ sLog->outError(LOG_FILTER_SQL, "Skill specialization %u have not existed required specialization spell id %u in `skill_extra_item_template`!", spellId, requiredSpecialization);
continue;
}
float additionalCreateChance = fields[2].GetFloat();
if (additionalCreateChance <= 0.0f)
{
- sLog->outError(LOG_FILTER_GENERAL, "Skill specialization %u has too low additional create chance in `skill_extra_item_template`!", spellId);
+ sLog->outError(LOG_FILTER_SQL, "Skill specialization %u has too low additional create chance in `skill_extra_item_template`!", spellId);
continue;
}
uint8 additionalMaxNum = fields[3].GetUInt8();
if (!additionalMaxNum)
{
- sLog->outError(LOG_FILTER_GENERAL, "Skill specialization %u has 0 max number of extra items in `skill_extra_item_template`!", spellId);
+ sLog->outError(LOG_FILTER_SQL, "Skill specialization %u has 0 max number of extra items in `skill_extra_item_template`!", spellId);
continue;
}
@@ -111,7 +110,6 @@ void LoadSkillExtraItemTable()
while (result->NextRow());
sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u spell specialization definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
-
}
bool canCreateExtraItems(Player* player, uint32 spellId, float &additionalChance, uint8 &additionalMax)
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 186cdb8c552..5f93551a099 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -504,8 +504,6 @@ int32 AuraEffect::CalculateAmount(Unit* caster)
}
}
- float DoneActualBenefit = 0.0f;
-
// custom amount calculations go here
switch (GetAuraType())
{
@@ -538,176 +536,8 @@ int32 AuraEffect::CalculateAmount(Unit* caster)
}
break;
case SPELL_AURA_SCHOOL_ABSORB:
- m_canBeRecalculated = false;
- if (!caster)
- break;
- switch (GetSpellInfo()->SpellFamilyName)
- {
- case SPELLFAMILY_MAGE:
- // Ice Barrier
- if (GetSpellInfo()->SpellFamilyFlags[1] & 0x1 && GetSpellInfo()->SpellFamilyFlags[2] & 0x8)
- {
- // +87% from sp bonus
- DoneActualBenefit += caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()) * 0.87f;
- }
- // Mage Ward
- else if (GetSpellInfo()->SpellFamilyFlags[0] & 0x8 && GetSpellInfo()->SpellFamilyFlags[2] & 0x8)
- {
- // +80.68% from sp bonus
- DoneActualBenefit += caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()) * 0.8068f;
- }
- break;
- case SPELLFAMILY_WARLOCK:
- // Shadow Ward
- if (m_spellInfo->SpellFamilyFlags[2] & 0x80000000)
- {
- // +80.68% from sp bonus
- DoneActualBenefit += caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()) * 0.8068f;
- }
- break;
- case SPELLFAMILY_PRIEST:
- // Power Word: Shield
- if (GetSpellInfo()->SpellFamilyFlags[0] & 0x1)
- {
- // +80.68% from sp bonus
- DoneActualBenefit += caster->SpellBaseHealingBonusDone(m_spellInfo->GetSchoolMask()) * 0.8068f;
- DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellInfo());
-
- amount += int32(DoneActualBenefit);
-
- // Twin Disciplines
- if (AuraEffect const* pAurEff = caster->GetAuraEffect(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, SPELLFAMILY_PRIEST, 2292, 0))
- AddPct(amount, pAurEff->GetAmount());
-
- // Reuse variable, not sure if this code below can be moved before Twin Disciplines
- DoneActualBenefit = float(amount);
- DoneActualBenefit *= caster->GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
- amount = int32(DoneActualBenefit);
-
- return amount;
- }
- break;
- default:
- break;
- }
- break;
case SPELL_AURA_MANA_SHIELD:
m_canBeRecalculated = false;
- if (!caster)
- break;
- // Mana Shield
- if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_MAGE && GetSpellInfo()->SpellFamilyFlags[0] & 0x8000 && m_spellInfo->SpellFamilyFlags[2] & 0x8)
- {
- // +80.7% from +spd bonus
- DoneActualBenefit += caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()) * 0.807f;
- }
- break;
- case SPELL_AURA_DUMMY:
- if (!caster)
- break;
- // Earth Shield
- if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[1] & 0x400)
- {
- amount = caster->SpellHealingBonusDone(GetBase()->GetUnitOwner(), GetSpellInfo(), amount, SPELL_DIRECT_DAMAGE);
- amount = GetBase()->GetUnitOwner()->SpellHealingBonusTaken(caster, GetSpellInfo(), amount, SPELL_DIRECT_DAMAGE);
- }
- break;
- case SPELL_AURA_PERIODIC_DAMAGE:
- if (!caster)
- break;
- // Rip
- if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[0] & 0x00800000)
- {
- m_canBeRecalculated = false;
- // 0.01*$AP*cp
- if (caster->GetTypeId() != TYPEID_PLAYER)
- break;
-
- uint8 cp = caster->ToPlayer()->GetComboPoints();
-
- // Idol of Feral Shadows. Cant be handled as SpellMod in SpellAura:Dummy due its dependency from CPs
- if (AuraEffect const* aurEff = caster->GetAuraEffect(34241, EFFECT_0))
- amount += cp * aurEff->GetAmount();
- // Idol of Worship. Cant be handled as SpellMod in SpellAura:Dummy due its dependency from CPs
- else if (AuraEffect const* aurEff = caster->GetAuraEffect(60774, EFFECT_0))
- amount += cp * aurEff->GetAmount();
-
- amount += uint32(CalculatePct(caster->GetTotalAttackPowerValue(BASE_ATTACK), cp));
- }
- // Rend
- else if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_WARRIOR && GetSpellInfo()->SpellFamilyFlags[0] & 0x20)
- {
- m_canBeRecalculated = false;
- // ${0.25 * 6 * (($MWB + $mwb) / 2 + $AP / 14 * $MWS)} bonus per tick
- float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
- int32 mws = caster->GetAttackTime(BASE_ATTACK);
- float mwb_min = caster->GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
- float mwb_max = caster->GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
- float mwb = ((mwb_min + mwb_max) / 2 + ap * mws / 14000) * 0.25f * 6.0f;
- amount += int32(caster->ApplyEffectModifiers(m_spellInfo, m_effIndex, mwb));
- }
- break;
- case SPELL_AURA_PERIODIC_ENERGIZE:
- switch (m_spellInfo->Id)
- {
- case 57669: // Replenishment (0.2% from max)
- amount = CalculatePct(GetBase()->GetUnitOwner()->GetMaxPower(POWER_MANA), amount);
- break;
- case 61782: // Infinite Replenishment
- amount = GetBase()->GetUnitOwner()->GetMaxPower(POWER_MANA) * 0.0025f;
- break;
- case 29166: // Innervate
- ApplyPct(amount, float(GetBase()->GetUnitOwner()->GetCreatePowers(POWER_MANA)) / GetTotalTicks());
- break;
- case 48391: // Owlkin Frenzy
- ApplyPct(amount, GetBase()->GetUnitOwner()->GetCreatePowers(POWER_MANA));
- break;
- default:
- break;
- }
- break;
- case SPELL_AURA_PERIODIC_HEAL:
- if (!caster)
- break;
- // Lightwell Renew
- if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellInfo->SpellFamilyFlags[2] & 0x4000)
- {
- if (caster->GetTypeId() == TYPEID_PLAYER)
- // Bonus from Glyph of Lightwell
- if (AuraEffect* modHealing = caster->GetAuraEffect(55673, 0))
- AddPct(amount, modHealing->GetAmount());
- }
- break;
- case SPELL_AURA_MOD_THREAT:
- {
- uint8 level_diff = 0;
- float multiplier = 0.0f;
- switch (GetId())
- {
- // Arcane Shroud
- case 26400:
- level_diff = GetBase()->GetUnitOwner()->getLevel() - 60;
- multiplier = 2;
- break;
- // The Eye of Diminution
- case 28862:
- level_diff = GetBase()->GetUnitOwner()->getLevel() - 60;
- multiplier = 1;
- break;
- }
- if (level_diff > 0)
- amount += int32(multiplier * level_diff);
- break;
- }
- case SPELL_AURA_MOD_INCREASE_HEALTH:
- // Vampiric Blood
- if (GetId() == 55233)
- amount = GetBase()->GetUnitOwner()->CountPctFromMaxHealth(amount);
- break;
- case SPELL_AURA_MOD_INCREASE_SPEED:
- // Dash - do not set speed if not in cat form
- if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_DRUID && GetSpellInfo()->SpellFamilyFlags[2] & 0x00000008)
- amount = GetBase()->GetUnitOwner()->GetShapeshiftForm() == FORM_CAT ? amount : 0;
break;
case SPELL_AURA_MOUNTED:
if (MountCapabilityEntry const* mountCapability = GetBase()->GetUnitOwner()->GetMountCapability(uint32(GetMiscValueB())))
@@ -751,13 +581,8 @@ int32 AuraEffect::CalculateAmount(Unit* caster)
default:
break;
}
- if (DoneActualBenefit != 0.0f)
- {
- DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellInfo());
- amount += (int32)DoneActualBenefit;
- }
- GetBase()->CallScriptEffectCalcAmountHandlers(const_cast<AuraEffect const*>(this), amount, m_canBeRecalculated);
+ GetBase()->CallScriptEffectCalcAmountHandlers(this, amount, m_canBeRecalculated);
amount *= GetBase()->GetStackAmount();
return amount;
}
@@ -791,7 +616,7 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer /*= tru
break;
}
- GetBase()->CallScriptEffectCalcPeriodicHandlers(const_cast<AuraEffect const*>(this), m_isPeriodic, m_amplitude);
+ GetBase()->CallScriptEffectCalcPeriodicHandlers(this, m_isPeriodic, m_amplitude);
if (!m_isPeriodic)
return;
@@ -845,32 +670,6 @@ void AuraEffect::CalculateSpellMod()
{
switch (GetAuraType())
{
- case SPELL_AURA_DUMMY:
- switch (GetSpellInfo()->SpellFamilyName)
- {
- case SPELLFAMILY_DRUID:
- switch (GetId())
- {
- case 34246: // Idol of the Emerald Queen
- case 60779: // Idol of Lush Moss
- {
- if (!m_spellmod)
- {
- m_spellmod = new SpellModifier(GetBase());
- m_spellmod->op = SPELLMOD_DOT;
- m_spellmod->type = SPELLMOD_FLAT;
- m_spellmod->spellId = GetId();
- m_spellmod->mask[1] = 0x0010;
- }
- m_spellmod->value = GetAmount()/7;
- }
- break;
- }
- break;
- default:
- break;
- }
- break;
case SPELL_AURA_ADD_FLAT_MODIFIER:
case SPELL_AURA_ADD_PCT_MODIFIER:
if (!m_spellmod)
@@ -879,7 +678,7 @@ void AuraEffect::CalculateSpellMod()
m_spellmod->op = SpellModOp(GetMiscValue());
ASSERT(m_spellmod->op < MAX_SPELLMOD);
- m_spellmod->type = SpellModType(GetAuraType()); // SpellModType value == spell aura types
+ m_spellmod->type = SpellModType(GetAuraType()); // SpellModType value == spell aura types
m_spellmod->spellId = GetId();
m_spellmod->mask = GetSpellInfo()->Effects[GetEffIndex()].SpellClassMask;
m_spellmod->charges = GetBase()->GetCharges();
@@ -889,7 +688,7 @@ void AuraEffect::CalculateSpellMod()
default:
break;
}
- GetBase()->CallScriptEffectCalcSpellModHandlers(const_cast<AuraEffect const*>(this), m_spellmod);
+ GetBase()->CallScriptEffectCalcSpellModHandlers(this, m_spellmod);
}
void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply)
@@ -948,15 +747,15 @@ void AuraEffect::HandleEffect(AuraApplication * aurApp, uint8 mode, bool apply)
// call scripts helping/replacing effect handlers
bool prevented = false;
if (apply)
- prevented = GetBase()->CallScriptEffectApplyHandlers(const_cast<AuraEffect const*>(this), const_cast<AuraApplication const*>(aurApp), (AuraEffectHandleModes)mode);
+ prevented = GetBase()->CallScriptEffectApplyHandlers(this, aurApp, (AuraEffectHandleModes)mode);
else
- prevented = GetBase()->CallScriptEffectRemoveHandlers(const_cast<AuraEffect const*>(this), const_cast<AuraApplication const*>(aurApp), (AuraEffectHandleModes)mode);
+ prevented = GetBase()->CallScriptEffectRemoveHandlers(this, aurApp, (AuraEffectHandleModes)mode);
// check if script events have removed the aura or if default effect prevention was requested
if ((apply && aurApp->GetRemoveMode()) || prevented)
return;
- (*this.*AuraEffectHandler [GetAuraType()])(const_cast<AuraApplication const*>(aurApp), mode, apply);
+ (*this.*AuraEffectHandler[GetAuraType()])(aurApp, mode, apply);
// check if script events have removed the aura or if default effect prevention was requested
if (apply && aurApp->GetRemoveMode())
@@ -964,9 +763,9 @@ void AuraEffect::HandleEffect(AuraApplication * aurApp, uint8 mode, bool apply)
// call scripts triggering additional events after apply/remove
if (apply)
- GetBase()->CallScriptAfterEffectApplyHandlers(const_cast<AuraEffect const*>(this), const_cast<AuraApplication const*>(aurApp), (AuraEffectHandleModes)mode);
+ GetBase()->CallScriptAfterEffectApplyHandlers(this, aurApp, (AuraEffectHandleModes)mode);
else
- GetBase()->CallScriptAfterEffectRemoveHandlers(const_cast<AuraEffect const*>(this), const_cast<AuraApplication const*>(aurApp), (AuraEffectHandleModes)mode);
+ GetBase()->CallScriptAfterEffectRemoveHandlers(this, aurApp, (AuraEffectHandleModes)mode);
}
void AuraEffect::HandleEffect(Unit* target, uint8 mode, bool apply)
@@ -1270,7 +1069,7 @@ void AuraEffect::PeriodicTick(AuraApplication * aurApp, Unit* caster) const
void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
- bool prevented = GetBase()->CallScriptEffectProcHandlers(const_cast<AuraEffect const*>(this), const_cast<AuraApplication const*>(aurApp), eventInfo);
+ bool prevented = GetBase()->CallScriptEffectProcHandlers(this, aurApp, eventInfo);
if (prevented)
return;
@@ -1295,7 +1094,7 @@ void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
break;
}
- GetBase()->CallScriptAfterEffectProcHandlers(const_cast<AuraEffect const*>(this), const_cast<AuraApplication const*>(aurApp), eventInfo);
+ GetBase()->CallScriptAfterEffectProcHandlers(this, aurApp, eventInfo);
}
void AuraEffect::CleanupTriggeredSpells(Unit* target)
@@ -2649,7 +2448,10 @@ void AuraEffect::HandleAuraTrackCreatures(AuraApplication const* aurApp, uint8 m
if (target->GetTypeId() != TYPEID_PLAYER)
return;
- target->SetUInt32Value(PLAYER_TRACK_CREATURES, (apply) ? ((uint32)1)<<(GetMiscValue()-1) : 0);
+ if (apply)
+ target->SetFlag(PLAYER_TRACK_CREATURES, uint32(1) << (GetMiscValue() - 1));
+ else
+ target->RemoveFlag(PLAYER_TRACK_CREATURES, uint32(1) << (GetMiscValue() - 1));
}
void AuraEffect::HandleAuraTrackResources(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -2662,7 +2464,10 @@ void AuraEffect::HandleAuraTrackResources(AuraApplication const* aurApp, uint8 m
if (target->GetTypeId() != TYPEID_PLAYER)
return;
- target->SetUInt32Value(PLAYER_TRACK_RESOURCES, (apply) ? ((uint32)1)<<(GetMiscValue()-1): 0);
+ if (apply)
+ target->SetFlag(PLAYER_TRACK_RESOURCES, uint32(1) << (GetMiscValue() - 1));
+ else
+ target->RemoveFlag(PLAYER_TRACK_RESOURCES, uint32(1) << (GetMiscValue() - 1));
}
void AuraEffect::HandleAuraTrackStealthed(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -2774,6 +2579,8 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo
if (apply)
{
uint32 creatureEntry = GetMiscValue();
+ uint32 displayId = 0;
+ uint32 vehicleId = 0;
// Festive Holiday Mount
if (target->HasAura(62061))
@@ -2784,30 +2591,28 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo
creatureEntry = 15665;
}
- CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(creatureEntry);
- if (!ci)
+ if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(creatureEntry))
{
- sLog->outError(LOG_FILTER_SQL, "AuraMounted: `creature_template`='%u' not found in database (only need its modelid)", GetMiscValue());
- return;
- }
+ uint32 team = 0;
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ team = target->ToPlayer()->GetTeam();
- uint32 team = 0;
- if (target->GetTypeId() == TYPEID_PLAYER)
- team = target->ToPlayer()->GetTeam();
+ displayId = ObjectMgr::ChooseDisplayId(team, ci);
+ sObjectMgr->GetCreatureModelRandomGender(&displayId);
- uint32 displayID = ObjectMgr::ChooseDisplayId(team, ci);
- sObjectMgr->GetCreatureModelRandomGender(&displayID);
+ vehicleId = ci->VehicleId;
- //some spell has one aura of mount and one of vehicle
- for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- if (GetSpellInfo()->Effects[i].Effect == SPELL_EFFECT_SUMMON
- && GetSpellInfo()->Effects[i].MiscValue == GetMiscValue())
- displayID = 0;
+ //some spell has one aura of mount and one of vehicle
+ for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (GetSpellInfo()->Effects[i].Effect == SPELL_EFFECT_SUMMON
+ && GetSpellInfo()->Effects[i].MiscValue == GetMiscValue())
+ displayId = 0;
+ }
- target->Mount(displayID, ci->VehicleId, GetMiscValue());
+ target->Mount(displayId, vehicleId, creatureEntry);
// cast speed aura
- if (MountCapabilityEntry const* mountCapability = target->GetMountCapability(uint32(GetMiscValueB())))
+ if (MountCapabilityEntry const* mountCapability = sMountCapabilityStore.LookupEntry(GetAmount()))
target->CastSpell(target, mountCapability->SpeedModSpell, true);
}
else
@@ -3624,22 +3429,19 @@ void AuraEffect::HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint
Unit* target = aurApp->GetTarget();
- target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, GetMiscValue(), apply);
+ target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, GetMiscValue(), apply);
// when removing flag aura, handle flag drop
- if (!apply && target->GetTypeId() == TYPEID_PLAYER
- && (GetSpellInfo()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION))
+ Player* player = target->ToPlayer();
+ if (!apply && player && (GetSpellInfo()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION))
{
- if (target->GetTypeId() == TYPEID_PLAYER)
+ if (player->InBattleground())
{
- if (target->ToPlayer()->InBattleground())
- {
- if (Battleground* bg = target->ToPlayer()->GetBattleground())
- bg->EventPlayerDroppedFlag(target->ToPlayer());
- }
- else
- sOutdoorPvPMgr->HandleDropFlag((Player*)target, GetSpellInfo()->Id);
+ if (Battleground* bg = player->GetBattleground())
+ bg->EventPlayerDroppedFlag(player);
}
+ else
+ sOutdoorPvPMgr->HandleDropFlag(player, GetSpellInfo()->Id);
}
}
@@ -4916,10 +4718,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
if (Aura* newAura = target->AddAura(71564, target))
newAura->SetStackAmount(newAura->GetSpellInfo()->StackAmount);
break;
- case 59628: // Tricks of the Trade
- if (caster && caster->GetMisdirectionTarget())
- target->SetReducedThreatPercent(100, caster->GetMisdirectionTarget()->GetGUID());
- break;
}
}
// AT REMOVE
@@ -5014,20 +4812,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
if (GetId() == 61777)
target->CastSpell(target, GetAmount(), true);
break;
- case SPELLFAMILY_ROGUE:
- // Tricks of the trade
- switch (GetId())
- {
- case 59628: //Tricks of the trade buff on rogue (6sec duration)
- target->SetReducedThreatPercent(0, 0);
- break;
- case 57934: //Tricks of the trade buff on rogue (30sec duration)
- if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE || !caster->GetMisdirectionTarget())
- target->SetReducedThreatPercent(0, 0);
- else
- target->SetReducedThreatPercent(0, caster->GetMisdirectionTarget()->GetGUID());
- break;
- }
default:
break;
}
@@ -5298,10 +5082,6 @@ void AuraEffect::HandleAuraEmpathy(AuraApplication const* aurApp, uint8 mode, bo
return;
Unit* target = aurApp->GetTarget();
-
- if (target->GetTypeId() != TYPEID_UNIT)
- return;
-
if (!apply)
{
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
@@ -5309,8 +5089,7 @@ void AuraEffect::HandleAuraEmpathy(AuraApplication const* aurApp, uint8 mode, bo
return;
}
- CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(target->GetEntry());
- if (ci && ci->type == CREATURE_TYPE_BEAST)
+ if (target->GetCreatureType() == CREATURE_TYPE_BEAST)
target->ApplyModUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO, apply);
}
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index d578b3507c6..4abca023dd3 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -1388,17 +1388,6 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
// mods at aura apply or remove
switch (GetSpellInfo()->SpellFamilyName)
{
- case SPELLFAMILY_GENERIC:
- switch (GetId())
- {
- case 50720: // Vigilance
- if (apply)
- target->CastSpell(caster, 59665, true, 0, 0, caster->GetGUID());
- else
- target->SetReducedThreatPercent(0, 0);
- break;
- }
- break;
case SPELLFAMILY_DRUID:
// Enrage
if ((GetSpellInfo()->SpellFamilyFlags[0] & 0x80000) && GetSpellInfo()->SpellIconID == 961)
@@ -1781,14 +1770,14 @@ float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& event
void Aura::TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
- CallScriptProcHandlers(const_cast<AuraApplication const*>(aurApp), eventInfo);
+ CallScriptProcHandlers(aurApp, eventInfo);
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (aurApp->HasEffect(i))
// OnEffectProc / AfterEffectProc hooks handled in AuraEffect::HandleProc()
GetEffect(i)->HandleProc(aurApp, eventInfo);
- CallScriptAfterProcHandlers(const_cast<AuraApplication const*>(aurApp), eventInfo);
+ CallScriptAfterProcHandlers(aurApp, eventInfo);
// Remove aura if we've used last charge to proc
if (IsUsingCharges() && !GetCharges())
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 2619ef0eeb6..ba570ad73a4 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -491,7 +491,7 @@ SpellValue::SpellValue(SpellInfo const* proto)
Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, uint64 originalCasterGUID, bool skipCheck) :
m_spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(info, caster)),
m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster)
-, m_spellValue(new SpellValue(m_spellInfo))
+, m_spellValue(new SpellValue(m_spellInfo)), m_preGeneratedPath(PathGenerator(m_caster))
{
m_customError = SPELL_CUSTOM_ERROR_NONE;
m_skipCheck = skipCheck;
@@ -611,6 +611,7 @@ Spell::~Spell()
if (m_caster && m_caster->GetTypeId() == TYPEID_PLAYER)
ASSERT(m_caster->ToPlayer()->m_spellModTakingSpell != this);
+
delete m_spellValue;
CheckEffectExecuteData();
@@ -1342,11 +1343,6 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge
}
}
- // todo: move to scripts, but we must call it before resize list by MaxAffectedTargets
- // Intimidating Shout
- if (m_spellInfo->Id == 5246 && effIndex != EFFECT_0)
- unitTargets.remove(m_targets.GetUnitTarget());
-
// Other special target selection goes here
if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
Trinity::Containers::RandomResizeList(unitTargets, maxTargets);
@@ -5189,12 +5185,30 @@ SpellCastResult Spell::CheckCast(bool strict)
if (strict && m_caster->IsScriptOverriden(m_spellInfo, 6953))
m_caster->RemoveMovementImpairingAuras();
}
+
if (m_caster->HasUnitState(UNIT_STATE_ROOT))
return SPELL_FAILED_ROOTED;
+
+ Unit* target = m_targets.GetUnitTarget();
+
+ if (!target)
+ return SPELL_FAILED_DONT_REPORT;
+
if (m_caster->GetTypeId() == TYPEID_PLAYER)
- if (Unit* target = m_targets.GetUnitTarget())
- if (!target->isAlive())
- return SPELL_FAILED_BAD_TARGETS;
+ if (!target->isAlive())
+ return SPELL_FAILED_BAD_TARGETS;
+
+ Position pos;
+ target->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ);
+ target->GetFirstCollisionPosition(pos, CONTACT_DISTANCE, target->GetRelativeAngle(m_caster));
+
+ m_preGeneratedPath.SetPathLengthLimit(m_spellInfo->GetMaxRange(true) * 1.5f);
+ bool result = m_preGeneratedPath.CalculatePath(pos.m_positionX, pos.m_positionY, pos.m_positionZ + target->GetObjectSize());
+ if (m_preGeneratedPath.GetPathType() & PATHFIND_SHORT)
+ return SPELL_FAILED_OUT_OF_RANGE;
+ else if (!result)
+ return SPELL_FAILED_NOPATH;
+
break;
}
case SPELL_EFFECT_SKINNING:
@@ -6520,7 +6534,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff) const
break;
}
- if (IsTriggered() || m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS)
+ if (IsTriggered() || m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS))
return true;
// todo: shit below shouldn't be here, but it's temporary
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index c7415d4c9d3..27474645d77 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -23,6 +23,7 @@
#include "SharedDefines.h"
#include "ObjectMgr.h"
#include "SpellInfo.h"
+#include "PathGenerator.h"
class Unit;
class Player;
@@ -669,6 +670,7 @@ class Spell
bool m_skipCheck;
uint8 m_auraScaleMask;
+ PathGenerator m_preGeneratedPath;
ByteBuffer * m_effectExecuteData[MAX_SPELL_EFFECTS];
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index e86ac6ef97f..bb730b94002 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -63,6 +63,7 @@
#include "GameObjectAI.h"
#include "AccountMgr.h"
#include "InstanceScript.h"
+#include "PathGenerator.h"
#include "Guild.h"
#include "GuildMgr.h"
#include "ReputationMgr.h"
@@ -756,12 +757,6 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex)
m_caster->CastSpell(unitTarget, spell->Id, true);
return;
}
- // Righteous Defense
- case 31980:
- {
- m_caster->CastSpell(unitTarget, 31790, true);
- return;
- }
// Cloak of Shadows
case 35729:
{
@@ -1012,32 +1007,8 @@ void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/)
return;
// Pre effects
- uint8 uiMaxSafeLevel = 0;
switch (m_spellInfo->Id)
{
- case 48129: // Scroll of Recall
- uiMaxSafeLevel = 40;
- case 60320: // Scroll of Recall II
- if (!uiMaxSafeLevel)
- uiMaxSafeLevel = 70;
- case 60321: // Scroll of Recal III
- if (!uiMaxSafeLevel)
- uiMaxSafeLevel = 80;
-
- if (unitTarget->getLevel() > uiMaxSafeLevel)
- {
- unitTarget->AddAura(60444, unitTarget); //Apply Lost! Aura
-
- // ALLIANCE from 60323 to 60330 - HORDE from 60328 to 60335
- uint32 spellId = 60323;
- if (m_caster->ToPlayer()->GetTeam() == HORDE)
- spellId += 5;
-
- spellId += urand(0, 7);
- m_caster->CastSpell(m_caster, spellId, true);
- return;
- }
- break;
case 66550: // teleports outside (Isle of Conquest)
if (Player* target = unitTarget->ToPlayer())
{
@@ -1061,7 +1032,7 @@ void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/)
// If not exist data for dest location - return
if (!m_targets.HasDst())
{
- sLog->outError(LOG_FILTER_SPELLS_AURAS, "Spell::EffectTeleportUnits - does not have destination for spell ID %u\n", m_spellInfo->Id);
+ sLog->outError(LOG_FILTER_SPELLS_AURAS, "Spell::EffectTeleportUnits - does not have destination for spellId %u.", m_spellInfo->Id);
return;
}
@@ -1432,10 +1403,6 @@ void Spell::EffectHealPct(SpellEffIndex /*effIndex*/)
if (!m_originalCaster)
return;
- // Rune Tap - Party
- if (m_spellInfo->Id == 59754 && unitTarget == m_caster)
- return;
-
uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, unitTarget->CountPctFromMaxHealth(damage), HEAL);
heal = unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL);
@@ -3020,24 +2987,6 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
switch (m_spellInfo->SpellFamilyName)
{
- case SPELLFAMILY_GENERIC:
- {
- switch (m_spellInfo->Id)
- {
- case 69055: // Saber Lash
- case 70814: // Saber Lash
- {
- uint32 count = 0;
- for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
- if (ihit->effectMask & (1 << effIndex))
- ++count;
-
- totalDamagePercentMod /= count;
- break;
- }
- }
- break;
- }
case SPELLFAMILY_WARRIOR:
{
// Devastate (player ones)
@@ -3440,23 +3389,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
return;
unitTarget->RemoveAurasDueToSpell(m_spellInfo->Effects[effIndex].CalcValue());
break;
- // PX-238 Winter Wondervolt TRAP
- case 26275:
- {
- uint32 spells[4] = { 26272, 26157, 26273, 26274 };
-
- // check presence
- for (uint8 j = 0; j < 4; ++j)
- if (unitTarget->HasAuraEffect(spells[j], 0))
- return;
-
- // select spell
- uint32 iTmpSpellId = spells[urand(0, 3)];
-
- // cast
- unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
- return;
- }
// Bending Shinbone
case 8856:
{
@@ -3502,14 +3434,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
m_caster->CastSpell(unitTarget, 22682, true);
return;
}
- // Piccolo of the Flaming Fire
- case 17512:
- {
- if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
- return;
- unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
- return;
- }
// Decimate
case 28374:
case 54426:
@@ -3652,17 +3576,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
m_caster->MonsterTextEmote(buf, 0);
break;
}
- // Vigilance
- case 50725:
- {
- if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
- return;
-
- // Remove Taunt cooldown
- unitTarget->ToPlayer()->RemoveSpellCooldown(355, true);
-
- return;
- }
// Death Knight Initiate Visual
case 51519:
{
@@ -3821,17 +3734,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
}
return;
}
- case 63845: // Create Lance
- {
- if (m_caster->GetTypeId() != TYPEID_PLAYER)
- return;
-
- if (m_caster->ToPlayer()->GetTeam() == ALLIANCE)
- m_caster->CastSpell(m_caster, 63914, true);
- else
- m_caster->CastSpell(m_caster, 63919, true);
- return;
- }
case 59317: // Teleporting
{
@@ -4025,46 +3927,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
return;
}
}
- case SPELLFAMILY_POTION:
- {
- switch (m_spellInfo->Id)
- {
- // Netherbloom
- case 28702:
- {
- if (!unitTarget)
- return;
- // 25% chance of casting a random buff
- if (roll_chance_i(75))
- return;
-
- // triggered spells are 28703 to 28707
- // Note: some sources say, that there was the possibility of
- // receiving a debuff. However, this seems to be removed by a patch.
- const uint32 spellid = 28703;
-
- // don't overwrite an existing aura
- for (uint8 i = 0; i < 5; ++i)
- if (unitTarget->HasAura(spellid + i))
- return;
- unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
- break;
- }
-
- // Nightmare Vine
- case 28720:
- {
- if (!unitTarget)
- return;
- // 25% chance of casting Nightmare Pollen
- if (roll_chance_i(75))
- return;
- unitTarget->CastSpell(unitTarget, 28721, true);
- break;
- }
- }
- break;
- }
case SPELLFAMILY_DEATHKNIGHT:
{
// Pestilence
@@ -4085,19 +3947,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
}
break;
}
- case SPELLFAMILY_WARRIOR:
- {
- // Shattering Throw
- if (m_spellInfo->SpellFamilyFlags[1] & 0x00400000)
- {
- if (!unitTarget)
- return;
- // remove shields, will still display immune to damage part
- unitTarget->RemoveAurasWithMechanic(1<<MECHANIC_IMMUNE_SHIELD, AURA_REMOVE_BY_ENEMY_SPELL);
- return;
- }
- break;
- }
}
// normal DB scripted effect
@@ -4580,45 +4429,12 @@ void Spell::EffectResurrect(SpellEffIndex effIndex)
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
return;
- if (!unitTarget)
- return;
- if (unitTarget->GetTypeId() != TYPEID_PLAYER)
+ if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
- if (unitTarget->isAlive())
- return;
- if (!unitTarget->IsInWorld())
+ if (unitTarget->isAlive() || !unitTarget->IsInWorld())
return;
- switch (m_spellInfo->Id)
- {
- // Defibrillate (Goblin Jumper Cables) have 33% chance on success
- case 8342:
- if (roll_chance_i(67))
- {
- m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
- return;
- }
- break;
- // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
- case 22999:
- if (roll_chance_i(50))
- {
- m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
- return;
- }
- break;
- // Defibrillate (Gnomish Army Knife) have 67% chance on success_list
- case 54732:
- if (roll_chance_i(33))
- {
- return;
- }
- break;
- default:
- break;
- }
-
Player* target = unitTarget->ToPlayer();
if (target->IsRessurectRequested()) // already have one active request
@@ -4810,25 +4626,24 @@ void Spell::EffectSkinning(SpellEffIndex /*effIndex*/)
void Spell::EffectCharge(SpellEffIndex /*effIndex*/)
{
+ if (!unitTarget)
+ return;
+
if (effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
{
- if (!unitTarget)
- return;
-
- float angle = unitTarget->GetRelativeAngle(m_caster);
- Position pos;
-
- unitTarget->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ);
- unitTarget->GetFirstCollisionPosition(pos, unitTarget->GetObjectSize(), angle);
-
- m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ + unitTarget->GetObjectSize());
+ if (m_preGeneratedPath.GetPathType() & PATHFIND_NOPATH)
+ {
+ Position pos;
+ unitTarget->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ);
+ unitTarget->GetFirstCollisionPosition(pos, unitTarget->GetObjectSize(), unitTarget->GetRelativeAngle(m_caster));
+ m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ);
+ }
+ else
+ m_caster->GetMotionMaster()->MoveCharge(m_preGeneratedPath);
}
if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET)
{
- if (!unitTarget)
- return;
-
// not all charge effects used in negative spells
if (!m_spellInfo->IsPositive() && m_caster->GetTypeId() == TYPEID_PLAYER)
m_caster->Attack(unitTarget, true);
@@ -4864,26 +4679,10 @@ void Spell::EffectKnockBack(SpellEffIndex effIndex)
if (creatureTarget->isWorldBoss() || creatureTarget->IsDungeonBoss())
return;
- // Spells with SPELL_EFFECT_KNOCK_BACK(like Thunderstorm) can't knoback target if target has ROOT/STUN
+ // Spells with SPELL_EFFECT_KNOCK_BACK (like Thunderstorm) can't knockback target if target has ROOT/STUN
if (unitTarget->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
return;
- // Typhoon
- if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[1] & 0x01000000)
- {
- // Glyph of Typhoon
- if (m_caster->HasAura(62135))
- return;
- }
-
- // Thunderstorm
- if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[1] & 0x00002000)
- {
- // Glyph of Thunderstorm
- if (m_caster->HasAura(62132))
- return;
- }
-
// Instantly interrupt non melee spells being casted
if (unitTarget->IsNonMeleeSpellCasted(true))
unitTarget->InterruptNonMeleeSpells(true);
@@ -5687,7 +5486,7 @@ void Spell::EffectRedirectThreat(SpellEffIndex /*effIndex*/)
return;
if (unitTarget)
- m_caster->SetReducedThreatPercent((uint32)damage, unitTarget->GetGUID());
+ m_caster->SetRedirectThreat(unitTarget->GetGUID(), uint32(damage));
}
void Spell::EffectGameObjectDamage(SpellEffIndex /*effIndex*/)
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index e85d0e2bfe6..aadc30e3921 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -386,7 +386,7 @@ bool SpellEffectInfo::IsAura() const
bool SpellEffectInfo::IsAura(AuraType aura) const
{
- return IsAura() && AuraType(ApplyAuraName) == uint32(aura);
+ return IsAura() && ApplyAuraName == uint32(aura);
}
bool SpellEffectInfo::IsTargetingArea() const
@@ -1007,7 +1007,7 @@ bool SpellInfo::IsLootCrafting() const
return (Effects[0].Effect == SPELL_EFFECT_CREATE_RANDOM_ITEM ||
// different random cards from Inscription (121==Virtuoso Inking Set category) r without explicit item
(Effects[0].Effect == SPELL_EFFECT_CREATE_ITEM_2 &&
- (TotemCategory[0] != 0 || Effects[0].ItemType == 0)));
+ ((TotemCategory[0] != 0 || (Totem[0] != 0 && SpellIconID == 1)) || Effects[0].ItemType == 0)));
}
bool SpellInfo::IsQuestTame() const
@@ -2095,6 +2095,9 @@ SpellSpecificType SpellInfo::GetSpellSpecific() const
case SPELL_AURA_AOE_CHARM:
return SPELL_SPECIFIC_CHARM;
case SPELL_AURA_TRACK_CREATURES:
+ /// @workaround For non-stacking tracking spells (We need generic solution)
+ if (Id == 30645) // Gas Cloud Tracking
+ return SPELL_SPECIFIC_NORMAL;
case SPELL_AURA_TRACK_RESOURCES:
case SPELL_AURA_TRACK_STEALTHED:
return SPELL_SPECIFIC_TRACKER;
@@ -2244,9 +2247,17 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) c
return 0;
}
}
- SpellSchools school = GetFirstSchoolInMask(schoolMask);
- // Flat mod from caster auras by spell school
- powerCost += caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school);
+
+ // Flat mod from caster auras by spell school and power type
+ Unit::AuraEffectList const& auras = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL);
+ for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
+ {
+ if (!((*i)->GetMiscValue() & schoolMask))
+ continue;
+ if (!((*i)->GetMiscValueB() & (1 << PowerType)))
+ continue;
+ powerCost += (*i)->GetAmount();
+ }
// Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost)
if (AttributesEx4 & SPELL_ATTR4_SPELL_VS_EXTEND_COST)
powerCost += caster->GetAttackTime(OFF_ATTACK) / 100;
@@ -2257,8 +2268,16 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) c
if (Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION)
powerCost = int32(powerCost / (1.117f * SpellLevel / caster->getLevel() -0.1327f));
- // PCT mod from user auras by school
- powerCost = int32(powerCost * (1.0f + caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER + school)));
+ // PCT mod from user auras by spell school and power type
+ Unit::AuraEffectList const& aurasPct = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT);
+ for (Unit::AuraEffectList::const_iterator i = aurasPct.begin(); i != aurasPct.end(); ++i)
+ {
+ if (!((*i)->GetMiscValue() & schoolMask))
+ continue;
+ if (!((*i)->GetMiscValueB() & (1 << PowerType)))
+ continue;
+ powerCost += CalculatePct(powerCost, (*i)->GetAmount());
+ }
if (powerCost < 0)
powerCost = 0;
return powerCost;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 4ce2604810c..b648a14fce5 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3382,7 +3382,7 @@ void SpellMgr::LoadSpellInfoCorrections()
break;
case 69055: // Saber Lash (Lord Marrowgar)
case 70814: // Saber Lash (Lord Marrowgar)
- spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_5_YARDS); // 5yd
+ spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_8_YARDS); // 8yd
break;
case 69075: // Bone Storm (Lord Marrowgar)
case 70834: // Bone Storm (Lord Marrowgar)
diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp
index 89ed223545f..6229a30a5f0 100644
--- a/src/server/game/Spells/SpellScript.cpp
+++ b/src/server/game/Spells/SpellScript.cpp
@@ -612,7 +612,7 @@ SpellValue const* SpellScript::GetSpellValue()
bool AuraScript::_Validate(SpellInfo const* entry)
{
for (std::list<CheckAreaTargetHandler>::iterator itr = DoCheckAreaTarget.begin(); itr != DoCheckAreaTarget.end(); ++itr)
- if (!entry->HasAreaAuraEffect())
+ if (!entry->HasAreaAuraEffect() && !entry->HasEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA))
sLog->outError(LOG_FILTER_TSCR, "Spell `%u` of script `%s` does not have area aura effect - handler bound to hook `DoCheckAreaTarget` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
for (std::list<AuraDispelHandler>::iterator itr = OnDispel.begin(); itr != OnDispel.end(); ++itr)
diff --git a/src/server/game/Tickets/TicketMgr.cpp b/src/server/game/Tickets/TicketMgr.cpp
index f030b3dc6f2..55b4d3f2e22 100644
--- a/src/server/game/Tickets/TicketMgr.cpp
+++ b/src/server/game/Tickets/TicketMgr.cpp
@@ -41,7 +41,7 @@ GmTicket::GmTicket(Player* player, WorldPacket& recvData) : _createTime(time(NUL
_playerGuid = player->GetGUID();
uint32 mapId;
- recvData >> mapId; // Map is sent as UInt32!
+ recvData >> mapId; // Map is sent as UInt32!
_mapId = mapId;
recvData >> _posX;
diff --git a/src/server/game/Tools/CharacterDatabaseCleaner.cpp b/src/server/game/Tools/CharacterDatabaseCleaner.cpp
index 379b6fc6225..29d96cc0cfe 100644
--- a/src/server/game/Tools/CharacterDatabaseCleaner.cpp
+++ b/src/server/game/Tools/CharacterDatabaseCleaner.cpp
@@ -23,7 +23,6 @@
#include "Database/DatabaseEnv.h"
#include "SpellMgr.h"
#include "DBCStores.h"
-#include "AchievementMgr.h"
void CharacterDatabaseCleaner::CleanDatabase()
{
diff --git a/src/server/game/Warden/Warden.cpp b/src/server/game/Warden/Warden.cpp
index a99688c8844..af695c482cf 100644
--- a/src/server/game/Warden/Warden.cpp
+++ b/src/server/game/Warden/Warden.cpp
@@ -219,7 +219,7 @@ std::string Warden::Penalty(WardenCheck* check /*= NULL*/)
void WorldSession::HandleWardenDataOpcode(WorldPacket& recvData)
{
- _warden->DecryptData(const_cast<uint8*>(recvData.contents()), recvData.size());
+ _warden->DecryptData(recvData.contents(), recvData.size());
uint8 opcode;
recvData >> opcode;
sLog->outDebug(LOG_FILTER_WARDEN, "Got packet, opcode %02X, size %u", opcode, uint32(recvData.size()));
diff --git a/src/server/game/Warden/WardenCheckMgr.cpp b/src/server/game/Warden/WardenCheckMgr.cpp
index c6542c68360..ec271192450 100644
--- a/src/server/game/Warden/WardenCheckMgr.cpp
+++ b/src/server/game/Warden/WardenCheckMgr.cpp
@@ -44,7 +44,6 @@ void WardenCheckMgr::LoadWardenChecks()
if (!sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED))
{
sLog->outInfo(LOG_FILTER_WARDEN, ">> Warden disabled, loading checks skipped.");
-
return;
}
@@ -53,7 +52,6 @@ void WardenCheckMgr::LoadWardenChecks()
if (!result)
{
sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 Warden checks. DB table `warden_checks` is empty!");
-
return;
}
@@ -145,8 +143,7 @@ void WardenCheckMgr::LoadWardenChecks()
}
while (result->NextRow());
- sLog->outInfo(LOG_FILTER_WARDEN, ">> Loaded %u warden checks.", count);
-
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u warden checks.", count);
}
void WardenCheckMgr::LoadWardenOverrides()
@@ -155,7 +152,6 @@ void WardenCheckMgr::LoadWardenOverrides()
if (!sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED))
{
sLog->outInfo(LOG_FILTER_WARDEN, ">> Warden disabled, loading check overrides skipped.");
-
return;
}
@@ -165,7 +161,6 @@ void WardenCheckMgr::LoadWardenOverrides()
if (!result)
{
sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 Warden action overrides. DB table `warden_action` is empty!");
-
return;
}
@@ -194,8 +189,7 @@ void WardenCheckMgr::LoadWardenOverrides()
}
while (result->NextRow());
- sLog->outInfo(LOG_FILTER_WARDEN, ">> Loaded %u warden action overrides.", count);
-
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u warden action overrides.", count);
}
WardenCheck* WardenCheckMgr::GetWardenDataById(uint16 Id)
diff --git a/src/server/game/Warden/WardenMac.cpp b/src/server/game/Warden/WardenMac.cpp
index 7c2979e0dc6..fa84cd216b6 100644
--- a/src/server/game/Warden/WardenMac.cpp
+++ b/src/server/game/Warden/WardenMac.cpp
@@ -206,7 +206,7 @@ void WardenMac::RequestData()
buff.hexlike();
// Encrypt with warden RC4 key.
- EncryptData(const_cast<uint8*>(buff.contents()), buff.size());
+ EncryptData(buff.contents(), buff.size());
WorldPacket pkt(SMSG_WARDEN_DATA, buff.size());
pkt.append(buff);
diff --git a/src/server/game/Warden/WardenWin.cpp b/src/server/game/Warden/WardenWin.cpp
index 4da05eded0c..bf423459222 100644
--- a/src/server/game/Warden/WardenWin.cpp
+++ b/src/server/game/Warden/WardenWin.cpp
@@ -310,7 +310,7 @@ void WardenWin::RequestData()
buff.hexlike();
// Encrypt with warden RC4 key
- EncryptData(const_cast<uint8*>(buff.contents()), buff.size());
+ EncryptData(buff.contents(), buff.size());
WorldPacket pkt(SMSG_WARDEN_DATA, buff.size());
pkt.append(buff);
diff --git a/src/server/game/Weather/WeatherMgr.cpp b/src/server/game/Weather/WeatherMgr.cpp
index 8bfa74d07e5..5eff13725b9 100644
--- a/src/server/game/Weather/WeatherMgr.cpp
+++ b/src/server/game/Weather/WeatherMgr.cpp
@@ -98,7 +98,6 @@ void LoadWeatherData()
if (!result)
{
sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 weather definitions. DB table `game_weather` is empty.");
-
return;
}
@@ -142,7 +141,6 @@ void LoadWeatherData()
while (result->NextRow());
sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u weather definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
-
}
void SendFineWeatherUpdateToPlayer(Player* player)
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 4b027e9ebbf..4a1d1566af1 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -21,6 +21,7 @@
*/
#include "Common.h"
+#include "Memory.h"
#include "DatabaseEnv.h"
#include "Config.h"
#include "SystemConfig.h"
@@ -55,6 +56,7 @@
#include "TemporarySummon.h"
#include "WaypointMovementGenerator.h"
#include "VMapFactory.h"
+#include "MMapFactory.h"
#include "GameEventMgr.h"
#include "PoolMgr.h"
#include "GridNotifiersImpl.h"
@@ -137,6 +139,7 @@ World::~World()
delete command;
VMAP::VMapFactory::clear();
+ MMAP::MMapFactory::clear();
//TODO free addSessQueue
}
@@ -266,7 +269,7 @@ void World::AddSession_(WorldSession* s)
if (decrease_session)
--Sessions;
- if (pLimit > 0 && Sessions >= pLimit && AccountMgr::IsPlayerAccount(s->GetSecurity()) && !HasRecentlyDisconnected(s))
+ if (pLimit > 0 && Sessions >= pLimit && !s->HasPermission(RBAC_PERM_SKIP_QUEUE) && !HasRecentlyDisconnected(s))
{
AddQueuedPlayer(s);
UpdateMaxSessionCounters();
@@ -584,7 +587,6 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_TICKET_LEVEL_REQ] = ConfigMgr::GetIntDefault("LevelReq.Ticket", 1);
m_int_configs[CONFIG_AUCTION_LEVEL_REQ] = ConfigMgr::GetIntDefault("LevelReq.Auction", 1);
m_int_configs[CONFIG_MAIL_LEVEL_REQ] = ConfigMgr::GetIntDefault("LevelReq.Mail", 1);
- m_bool_configs[CONFIG_ALLOW_PLAYER_COMMANDS] = ConfigMgr::GetBoolDefault("AllowPlayerCommands", 1);
m_bool_configs[CONFIG_PRESERVE_CUSTOM_CHANNELS] = ConfigMgr::GetBoolDefault("PreserveCustomChannels", false);
m_int_configs[CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION] = ConfigMgr::GetIntDefault("PreserveCustomChannelDuration", 14);
m_bool_configs[CONFIG_GRID_UNLOAD] = ConfigMgr::GetBoolDefault("GridUnload", true);
@@ -773,7 +775,7 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_START_PLAYER_MONEY] = ConfigMgr::GetIntDefault("StartPlayerMoney", 0);
if (int32(m_int_configs[CONFIG_START_PLAYER_MONEY]) < 0)
{
- sLog->outError(LOG_FILTER_SERVER_LOADING, "StartPlayerMoney (%i) must be in range 0.." UI64FMTD ". Set to %u.", m_int_configs[CONFIG_START_PLAYER_MONEY], MAX_MONEY_AMOUNT, 0);
+ sLog->outError(LOG_FILTER_SERVER_LOADING, "StartPlayerMoney (%i) must be in range 0.." UI64FMTD ". Set to %u.", m_int_configs[CONFIG_START_PLAYER_MONEY], uint64(MAX_MONEY_AMOUNT), 0);
m_int_configs[CONFIG_START_PLAYER_MONEY] = 0;
}
else if (m_int_configs[CONFIG_START_PLAYER_MONEY] > 0x7FFFFFFF-1) // TODO: (See MAX_MONEY_AMOUNT)
@@ -1078,8 +1080,6 @@ void World::LoadConfigSettings(bool reload)
sLog->outError(LOG_FILTER_SERVER_LOADING, "ClientCacheVersion can't be negative %d, ignored.", clientCacheId);
}
- m_int_configs[CONFIG_INSTANT_LOGOUT] = ConfigMgr::GetIntDefault("InstantLogout", SEC_MODERATOR);
-
m_int_configs[CONFIG_GUILD_NEWS_LOG_COUNT] = ConfigMgr::GetIntDefault("Guild.NewsLogRecordsCount", GUILD_NEWSLOG_MAX_RECORDS);
if (m_int_configs[CONFIG_GUILD_NEWS_LOG_COUNT] > GUILD_NEWSLOG_MAX_RECORDS)
m_int_configs[CONFIG_GUILD_NEWS_LOG_COUNT] = GUILD_NEWSLOG_MAX_RECORDS;
@@ -1143,6 +1143,15 @@ void World::LoadConfigSettings(bool reload)
if (dataPath.at(dataPath.length()-1) != '/' && dataPath.at(dataPath.length()-1) != '\\')
dataPath.push_back('/');
+#if PLATFORM == PLATFORM_UNIX || PLATFORM == PLATFORM_APPLE
+ if (dataPath[0] == '~')
+ {
+ const char* home = getenv("HOME");
+ if (home)
+ dataPath.replace(0, 1, home);
+ }
+#endif
+
if (reload)
{
if (dataPath != m_dataPath)
@@ -1154,22 +1163,23 @@ void World::LoadConfigSettings(bool reload)
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Using DataDir %s", m_dataPath.c_str());
}
+ m_bool_configs[CONFIG_ENABLE_MMAPS] = ConfigMgr::GetBoolDefault("mmap.enablePathFinding", false);
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "WORLD: MMap data directory is: %smmaps", m_dataPath.c_str());
+
m_bool_configs[CONFIG_VMAP_INDOOR_CHECK] = ConfigMgr::GetBoolDefault("vmap.enableIndoorCheck", 0);
bool enableIndoor = ConfigMgr::GetBoolDefault("vmap.enableIndoorCheck", true);
bool enableLOS = ConfigMgr::GetBoolDefault("vmap.enableLOS", true);
bool enableHeight = ConfigMgr::GetBoolDefault("vmap.enableHeight", true);
- bool enablePetLOS = ConfigMgr::GetBoolDefault("vmap.petLOS", true);
if (!enableHeight)
sLog->outError(LOG_FILTER_SERVER_LOADING, "VMap height checking disabled! Creatures movements and other various things WILL be broken! Expect no support.");
VMAP::VMapFactory::createOrGetVMapManager()->setEnableLineOfSightCalc(enableLOS);
VMAP::VMapFactory::createOrGetVMapManager()->setEnableHeightCalc(enableHeight);
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, "VMap support included. LineOfSight: %i, getHeight: %i, indoorCheck: %i PetLOS: %i", enableLOS, enableHeight, enableIndoor, enablePetLOS);
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "VMap support included. LineOfSight: %i, getHeight: %i, indoorCheck: %i", enableLOS, enableHeight, enableIndoor);
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "VMap data directory is: %svmaps", m_dataPath.c_str());
m_int_configs[CONFIG_MAX_WHO] = ConfigMgr::GetIntDefault("MaxWhoListReturns", 49);
- m_bool_configs[CONFIG_PET_LOS] = ConfigMgr::GetBoolDefault("vmap.petLOS", true);
m_bool_configs[CONFIG_START_ALL_SPELLS] = ConfigMgr::GetBoolDefault("PlayerStart.AllSpells", false);
if (m_bool_configs[CONFIG_START_ALL_SPELLS])
sLog->outWarn(LOG_FILTER_SERVER_LOADING, "PlayerStart.AllSpells enabled - may not function as intended!");
@@ -1245,6 +1255,7 @@ void World::LoadConfigSettings(bool reload)
// misc
m_bool_configs[CONFIG_PDUMP_NO_PATHS] = ConfigMgr::GetBoolDefault("PlayerDump.DisallowPaths", true);
m_bool_configs[CONFIG_PDUMP_NO_OVERWRITE] = ConfigMgr::GetBoolDefault("PlayerDump.DisallowOverwrite", true);
+ m_bool_configs[CONFIG_UI_QUESTLEVELS_IN_DIALOGS] = ConfigMgr::GetBoolDefault("UI.ShowQuestLevelsInDialogs", false);
// call ScriptMgr if we're reloading the configuration
m_bool_configs[CONFIG_WINTERGRASP_ENABLE] = ConfigMgr::GetBoolDefault("Wintergrasp.Enable", false);
@@ -1270,6 +1281,9 @@ void World::SetInitialWorldSettings()
///- Initialize the random number generator
srand((unsigned int)time(NULL));
+ ///- Initialize detour memory management
+ dtAllocSetCustom(dtCustomAlloc, dtCustomFree);
+
///- Initialize config settings
LoadConfigSettings();
@@ -1365,6 +1379,8 @@ void World::SetInitialWorldSettings()
sObjectMgr->SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts)
sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Localization strings loaded in %u ms", GetMSTimeDiffToNow(oldMSTime));
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Account Roles and Permissions...");
+ sAccountMgr->LoadRBAC();
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Page Texts...");
sObjectMgr->LoadPageTexts();
@@ -1414,8 +1430,8 @@ void World::SetInitialWorldSettings()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Item Random Enchantments Table...");
LoadRandomEnchantmentsTable();
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Disables");
- DisableMgr::LoadDisables(); // must be before loading quests and items
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Disables"); // must be before loading quests and items
+ DisableMgr::LoadDisables();
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Items..."); // must be after LoadRandomEnchantmentsTable and LoadPageTexts
sObjectMgr->LoadItemTemplates();
@@ -1531,6 +1547,9 @@ void World::SetInitialWorldSettings()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Graveyard-zone links...");
sObjectMgr->LoadGraveyardZones();
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Graveyard Orientations...");
+ sObjectMgr->LoadGraveyardOrientations();
+
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading spell pet auras...");
sSpellMgr->LoadSpellPetAuras();
@@ -1598,6 +1617,7 @@ void World::SetInitialWorldSettings()
///- Load dynamic data tables from the database
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Item Auctions...");
sAuctionMgr->LoadAuctionItems();
+
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Auctions...");
sAuctionMgr->LoadAuctions();
@@ -1607,6 +1627,7 @@ void World::SetInitialWorldSettings()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Guild rewards...");
sGuildMgr->LoadGuildRewards();
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Guilds...");
sGuildMgr->LoadGuilds();
sGuildFinderMgr->LoadFromDB();
@@ -2948,8 +2969,6 @@ void World::ResetMonthlyQuests()
if (itr->second->GetPlayer())
itr->second->GetPlayer()->ResetMonthlyQuestStatus();
- time_t mostRecentQuestTime = 0;
-
// generate time
time_t curTime = time(NULL);
tm localTm = *localtime(&curTime);
@@ -2976,14 +2995,8 @@ void World::ResetMonthlyQuests()
time_t nextMonthResetTime = mktime(&localTm);
- // last reset time before current moment
- time_t resetTime = (curTime < nextMonthResetTime) ? nextMonthResetTime - MONTH : nextMonthResetTime;
-
- // need reset (if we have quest time before last reset time (not processed by some reason)
- if (mostRecentQuestTime && mostRecentQuestTime <= resetTime)
- m_NextMonthlyQuestReset = mostRecentQuestTime;
- else // plan next reset time
- m_NextMonthlyQuestReset = (curTime >= nextMonthResetTime) ? nextMonthResetTime + MONTH : nextMonthResetTime;
+ // plan next reset time
+ m_NextMonthlyQuestReset = (curTime >= nextMonthResetTime) ? nextMonthResetTime + MONTH : nextMonthResetTime;
sWorld->setWorldState(WS_MONTHLY_QUEST_RESET_TIME, uint64(m_NextMonthlyQuestReset));
}
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index cca1ac39728..6c86057eefb 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -145,7 +145,6 @@ enum WorldBoolConfigs
CONFIG_ARENA_LOG_EXTENDED_INFO,
CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN,
CONFIG_VMAP_INDOOR_CHECK,
- CONFIG_PET_LOS,
CONFIG_START_ALL_SPELLS,
CONFIG_START_ALL_EXPLORED,
CONFIG_START_ALL_REP,
@@ -171,8 +170,10 @@ enum WorldBoolConfigs
CONFIG_QUEST_IGNORE_AUTO_ACCEPT,
CONFIG_QUEST_IGNORE_AUTO_COMPLETE,
CONFIG_WARDEN_ENABLED,
+ CONFIG_ENABLE_MMAPS,
CONFIG_WINTERGRASP_ENABLE,
CONFIG_GUILD_LEVELING_ENABLED,
+ CONFIG_UI_QUESTLEVELS_IN_DIALOGS, // Should we add quest levels to the title in the NPC dialogs?
BOOL_CONFIG_VALUE_COUNT
};