aboutsummaryrefslogtreecommitdiff
path: root/src/server/game
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2020-05-01 15:41:32 +0200
committerGitHub <noreply@github.com>2020-05-01 15:41:32 +0200
commit57a5969c2672b36160fea1b7c38c424de562a57b (patch)
treeee52f8ddaa8d37297142e59029df461d3000ce31 /src/server/game
parentfbd74eb5d8b5aa3a6874ee99044054e097b5ef21 (diff)
parent05ba662d5daaa3428cc01cdaa3794bf5a073ef17 (diff)
Merge pull request #24500 from funjoker/cherry-picks
Diffstat (limited to 'src/server/game')
-rw-r--r--src/server/game/AI/CoreAI/TotemAI.cpp3
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.cpp10
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.h3
-rw-r--r--src/server/game/AI/CreatureAI.cpp32
-rw-r--r--src/server/game/AI/CreatureAI.h7
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp2
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp6
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp8
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.h1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp13
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp9
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h4
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp10
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.h2
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBot.cpp43
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBot.h39
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp290
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h76
-rw-r--r--src/server/game/Battlefield/Zones/BattlefieldTB.cpp2
-rw-r--r--src/server/game/Battlefield/Zones/BattlefieldWG.cpp24
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp2
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp4
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp8
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp12
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp8
-rw-r--r--src/server/game/Chat/Chat.cpp2
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp51
-rw-r--r--src/server/game/Entities/Creature/Creature.h4
-rw-r--r--src/server/game/Entities/Creature/CreatureGroups.cpp11
-rw-r--r--src/server/game/Entities/Creature/CreatureGroups.h3
-rw-r--r--src/server/game/Entities/Creature/TemporarySummon.cpp8
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp4
-rw-r--r--src/server/game/Entities/Item/Item.cpp190
-rw-r--r--src/server/game/Entities/Item/Item.h8
-rw-r--r--src/server/game/Entities/Object/Object.cpp2
-rw-r--r--src/server/game/Entities/Object/Updates/ViewerDependentValues.h2
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp6
-rw-r--r--src/server/game/Entities/Pet/Pet.h1
-rw-r--r--src/server/game/Entities/Player/Player.cpp268
-rw-r--r--src/server/game/Entities/Player/Player.h12
-rw-r--r--src/server/game/Entities/Unit/StatSystem.cpp98
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp245
-rw-r--r--src/server/game/Entities/Unit/Unit.h29
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp27
-rw-r--r--src/server/game/Handlers/AuctionHouseHandler.cpp34
-rw-r--r--src/server/game/Handlers/LootHandler.cpp3
-rw-r--r--src/server/game/Handlers/NPCHandler.cpp2
-rw-r--r--src/server/game/Handlers/PetHandler.cpp6
-rw-r--r--src/server/game/Handlers/QuestHandler.cpp52
-rw-r--r--src/server/game/Instances/InstanceSaveMgr.cpp62
-rw-r--r--src/server/game/Loot/Loot.cpp28
-rw-r--r--src/server/game/Loot/Loot.h8
-rw-r--r--src/server/game/Loot/LootItemStorage.cpp365
-rw-r--r--src/server/game/Loot/LootItemStorage.h99
-rw-r--r--src/server/game/Maps/Map.cpp8
-rw-r--r--src/server/game/Movement/MotionMaster.cpp20
-rw-r--r--src/server/game/Movement/MotionMaster.h5
-rwxr-xr-xsrc/server/game/Movement/MovementGenerator.h17
-rw-r--r--src/server/game/Movement/MovementGeneratorImpl.h8
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp109
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h13
-rw-r--r--src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp253
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h24
-rw-r--r--src/server/game/Movement/MovementGenerators/FormationMovementGenerator.cpp130
-rw-r--r--src/server/game/Movement/MovementGenerators/FormationMovementGenerator.h49
-rw-r--r--src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp80
-rw-r--r--src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h32
-rw-r--r--src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp32
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/IdleMovementGenerator.h15
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp149
-rw-r--r--src/server/game/Movement/MovementGenerators/PointMovementGenerator.h41
-rw-r--r--src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp208
-rw-r--r--src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h21
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp426
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h105
-rw-r--r--src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp15
-rw-r--r--src/server/game/Quests/QuestDef.h4
-rw-r--r--src/server/game/Reputation/ReputationMgr.cpp7
-rw-r--r--src/server/game/Reputation/ReputationMgr.h8
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp27
-rw-r--r--src/server/game/Scripting/ScriptMgr.h12
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp45
-rw-r--r--src/server/game/Spells/Spell.cpp85
-rw-r--r--src/server/game/Spells/SpellEffects.cpp36
-rw-r--r--src/server/game/Spells/SpellInfo.cpp20
-rw-r--r--src/server/game/Spells/SpellMgr.cpp183
-rw-r--r--src/server/game/Spells/SpellMgr.h24
-rw-r--r--src/server/game/Time/UpdateTime.cpp1
-rw-r--r--src/server/game/World/World.cpp4
89 files changed, 2554 insertions, 1910 deletions
diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp
index 70ed58d853d..a2f0f8f664b 100644
--- a/src/server/game/AI/CoreAI/TotemAI.cpp
+++ b/src/server/game/AI/CoreAI/TotemAI.cpp
@@ -83,8 +83,7 @@ void TotemAI::UpdateAI(uint32 /*diff*/)
i_victimGuid = victim->GetGUID();
// attack
- me->SetInFront(victim); // client change orientation by self
- me->CastSpell(victim, me->ToTotem()->GetSpell(), false);
+ me->CastSpell(victim, me->ToTotem()->GetSpell());
}
else
i_victimGuid.Clear();
diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp
index 21d15731b11..124361f0c07 100644
--- a/src/server/game/AI/CoreAI/UnitAI.cpp
+++ b/src/server/game/AI/CoreAI/UnitAI.cpp
@@ -65,14 +65,20 @@ void UnitAI::DoMeleeAttackIfReady()
//Make sure our attack is ready and we aren't currently casting before checking distance
if (me->isAttackReady())
{
- me->AttackerStateUpdate(victim);
+ if (ShouldSparWith(victim))
+ me->FakeAttackerStateUpdate(victim);
+ else
+ me->AttackerStateUpdate(victim);
me->resetAttackTimer();
}
if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK))
{
- me->AttackerStateUpdate(victim, OFF_ATTACK);
+ if (ShouldSparWith(victim))
+ me->FakeAttackerStateUpdate(victim, OFF_ATTACK);
+ else
+ me->AttackerStateUpdate(victim, OFF_ATTACK);
me->resetAttackTimer(OFF_ATTACK);
}
diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h
index 0145233e3c9..73dc7afc2ec 100644
--- a/src/server/game/AI/CoreAI/UnitAI.h
+++ b/src/server/game/AI/CoreAI/UnitAI.h
@@ -265,6 +265,8 @@ class TC_GAME_API UnitAI
void DoCastVictim(uint32 spellId, bool triggered = false);
void DoCastAOE(uint32 spellId, bool triggered = false);
+ virtual bool ShouldSparWith(Unit const* /*target*/) const { return false; }
+
void DoMeleeAttackIfReady();
bool DoSpellAttackIfReady(uint32 spellId);
@@ -277,7 +279,6 @@ class TC_GAME_API UnitAI
virtual void sQuestAccept(Player* /*player*/, Quest const* /*quest*/) { }
virtual void sQuestSelect(Player* /*player*/, Quest const* /*quest*/) { }
virtual void sQuestReward(Player* /*player*/, Quest const* /*quest*/, uint32 /*opt*/) { }
- virtual bool sOnDummyEffect(Unit* /*caster*/, uint32 /*spellId*/, SpellEffIndex /*effIndex*/) { return false; }
virtual void sOnGameEvent(bool /*start*/, uint16 /*eventId*/) { }
private:
diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp
index b9d052cb528..3c65160aaf6 100644
--- a/src/server/game/AI/CreatureAI.cpp
+++ b/src/server/game/AI/CreatureAI.cpp
@@ -44,7 +44,7 @@ void CreatureAI::OnCharmed(bool apply)
AISpellInfoType* UnitAI::AISpellInfo;
AISpellInfoType* GetAISpellInfo(uint32 i) { return &UnitAI::AISpellInfo[i]; }
-CreatureAI::CreatureAI(Creature* creature) : UnitAI(creature), me(creature), _boundary(nullptr), m_MoveInLineOfSight_locked(false)
+CreatureAI::CreatureAI(Creature* creature) : UnitAI(creature), me(creature), _boundary(nullptr), _negateBoundary(false), m_MoveInLineOfSight_locked(false)
{
}
@@ -173,9 +173,9 @@ void CreatureAI::TriggerAlert(Unit const* who) const
me->SendAIReaction(AI_REACTION_ALERT);
// Face the unit (stealthed player) and set distracted state for 5 seconds
- me->SetFacingTo(me->GetAngle(who->GetPositionX(), who->GetPositionY()), true);
- me->StopMoving();
me->GetMotionMaster()->MoveDistract(5 * IN_MILLISECONDS);
+ me->StopMoving();
+ me->SetFacingTo(me->GetAngle(who));
}
void CreatureAI::EnterEvadeMode(EvadeReason why)
@@ -217,7 +217,7 @@ void CreatureAI::SetGazeOn(Unit* target)
{
if (me->IsValidAttackTarget(target))
{
- if (!me->IsFocusing(nullptr, true))
+ if (!me->IsFocusing(nullptr, true) && target != me->GetVictim())
AttackStart(target);
me->SetReactState(REACT_PASSIVE);
}
@@ -237,7 +237,7 @@ bool CreatureAI::UpdateVictimWithGaze()
}
if (Unit* victim = me->SelectVictim())
- if (!me->IsFocusing(nullptr, true))
+ if (!me->IsFocusing(nullptr, true) && victim != me->GetVictim())
AttackStart(victim);
return me->GetVictim() != nullptr;
@@ -251,7 +251,7 @@ bool CreatureAI::UpdateVictim()
if (!me->HasReactState(REACT_PASSIVE))
{
if (Unit* victim = me->SelectVictim())
- if (!me->IsFocusing(nullptr, true))
+ if (!me->IsFocusing(nullptr, true) && victim != me->GetVictim())
AttackStart(victim);
return me->GetVictim() != nullptr;
@@ -364,32 +364,28 @@ int32 CreatureAI::VisualizeBoundary(uint32 duration, Unit* owner, bool fill) con
bool CreatureAI::CheckBoundary(Position const* who) const
{
+ if (!_boundary)
+ return true;
+
if (!who)
who = me;
- if (_boundary)
- for (AreaBoundary const* areaBoundary : *_boundary)
- if (!areaBoundary->IsWithinBoundary(who))
- return false;
-
- return true;
+ return (CreatureAI::IsInBounds(*_boundary, who) != _negateBoundary);
}
-bool CreatureAI::IsInBounds(CreatureBoundary const* boundary, Position const* pos)
+bool CreatureAI::IsInBounds(CreatureBoundary const& boundary, Position const* pos)
{
- if (!boundary)
- return true;
-
- for (AreaBoundary const* areaBoundary : *boundary)
+ for (AreaBoundary const* areaBoundary : boundary)
if (!areaBoundary->IsWithinBoundary(pos))
return false;
return true;
}
-void CreatureAI::SetBoundary(CreatureBoundary const* boundary)
+void CreatureAI::SetBoundary(CreatureBoundary const* boundary, bool negateBoundaries /*= false*/)
{
_boundary = boundary;
+ _negateBoundary = negateBoundaries;
me->DoImmediateBoundaryCheck();
}
diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h
index 5fe93e7675a..edc09a650c7 100644
--- a/src/server/game/AI/CreatureAI.h
+++ b/src/server/game/AI/CreatureAI.h
@@ -83,7 +83,6 @@ class TC_GAME_API CreatureAI : public UnitAI
bool CheckBoundary(Position const* who = nullptr) const;
- void SetBoundary(CreatureBoundary const* boundary);
public:
enum EvadeReason
{
@@ -211,11 +210,12 @@ class TC_GAME_API CreatureAI : public UnitAI
virtual PlayerAI* GetAIForCharmedPlayer(Player* /*who*/) { return nullptr; }
// intended for encounter design/debugging. do not use for other purposes. expensive.
- int32 VisualizeBoundary(uint32 duration, Unit* owner=nullptr, bool fill=false) const;
+ int32 VisualizeBoundary(uint32 duration, Unit* owner = nullptr, bool fill = false) const;
virtual bool CheckInRoom();
CreatureBoundary const* GetBoundary() const { return _boundary; }
+ void SetBoundary(CreatureBoundary const* boundary, bool negativeBoundaries = false);
- static bool IsInBounds(CreatureBoundary const* boundary, Position const* who);
+ static bool IsInBounds(CreatureBoundary const& boundary, Position const* who);
protected:
virtual void MoveInLineOfSight(Unit* /*who*/);
@@ -223,6 +223,7 @@ class TC_GAME_API CreatureAI : public UnitAI
bool _EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER);
CreatureBoundary const* _boundary;
+ bool _negateBoundary;
private:
bool m_MoveInLineOfSight_locked;
diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
index 20a1c895dae..46e4159bb4c 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
@@ -176,7 +176,7 @@ void npc_escortAI::JustRespawned()
//add a small delay before going to first waypoint, normal in near all cases
m_uiWPWaitTimer = 2500;
- if (me->getFaction() != me->GetCreatureTemplate()->faction)
+ if (me->GetFaction() != me->GetCreatureTemplate()->faction)
me->RestoreFaction();
Reset();
diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
index 961700d43b1..6c38e34df97 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
@@ -166,8 +166,8 @@ void FollowerAI::JustRespawned()
if (!IsCombatMovementAllowed())
SetCombatMovement(true);
- if (me->getFaction() != me->GetCreatureTemplate()->faction)
- me->setFaction(me->GetCreatureTemplate()->faction);
+ if (me->GetFaction() != me->GetCreatureTemplate()->faction)
+ me->SetFaction(me->GetCreatureTemplate()->faction);
Reset();
}
@@ -303,7 +303,7 @@ void FollowerAI::StartFollow(Player* player, uint32 factionForFollower, const Qu
m_uiLeaderGUID = player->GetGUID();
if (factionForFollower)
- me->setFaction(factionForFollower);
+ me->SetFaction(factionForFollower);
m_pQuestForFollow = quest;
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index a215153b550..1d4c2150585 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -580,7 +580,7 @@ void SmartAI::JustRespawned()
mDespawnState = 0;
mEscortState = SMART_ESCORT_NONE;
me->SetVisible(true);
- if (me->getFaction() != me->GetCreatureTemplate()->faction)
+ if (me->GetFaction() != me->GetCreatureTemplate()->faction)
me->RestoreFaction();
mJustReset = true;
JustReachedHome();
@@ -830,12 +830,6 @@ void SmartAI::sQuestReward(Player* player, Quest const* quest, uint32 opt)
GetScript()->ProcessEventsFor(SMART_EVENT_REWARD_QUEST, player, quest->GetQuestId(), opt);
}
-bool SmartAI::sOnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex)
-{
- GetScript()->ProcessEventsFor(SMART_EVENT_DUMMY_EFFECT, caster, spellId, (uint32)effIndex);
- return true;
-}
-
void SmartAI::SetCombatMove(bool on)
{
if (mCanCombatMove == on)
diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h
index 02cb4529a38..cce8ffd57ad 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.h
+++ b/src/server/game/AI/SmartScripts/SmartAI.h
@@ -182,7 +182,6 @@ class TC_GAME_API SmartAI : public CreatureAI
void sQuestAccept(Player* player, Quest const* quest) override;
//void sQuestSelect(Player* player, Quest const* quest) override;
void sQuestReward(Player* player, Quest const* quest, uint32 opt) override;
- bool sOnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex) override;
void sOnGameEvent(bool start, uint16 eventId) override;
uint32 mEscortQuestID;
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 6224533846e..abf80f95794 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -365,7 +365,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
if (e.action.faction.factionID)
{
- (*itr)->ToCreature()->setFaction(e.action.faction.factionID);
+ (*itr)->ToCreature()->SetFaction(e.action.faction.factionID);
TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature entry %u, %s set faction to %u",
(*itr)->GetEntry(), (*itr)->GetGUID().ToString().c_str(), e.action.faction.factionID);
}
@@ -373,9 +373,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate((*itr)->ToCreature()->GetEntry()))
{
- if ((*itr)->ToCreature()->getFaction() != ci->faction)
+ if ((*itr)->ToCreature()->GetFaction() != ci->faction)
{
- (*itr)->ToCreature()->setFaction(ci->faction);
+ (*itr)->ToCreature()->SetFaction(ci->faction);
TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature entry %u, %s set faction to %u",
(*itr)->GetEntry(), (*itr)->GetGUID().ToString().c_str(), ci->faction);
}
@@ -3831,13 +3831,6 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
ProcessAction(e, unit, var0, var1);
break;
}
- case SMART_EVENT_DUMMY_EFFECT:
- {
- if (e.event.dummy.spell != var0 || e.event.dummy.effIndex != var1)
- return;
- ProcessAction(e, unit, var0, var1);
- break;
- }
case SMART_EVENT_GAME_EVENT_START:
case SMART_EVENT_GAME_EVENT_END:
{
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 9faaab903e6..42f0a4b4f2c 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -857,15 +857,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
if (!IsTextValid(e, e.event.textOver.textGroupID))
return false;
break;
- case SMART_EVENT_DUMMY_EFFECT:
- {
- if (!IsSpellValid(e, e.event.dummy.spell))
- return false;
-
- if (e.event.dummy.effIndex > EFFECT_2)
- return false;
- break;
- }
case SMART_EVENT_IS_BEHIND_TARGET:
{
if (!IsMinMaxValid(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax))
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 1ff452f4182..392cdc7cc22 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -177,7 +177,7 @@ enum SMART_EVENT
SMART_EVENT_JUST_CREATED = 63, // none
SMART_EVENT_GOSSIP_HELLO = 64, // noReportUse (for GOs)
SMART_EVENT_FOLLOW_COMPLETED = 65, // none
- SMART_EVENT_DUMMY_EFFECT = 66, // spellId, effectIndex
+ // 66 unused
SMART_EVENT_IS_BEHIND_TARGET = 67, // cooldownMin, CooldownMax
SMART_EVENT_GAME_EVENT_START = 68, // game_event.Entry
SMART_EVENT_GAME_EVENT_END = 69, // game_event.Entry
@@ -1492,7 +1492,7 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] =
{SMART_EVENT_JUST_CREATED, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
{SMART_EVENT_GOSSIP_HELLO, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
{SMART_EVENT_FOLLOW_COMPLETED, SMART_SCRIPT_TYPE_MASK_CREATURE },
- {SMART_EVENT_DUMMY_EFFECT, SMART_SCRIPT_TYPE_MASK_SPELL },
+ {66, 0 }, // unused
{SMART_EVENT_IS_BEHIND_TARGET, SMART_SCRIPT_TYPE_MASK_CREATURE },
{SMART_EVENT_GAME_EVENT_START, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
{SMART_EVENT_GAME_EVENT_END, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index b86ec0a29f3..ca785cea3da 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -653,7 +653,7 @@ void AuctionHouseMgr::AddAItem(Item* item)
_itemsByGuid[item->GetGUID()] = item;
}
-bool AuctionHouseMgr::RemoveAItem(ObjectGuid id, bool deleteItem)
+bool AuctionHouseMgr::RemoveAItem(ObjectGuid id, bool deleteItem /*= false*/, CharacterDatabaseTransaction* trans /*= nullptr*/)
{
auto i = _itemsByGuid.find(id);
if (i == _itemsByGuid.end())
@@ -661,9 +661,9 @@ bool AuctionHouseMgr::RemoveAItem(ObjectGuid id, bool deleteItem)
if (deleteItem)
{
- CharacterDatabaseTransaction trans = CharacterDatabaseTransaction(nullptr);
+ ASSERT(trans);
i->second->FSetState(ITEM_REMOVED);
- i->second->SaveToDB(trans);
+ i->second->SaveToDB(*trans);
}
_itemsByGuid.erase(i);
@@ -1850,7 +1850,7 @@ void AuctionHouseObject::SendAuctionWon(AuctionPosting const* auction, Player* b
{
// bidder doesn't exist, delete the item
for (Item* item : auction->Items)
- sAuctionMgr->RemoveAItem(item->GetGUID(), true);
+ sAuctionMgr->RemoveAItem(item->GetGUID(), true, &trans);
}
}
@@ -1902,7 +1902,7 @@ void AuctionHouseObject::SendAuctionExpired(AuctionPosting const* auction, Chara
{
// owner doesn't exist, delete the item
for (Item* item : auction->Items)
- sAuctionMgr->RemoveAItem(item->GetGUID(), true);
+ sAuctionMgr->RemoveAItem(item->GetGUID(), true, &trans);
}
}
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.h b/src/server/game/AuctionHouse/AuctionHouseMgr.h
index 308df2083a4..33a902b6d32 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.h
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.h
@@ -373,7 +373,7 @@ class TC_GAME_API AuctionHouseMgr
void LoadAuctions();
void AddAItem(Item* item);
- bool RemoveAItem(ObjectGuid itemGuid, bool deleteItem = false);
+ bool RemoveAItem(ObjectGuid itemGuid, bool deleteItem = false, CharacterDatabaseTransaction* trans = nullptr);
bool PendingAuctionAdd(Player* player, uint32 auctionHouseId, uint32 auctionId, uint64 deposit);
std::size_t PendingAuctionCount(Player const* player) const;
void PendingAuctionProcess(Player* player);
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp
index f4c8aa5c320..b93a979033c 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp
@@ -179,21 +179,21 @@ void AuctionBotConfig::GetConfigFromFile()
SetConfig(CONFIG_AHBOT_ITEM_ORANGE_AMOUNT, "AuctionHouseBot.Items.Amount.Orange", 0);
SetConfig(CONFIG_AHBOT_ITEM_YELLOW_AMOUNT, "AuctionHouseBot.Items.Amount.Yellow", 0);
- SetConfigMax(CONFIG_AHBOT_CLASS_CONSUMABLE_AMOUNT, "AuctionHouseBot.Class.Consumable", 6, 10);
- SetConfigMax(CONFIG_AHBOT_CLASS_CONTAINER_AMOUNT, "AuctionHouseBot.Class.Container", 4, 10);
- SetConfigMax(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT, "AuctionHouseBot.Class.Weapon", 8, 10);
- SetConfigMax(CONFIG_AHBOT_CLASS_GEM_AMOUNT, "AuctionHouseBot.Class.Gem", 3, 10);
- SetConfigMax(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT, "AuctionHouseBot.Class.Armor", 8, 10);
- SetConfigMax(CONFIG_AHBOT_CLASS_REAGENT_AMOUNT, "AuctionHouseBot.Class.Reagent", 1, 10);
- SetConfigMax(CONFIG_AHBOT_CLASS_PROJECTILE_AMOUNT, "AuctionHouseBot.Class.Projectile", 2, 10);
- SetConfigMax(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT, "AuctionHouseBot.Class.TradeGood", 10, 10);
- SetConfigMax(CONFIG_AHBOT_CLASS_GENERIC_AMOUNT, "AuctionHouseBot.Class.Generic", 1, 10);
- SetConfigMax(CONFIG_AHBOT_CLASS_RECIPE_AMOUNT, "AuctionHouseBot.Class.Recipe", 6, 10);
- SetConfigMax(CONFIG_AHBOT_CLASS_QUIVER_AMOUNT, "AuctionHouseBot.Class.Quiver", 1, 10);
- SetConfigMax(CONFIG_AHBOT_CLASS_QUEST_AMOUNT, "AuctionHouseBot.Class.Quest", 1, 10);
- SetConfigMax(CONFIG_AHBOT_CLASS_KEY_AMOUNT, "AuctionHouseBot.Class.Key", 1, 10);
- SetConfigMax(CONFIG_AHBOT_CLASS_MISC_AMOUNT, "AuctionHouseBot.Class.Misc", 5, 10);
- SetConfigMax(CONFIG_AHBOT_CLASS_GLYPH_AMOUNT, "AuctionHouseBot.Class.Glyph", 3, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_CONSUMABLE_PRIORITY, "AuctionHouseBot.Class.Consumable", 6, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_CONTAINER_PRIORITY, "AuctionHouseBot.Class.Container", 4, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_WEAPON_PRIORITY, "AuctionHouseBot.Class.Weapon", 8, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_GEM_PRIORITY, "AuctionHouseBot.Class.Gem", 3, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_ARMOR_PRIORITY, "AuctionHouseBot.Class.Armor", 8, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_REAGENT_PRIORITY, "AuctionHouseBot.Class.Reagent", 1, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_PROJECTILE_PRIORITY, "AuctionHouseBot.Class.Projectile", 2, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_TRADEGOOD_PRIORITY, "AuctionHouseBot.Class.TradeGood", 10, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_GENERIC_PRIORITY, "AuctionHouseBot.Class.Generic", 1, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_RECIPE_PRIORITY, "AuctionHouseBot.Class.Recipe", 6, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_QUIVER_PRIORITY, "AuctionHouseBot.Class.Quiver", 1, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_QUEST_PRIORITY, "AuctionHouseBot.Class.Quest", 1, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_KEY_PRIORITY, "AuctionHouseBot.Class.Key", 1, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_MISC_PRIORITY, "AuctionHouseBot.Class.Misc", 5, 10);
+ SetConfigMax(CONFIG_AHBOT_CLASS_GLYPH_PRIORITY, "AuctionHouseBot.Class.Glyph", 3, 10);
SetConfig(CONFIG_AHBOT_ALLIANCE_PRICE_RATIO, "AuctionHouseBot.Alliance.Price.Ratio", 100);
SetConfig(CONFIG_AHBOT_HORDE_PRICE_RATIO, "AuctionHouseBot.Horde.Price.Ratio", 100);
@@ -351,6 +351,19 @@ uint32 AuctionBotConfig::GetConfigItemAmountRatio(AuctionHouseType houseType) co
}
}
+uint32 AuctionBotConfig::GetConfigPriceRatio(AuctionHouseType houseType) const
+{
+ switch (houseType)
+ {
+ case AUCTION_HOUSE_ALLIANCE:
+ return GetConfig(CONFIG_AHBOT_ALLIANCE_PRICE_RATIO);
+ case AUCTION_HOUSE_HORDE:
+ return GetConfig(CONFIG_AHBOT_HORDE_PRICE_RATIO);
+ default:
+ return GetConfig(CONFIG_AHBOT_NEUTRAL_PRICE_RATIO);
+ }
+}
+
bool AuctionBotConfig::GetConfigBuyerEnabled(AuctionHouseType houseType) const
{
switch (houseType)
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBot.h b/src/server/game/AuctionHouseBot/AuctionHouseBot.h
index 75145c498e6..3bf9caef9f8 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBot.h
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.h
@@ -71,21 +71,21 @@ enum AuctionBotConfigUInt32Values
CONFIG_AHBOT_ITEM_PURPLE_AMOUNT,
CONFIG_AHBOT_ITEM_ORANGE_AMOUNT,
CONFIG_AHBOT_ITEM_YELLOW_AMOUNT,
- CONFIG_AHBOT_CLASS_CONSUMABLE_AMOUNT,
- CONFIG_AHBOT_CLASS_CONTAINER_AMOUNT,
- CONFIG_AHBOT_CLASS_WEAPON_AMOUNT,
- CONFIG_AHBOT_CLASS_GEM_AMOUNT,
- CONFIG_AHBOT_CLASS_ARMOR_AMOUNT,
- CONFIG_AHBOT_CLASS_REAGENT_AMOUNT,
- CONFIG_AHBOT_CLASS_PROJECTILE_AMOUNT,
- CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT,
- CONFIG_AHBOT_CLASS_GENERIC_AMOUNT,
- CONFIG_AHBOT_CLASS_RECIPE_AMOUNT,
- CONFIG_AHBOT_CLASS_QUIVER_AMOUNT,
- CONFIG_AHBOT_CLASS_QUEST_AMOUNT,
- CONFIG_AHBOT_CLASS_KEY_AMOUNT,
- CONFIG_AHBOT_CLASS_MISC_AMOUNT,
- CONFIG_AHBOT_CLASS_GLYPH_AMOUNT,
+ CONFIG_AHBOT_CLASS_CONSUMABLE_PRIORITY,
+ CONFIG_AHBOT_CLASS_CONTAINER_PRIORITY,
+ CONFIG_AHBOT_CLASS_WEAPON_PRIORITY,
+ CONFIG_AHBOT_CLASS_GEM_PRIORITY,
+ CONFIG_AHBOT_CLASS_ARMOR_PRIORITY,
+ CONFIG_AHBOT_CLASS_REAGENT_PRIORITY,
+ CONFIG_AHBOT_CLASS_PROJECTILE_PRIORITY,
+ CONFIG_AHBOT_CLASS_TRADEGOOD_PRIORITY,
+ CONFIG_AHBOT_CLASS_GENERIC_PRIORITY,
+ CONFIG_AHBOT_CLASS_RECIPE_PRIORITY,
+ CONFIG_AHBOT_CLASS_QUIVER_PRIORITY,
+ CONFIG_AHBOT_CLASS_QUEST_PRIORITY,
+ CONFIG_AHBOT_CLASS_KEY_PRIORITY,
+ CONFIG_AHBOT_CLASS_MISC_PRIORITY,
+ CONFIG_AHBOT_CLASS_GLYPH_PRIORITY,
CONFIG_AHBOT_ALLIANCE_PRICE_RATIO,
CONFIG_AHBOT_HORDE_PRICE_RATIO,
CONFIG_AHBOT_NEUTRAL_PRICE_RATIO,
@@ -205,8 +205,8 @@ enum AuctionBotConfigFloatValues
class TC_GAME_API AuctionBotConfig
{
private:
- AuctionBotConfig(): _itemsPerCycleBoost(1000), _itemsPerCycleNormal(20) { }
- ~AuctionBotConfig() { }
+ AuctionBotConfig(): _itemsPerCycleBoost(1000), _itemsPerCycleNormal(20) {}
+ ~AuctionBotConfig() {}
AuctionBotConfig(AuctionBotConfig const&) = delete;
AuctionBotConfig& operator=(AuctionBotConfig const&) = delete;
@@ -225,6 +225,7 @@ public:
void SetConfig(AuctionBotConfigFloatValues index, float value) { _configFloatValues[index] = value; }
uint32 GetConfigItemAmountRatio(AuctionHouseType houseType) const;
+ uint32 GetConfigPriceRatio(AuctionHouseType houseType) const;
bool GetConfigBuyerEnabled(AuctionHouseType houseType) const;
uint32 GetConfigItemQualityAmount(AuctionQuality quality) const;
@@ -286,8 +287,8 @@ class TC_GAME_API AuctionHouseBot
private:
AuctionHouseBot();
~AuctionHouseBot();
- AuctionHouseBot(const AuctionHouseBot&);
- AuctionHouseBot& operator=(const AuctionHouseBot&);
+ AuctionHouseBot(AuctionHouseBot const&) = delete;
+ AuctionHouseBot& operator=(AuctionHouseBot const&) = delete;
public:
static AuctionHouseBot* instance();
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
index 44ee9fcc2a4..da14231ec3c 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
@@ -22,6 +22,7 @@
#include "GameTime.h"
#include "Item.h"
#include "Log.h"
+#include "Containers.h"
#include "ObjectMgr.h"
#include "Random.h"
#include <sstream>
@@ -29,7 +30,7 @@
AuctionBotSeller::AuctionBotSeller()
{
// Define faction for our main data class.
- for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i)
+ for (uint8 i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i)
_houseConfig[i].Initialize(AuctionHouseType(i));
}
@@ -117,11 +118,11 @@ bool AuctionBotSeller::Initialize()
continue;
// forced exclude filter
- if (excludeItems.find(itemId) != excludeItems.end())
+ if (excludeItems.count(itemId))
continue;
// forced include filter
- if (includeItems.find(itemId) != includeItems.end())
+ if (includeItems.count(itemId))
{
_itemPool[prototype->GetQuality()][prototype->GetClass()].push_back(itemId);
++itemsAdded;
@@ -207,19 +208,20 @@ bool AuctionBotSeller::Initialize()
// vendor filter
if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEMS_VENDOR))
- if (npcItems.find(itemId) != npcItems.end())
+ if (npcItems.count(itemId))
continue;
// loot filter
if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEMS_LOOT))
- if (lootItems.find(itemId) != lootItems.end())
+ if (lootItems.count(itemId))
continue;
// not vendor/loot filter
if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEMS_MISC))
{
- bool isVendorItem = npcItems.find(itemId) != npcItems.end();
- bool isLootItem = lootItems.find(itemId) != lootItems.end();
+ bool const isVendorItem = npcItems.count(itemId) > 0;
+ bool const isLootItem = lootItems.count(itemId) > 0;
+
if (!isLootItem && !isVendorItem)
continue;
}
@@ -368,7 +370,7 @@ bool AuctionBotSeller::Initialize()
void AuctionBotSeller::LoadConfig()
{
- for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i)
+ for (uint8 i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i)
if (sAuctionBotConfig->GetConfigItemAmountRatio(AuctionHouseType(i)))
LoadSellerValues(_houseConfig[i]);
}
@@ -377,129 +379,11 @@ void AuctionBotSeller::LoadItemsQuantity(SellerConfiguration& config)
{
uint32 ratio = sAuctionBotConfig->GetConfigItemAmountRatio(config.GetHouseType());
- config.SetItemsAmountPerQuality(AUCTION_QUALITY_GRAY, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_GRAY_AMOUNT) * ratio / 100);
- config.SetItemsAmountPerQuality(AUCTION_QUALITY_WHITE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_WHITE_AMOUNT) * ratio / 100);
- config.SetItemsAmountPerQuality(AUCTION_QUALITY_GREEN, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_GREEN_AMOUNT) * ratio / 100);
- config.SetItemsAmountPerQuality(AUCTION_QUALITY_BLUE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_BLUE_AMOUNT) * ratio / 100);
- config.SetItemsAmountPerQuality(AUCTION_QUALITY_PURPLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_PURPLE_AMOUNT) * ratio / 100);
- config.SetItemsAmountPerQuality(AUCTION_QUALITY_ORANGE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_ORANGE_AMOUNT) * ratio / 100);
- config.SetItemsAmountPerQuality(AUCTION_QUALITY_YELLOW, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_YELLOW_AMOUNT) * ratio / 100);
-
- // Set quantity wanted but only on possible item color
- // This avoid any no-exist class-color items selection by random items create function
- // ============================================================================================
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_CONSUMABLE, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_CONTAINER, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_GEM, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_REAGENT, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_PROJECTILE, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_ITEM_ENHANCEMENT, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_RECIPE, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_QUIVER, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_QUEST, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUEST_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_KEY, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_MISCELLANEOUS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_GLYPH, 0);
-
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_CONSUMABLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_CONTAINER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_GEM, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GEM_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_REAGENT, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_REAGENT_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_PROJECTILE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_PROJECTILE_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_ITEM_ENHANCEMENT, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GENERIC_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_RECIPE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RECIPE_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_QUIVER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUIVER_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_QUEST, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUEST_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_KEY, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_KEY_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_MISCELLANEOUS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_GLYPH, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_AMOUNT));
-
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_CONSUMABLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_CONTAINER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_GEM, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GEM_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_REAGENT, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_PROJECTILE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_PROJECTILE_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_ITEM_ENHANCEMENT, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_RECIPE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RECIPE_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_QUIVER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUIVER_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_QUEST, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUEST_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_KEY, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_KEY_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_MISCELLANEOUS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_GLYPH, 0);
-
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_CONSUMABLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_CONTAINER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_GEM, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GEM_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_REAGENT, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_PROJECTILE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_PROJECTILE_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_ITEM_ENHANCEMENT, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_RECIPE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RECIPE_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_QUIVER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUIVER_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_QUEST, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUEST_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_KEY, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_MISCELLANEOUS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_GLYPH, 0);
-
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_CONSUMABLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_CONTAINER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_GEM, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GEM_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_REAGENT, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_PROJECTILE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_PROJECTILE_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_ITEM_ENHANCEMENT, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_RECIPE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RECIPE_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_QUIVER, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_QUEST, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUEST_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_KEY, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_MISCELLANEOUS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_GLYPH, 0);
-
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_CONSUMABLE, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_CONTAINER, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_GEM, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_REAGENT, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_PROJECTILE, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_ITEM_ENHANCEMENT, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_RECIPE, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_QUIVER, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_QUEST, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_KEY, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_MISCELLANEOUS, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_GLYPH, 0);
-
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_CONSUMABLE, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_CONTAINER, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_GEM, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT));
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_REAGENT, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_PROJECTILE, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_TRADE_GOODS, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_ITEM_ENHANCEMENT, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_RECIPE, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_QUIVER, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_QUEST, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_KEY, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_MISCELLANEOUS, 0);
- config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_GLYPH, 0);
- // ============================================================================================
+ for (uint32 i = 0; i < MAX_AUCTION_QUALITY; ++i)
+ {
+ uint32 amount = sAuctionBotConfig->GetConfig(AuctionBotConfigUInt32Values(CONFIG_AHBOT_ITEM_GRAY_AMOUNT + i));
+ config.SetItemsAmountPerQuality(AuctionQuality(i), std::lroundf(amount * ratio / 100.f));
+ }
// Set Stack Quantities
config.SetRandomStackRatioPerClass(ITEM_CLASS_CONSUMABLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_CONSUMABLE));
@@ -519,45 +403,100 @@ void AuctionBotSeller::LoadItemsQuantity(SellerConfiguration& config)
config.SetRandomStackRatioPerClass(ITEM_CLASS_GLYPH, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_GLYPH));
// Set the best value to get nearest amount of items wanted
+ auto getPriorityForClass = [](uint32 itemClass) -> uint32
+ {
+ AuctionBotConfigUInt32Values index;
+ switch (itemClass)
+ {
+ case ITEM_CLASS_CONSUMABLE:
+ index = CONFIG_AHBOT_CLASS_CONSUMABLE_PRIORITY; break;
+ case ITEM_CLASS_CONTAINER:
+ index = CONFIG_AHBOT_CLASS_CONTAINER_PRIORITY; break;
+ case ITEM_CLASS_WEAPON:
+ index = CONFIG_AHBOT_CLASS_WEAPON_PRIORITY; break;
+ case ITEM_CLASS_GEM:
+ index = CONFIG_AHBOT_CLASS_GEM_PRIORITY; break;
+ case ITEM_CLASS_ARMOR:
+ index = CONFIG_AHBOT_CLASS_ARMOR_PRIORITY; break;
+ case ITEM_CLASS_REAGENT:
+ index = CONFIG_AHBOT_CLASS_REAGENT_PRIORITY; break;
+ case ITEM_CLASS_PROJECTILE:
+ index = CONFIG_AHBOT_CLASS_PROJECTILE_PRIORITY; break;
+ case ITEM_CLASS_TRADE_GOODS:
+ index = CONFIG_AHBOT_CLASS_TRADEGOOD_PRIORITY; break;
+ case ITEM_CLASS_ITEM_ENHANCEMENT:
+ index = CONFIG_AHBOT_CLASS_GENERIC_PRIORITY; break;
+ case ITEM_CLASS_RECIPE:
+ index = CONFIG_AHBOT_CLASS_RECIPE_PRIORITY; break;
+ case ITEM_CLASS_QUIVER:
+ index = CONFIG_AHBOT_CLASS_QUIVER_PRIORITY; break;
+ case ITEM_CLASS_QUEST:
+ index = CONFIG_AHBOT_CLASS_QUEST_PRIORITY; break;
+ case ITEM_CLASS_KEY:
+ index = CONFIG_AHBOT_CLASS_KEY_PRIORITY; break;
+ case ITEM_CLASS_MISCELLANEOUS:
+ index = CONFIG_AHBOT_CLASS_MISC_PRIORITY; break;
+ case ITEM_CLASS_GLYPH:
+ index = CONFIG_AHBOT_CLASS_GLYPH_PRIORITY; break;
+ default:
+ return 0;
+ }
+
+ return sAuctionBotConfig->GetConfig(index);
+ };
+
+ std::vector<uint32> totalPrioPerQuality(MAX_AUCTION_QUALITY);
for (uint32 j = 0; j < MAX_AUCTION_QUALITY; ++j)
{
- uint32 index = config.GetItemsAmountPerQuality(AuctionQuality(j)) /
- (sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT) +
- sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GEM_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_REAGENT_AMOUNT) +
- sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_PROJECTILE_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GENERIC_AMOUNT) +
- sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RECIPE_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUIVER_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUEST_AMOUNT) +
- sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_KEY_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_AMOUNT));
+ for (uint32 i = 0; i < MAX_ITEM_CLASS; ++i)
+ {
+ // skip empty pools
+ if (_itemPool[j][i].empty())
+ continue;
+
+ totalPrioPerQuality[j] += getPriorityForClass(i);
+ }
+ }
+
+ for (uint32 j = 0; j < MAX_AUCTION_QUALITY; ++j)
+ {
+ uint32 qualityAmount = config.GetItemsAmountPerQuality(AuctionQuality(j));
+ if (!totalPrioPerQuality[j])
+ continue;
+
+ for (uint32 i = 0; i < MAX_ITEM_CLASS; ++i)
+ {
+ uint32 classPrio = getPriorityForClass(i);
+ if (_itemPool[j][i].empty())
+ classPrio = 0;
+
+ uint32 weightedAmount = std::lroundf(classPrio / float(totalPrioPerQuality[j]) * qualityAmount);
+ config.SetItemsAmountPerClass(AuctionQuality(j), ItemClass(i), weightedAmount);
+ }
+ }
+ // do some assert checking, GetItemAmount must always return 0 if selected _itemPool is empty
+ for (uint32 j = 0; j < MAX_AUCTION_QUALITY; ++j)
+ {
for (uint32 i = 0; i < MAX_ITEM_CLASS; ++i)
- config.SetItemsAmountPerClass(AuctionQuality(j), ItemClass(i), index);
+ {
+ if (_itemPool[j][i].empty())
+ ASSERT(config.GetItemsAmountPerClass(AuctionQuality(j), ItemClass(i)) == 0);
+ }
}
}
void AuctionBotSeller::LoadSellerValues(SellerConfiguration& config)
{
LoadItemsQuantity(config);
- uint32 PriceRatio;
- switch (config.GetHouseType())
+ uint32 ratio = sAuctionBotConfig->GetConfigPriceRatio(config.GetHouseType());
+
+ for (uint32 i = 0; i < MAX_AUCTION_QUALITY; ++i)
{
- case AUCTION_HOUSE_ALLIANCE:
- PriceRatio = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ALLIANCE_PRICE_RATIO);
- break;
- case AUCTION_HOUSE_HORDE:
- PriceRatio = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_HORDE_PRICE_RATIO);
- break;
- default:
- PriceRatio = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_NEUTRAL_PRICE_RATIO);
- break;
+ uint32 amount = sAuctionBotConfig->GetConfig(AuctionBotConfigUInt32Values(CONFIG_AHBOT_ITEM_GRAY_PRICE_RATIO + i));
+ config.SetPriceRatioPerQuality(AuctionQuality(i), std::lroundf(amount * ratio / 100.f));
}
- config.SetPriceRatioPerQuality(AUCTION_QUALITY_GRAY, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_GRAY_PRICE_RATIO));
- config.SetPriceRatioPerQuality(AUCTION_QUALITY_WHITE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_WHITE_PRICE_RATIO));
- config.SetPriceRatioPerQuality(AUCTION_QUALITY_GREEN, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_GREEN_PRICE_RATIO));
- config.SetPriceRatioPerQuality(AUCTION_QUALITY_BLUE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_BLUE_PRICE_RATIO));
- config.SetPriceRatioPerQuality(AUCTION_QUALITY_PURPLE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_PURPLE_PRICE_RATIO));
- config.SetPriceRatioPerQuality(AUCTION_QUALITY_ORANGE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_ORANGE_PRICE_RATIO));
- config.SetPriceRatioPerQuality(AUCTION_QUALITY_YELLOW, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_YELLOW_PRICE_RATIO));
-
config.SetPriceRatioPerClass(ITEM_CLASS_CONSUMABLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_PRICE_RATIO));
config.SetPriceRatioPerClass(ITEM_CLASS_CONTAINER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_PRICE_RATIO));
config.SetPriceRatioPerClass(ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_PRICE_RATIO));
@@ -579,18 +518,6 @@ void AuctionBotSeller::LoadSellerValues(SellerConfiguration& config)
//load min and max auction times
config.SetMinTime(sAuctionBotConfig->GetConfig(CONFIG_AHBOT_MINTIME));
config.SetMaxTime(sAuctionBotConfig->GetConfig(CONFIG_AHBOT_MAXTIME));
-
- TC_LOG_DEBUG("ahbot", "AHBot: minTime = %u", config.GetMinTime());
- TC_LOG_DEBUG("ahbot", "AHBot: maxTime = %u", config.GetMaxTime());
-
- TC_LOG_DEBUG("ahbot", "AHBot: For AH type %u", config.GetHouseType());
- TC_LOG_DEBUG("ahbot", "AHBot: GrayItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_GRAY));
- TC_LOG_DEBUG("ahbot", "AHBot: WhiteItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_WHITE));
- TC_LOG_DEBUG("ahbot", "AHBot: GreenItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_GREEN));
- TC_LOG_DEBUG("ahbot", "AHBot: BlueItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_BLUE));
- TC_LOG_DEBUG("ahbot", "AHBot: PurpleItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_PURPLE));
- TC_LOG_DEBUG("ahbot", "AHBot: OrangeItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_ORANGE));
- TC_LOG_DEBUG("ahbot", "AHBot: YellowItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_YELLOW));
}
// Set static of items on one AH faction.
@@ -644,12 +571,13 @@ bool AuctionBotSeller::GetItemsToSell(SellerConfiguration& config, ItemsToSellAr
{
for (uint32 i = 0; i < MAX_ITEM_CLASS; ++i)
{
- if (config.GetMissedItemsPerClass(AuctionQuality(j), ItemClass(i)) > addedItem[j][i] && !_itemPool[j][i].empty())
+ // if _itemPool for chosen is empty, MissedItemsPerClass will return 0 here (checked at startup)
+ if (config.GetMissedItemsPerClass(AuctionQuality(j), ItemClass(i)) > addedItem[j][i])
{
ItemToSell miss_item;
miss_item.Color = j;
miss_item.Itemclass = i;
- itemsToSellArray.push_back(miss_item);
+ itemsToSellArray.emplace_back(std::move(miss_item));
found = true;
}
}
@@ -688,7 +616,9 @@ void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConf
if (sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYPRICE_SELLER))
buyPrice = sellPrice;
- float basePriceFloat = (buyPrice * stackCount * priceRatio) / (itemProto->GetClass() == 6 ? 200.0f : static_cast<float>(itemProto->GetBuyCount())) / 100.0f;
+ float basePriceFloat = buyPrice * stackCount / (itemProto->GetClass() == 6 ? 200.0f : static_cast<float>(itemProto->GetBuyCount()));
+ basePriceFloat *= priceRatio;
+
float range = basePriceFloat * 0.04f;
buyout = (static_cast<uint32>(frand(basePriceFloat - range, basePriceFloat + range) + 0.5f) / SILVER) * SILVER;
@@ -908,11 +838,11 @@ void AuctionBotSeller::AddNewAuctions(SellerConfiguration& config)
--items;
// Select random position from missed items table
- uint32 pos = urand(0, itemsToSell.size() - 1);
+ ItemToSell const& sellItem = Trinity::Containers::SelectRandomContainerElement(itemsToSell);
// Set itemId with random item ID for selected categories and color, from _itemPool table
- uint32 itemId = _itemPool[itemsToSell[pos].Color][itemsToSell[pos].Itemclass][urand(0, _itemPool[itemsToSell[pos].Color][itemsToSell[pos].Itemclass].size() - 1)];
- ++allItems[itemsToSell[pos].Color][itemsToSell[pos].Itemclass]; // Helper table to avoid rescan from DB in this loop. (has we add item in random orders)
+ uint32 itemId = Trinity::Containers::SelectRandomContainerElement(_itemPool[sellItem.Color][sellItem.Itemclass]);
+ ++allItems[sellItem.Color][sellItem.Itemclass]; // Helper table to avoid rescan from DB in this loop. (has we add item in random orders)
if (!itemId)
{
@@ -951,16 +881,14 @@ void AuctionBotSeller::AddNewAuctions(SellerConfiguration& config)
switch (etime)
{
case 1:
- etime = 43200;
- break;
- case 2:
- etime = 86400;
+ etime = DAY / 2;
break;
case 3:
- etime = 172800;
+ etime = 2 *DAY;
break;
+ case 2:
default:
- etime = 86400;
+ etime = DAY;
break;
}
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h
index ea82dd991f4..29288c6fb3b 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h
@@ -32,36 +32,28 @@ struct ItemToSell
typedef std::vector<ItemToSell> ItemsToSellArray;
typedef std::array<std::array<uint32, MAX_ITEM_CLASS>, MAX_ITEM_QUALITY> AllItemsArray;
-struct SellerItemClassInfo
+struct SellerItemInfo
{
- SellerItemClassInfo(): AmountOfItems(0), MissItems(0), Quantity(0), PriceRatio(0), RandomStackRatio(100) {}
-
- uint32 AmountOfItems;
- uint32 MissItems;
- uint32 Quantity;
- uint32 PriceRatio;
- uint32 RandomStackRatio;
+ uint32 AmountOfItems = 0;
+ uint32 MissItems = 0;
};
-struct SellerItemInfo
+struct SellerItemClassSharedInfo
{
- SellerItemInfo(): AmountOfItems(0), MissItems(0), PriceRatio(0) {}
-
- uint32 AmountOfItems;
- uint32 MissItems;
- uint32 PriceRatio;
+ uint32 PriceRatio = 0;
+ uint32 RandomStackRatio = 100;
+};
- SellerItemClassInfo ItemClassInfos[MAX_ITEM_CLASS];
+struct SellerItemQualitySharedInfo
+{
+ uint32 AmountOfItems = 0;
+ uint32 PriceRatio = 0;
};
class SellerConfiguration
{
public:
- SellerConfiguration(): LastMissedItem(0), _houseType(AUCTION_HOUSE_NEUTRAL), _minTime(1), _maxTime(72)
- {
- }
-
- ~SellerConfiguration() {}
+ SellerConfiguration() : LastMissedItem(0), _houseType(AUCTION_HOUSE_NEUTRAL), _minTime(1), _maxTime(72), _itemInfo(), _itemSharedQualityInfo(), _itemSharedClassInfo() { }
void Initialize(AuctionHouseType houseType)
{
@@ -83,35 +75,43 @@ public:
void SetMaxTime(uint32 value) { _maxTime = value; }
uint32 GetMaxTime() const { return _maxTime; }
+
// Data access classified by item class and item quality
- void SetItemsAmountPerClass(AuctionQuality quality, ItemClass itemclass, uint32 amount) { _ItemInfo[quality].ItemClassInfos[itemclass].AmountOfItems = amount * _ItemInfo[quality].ItemClassInfos[itemclass].Quantity; }
- uint32 GetItemsAmountPerClass(AuctionQuality quality, ItemClass itemclass) const { return _ItemInfo[quality].ItemClassInfos[itemclass].AmountOfItems; }
- void SetItemsQuantityPerClass(AuctionQuality quality, ItemClass itemclass, uint32 qty) { _ItemInfo[quality].ItemClassInfos[itemclass].Quantity = qty; }
- uint32 GetItemsQuantityPerClass(AuctionQuality quality, ItemClass itemclass) const { return _ItemInfo[quality].ItemClassInfos[itemclass].Quantity; }
- void SetMissedItemsPerClass(AuctionQuality quality, ItemClass itemclass, uint32 found)
+ void SetItemsAmountPerClass(AuctionQuality quality, ItemClass itemClass, uint32 amount) { _itemInfo[quality][itemClass].AmountOfItems = amount; }
+ uint32 GetItemsAmountPerClass(AuctionQuality quality, ItemClass itemClass) const { return _itemInfo[quality][itemClass].AmountOfItems; }
+
+ void SetMissedItemsPerClass(AuctionQuality quality, ItemClass itemClass, uint32 found)
{
- if (_ItemInfo[quality].ItemClassInfos[itemclass].AmountOfItems > found)
- _ItemInfo[quality].ItemClassInfos[itemclass].MissItems = _ItemInfo[quality].ItemClassInfos[itemclass].AmountOfItems - found;
+ if (_itemInfo[quality][itemClass].AmountOfItems > found)
+ _itemInfo[quality][itemClass].MissItems = _itemInfo[quality][itemClass].AmountOfItems - found;
else
- _ItemInfo[quality].ItemClassInfos[itemclass].MissItems = 0;
+ _itemInfo[quality][itemClass].MissItems = 0;
}
- uint32 GetMissedItemsPerClass(AuctionQuality quality, ItemClass itemclass) const { return _ItemInfo[quality].ItemClassInfos[itemclass].MissItems; }
+ uint32 GetMissedItemsPerClass(AuctionQuality quality, ItemClass itemClass) const { return _itemInfo[quality][itemClass].MissItems; }
// Data for every quality of item
- void SetItemsAmountPerQuality(AuctionQuality quality, uint32 cnt) { _ItemInfo[quality].AmountOfItems = cnt; }
- uint32 GetItemsAmountPerQuality(AuctionQuality quality) const { return _ItemInfo[quality].AmountOfItems; }
- void SetPriceRatioPerQuality(AuctionQuality quality, uint32 value) { _ItemInfo[quality].PriceRatio = value; }
- uint32 GetPriceRatioPerQuality(AuctionQuality quality) const { return _ItemInfo[quality].PriceRatio; }
- void SetPriceRatioPerClass(ItemClass item, uint32 value) { _ItemInfo[0].ItemClassInfos[item].PriceRatio = value; }
- uint32 GetPriceRatioPerClass(ItemClass item) const { return _ItemInfo[0].ItemClassInfos[item].PriceRatio; }
- void SetRandomStackRatioPerClass(ItemClass item, uint32 value) { _ItemInfo[0].ItemClassInfos[item].RandomStackRatio = value; }
- uint32 GetRandomStackRatioPerClass(ItemClass item) const { return _ItemInfo[0].ItemClassInfos[item].RandomStackRatio; }
+ void SetItemsAmountPerQuality(AuctionQuality quality, uint32 cnt) { _itemSharedQualityInfo[quality].AmountOfItems = cnt; }
+ uint32 GetItemsAmountPerQuality(AuctionQuality quality) const { return _itemSharedQualityInfo[quality].AmountOfItems; }
+
+ void SetPriceRatioPerQuality(AuctionQuality quality, uint32 value) { _itemSharedQualityInfo[quality].PriceRatio = value; }
+ uint32 GetPriceRatioPerQuality(AuctionQuality quality) const { return _itemSharedQualityInfo[quality].PriceRatio; }
+
+ // data for every class of item
+ void SetPriceRatioPerClass(ItemClass itemClass, uint32 value) { _itemSharedClassInfo[itemClass].PriceRatio = value; }
+ uint32 GetPriceRatioPerClass(ItemClass itemClass) const { return _itemSharedClassInfo[itemClass].PriceRatio; }
+
+ void SetRandomStackRatioPerClass(ItemClass itemClass, uint32 value) { _itemSharedClassInfo[itemClass].RandomStackRatio = value; }
+ uint32 GetRandomStackRatioPerClass(ItemClass itemClass) const { return _itemSharedClassInfo[itemClass].RandomStackRatio; }
private:
AuctionHouseType _houseType;
uint32 _minTime;
uint32 _maxTime;
- SellerItemInfo _ItemInfo[MAX_AUCTION_QUALITY];
+
+ SellerItemInfo _itemInfo[MAX_AUCTION_QUALITY][MAX_ITEM_CLASS];
+
+ SellerItemQualitySharedInfo _itemSharedQualityInfo[MAX_ITEM_QUALITY];
+ SellerItemClassSharedInfo _itemSharedClassInfo[MAX_ITEM_CLASS];
};
// This class handle all Selling method
diff --git a/src/server/game/Battlefield/Zones/BattlefieldTB.cpp b/src/server/game/Battlefield/Zones/BattlefieldTB.cpp
index f2130d973db..1d610373c94 100644
--- a/src/server/game/Battlefield/Zones/BattlefieldTB.cpp
+++ b/src/server/game/Battlefield/Zones/BattlefieldTB.cpp
@@ -609,7 +609,7 @@ void BattlefieldTB::OnCreatureCreate(Creature* creature)
HideNpc(creature);
break;
case NPC_ABANDONED_SIEGE_ENGINE:
- creature->setFaction(TBFactions[GetDefenderTeam()]);
+ creature->SetFaction(TBFactions[GetDefenderTeam()]);
creature->CastSpell(creature, SPELL_THICK_LAYER_OF_RUST, true);
break;
case NPC_SIEGE_ENGINE_TURRET:
diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp
index 3589d7dd08c..6e1bba5f1a9 100644
--- a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp
+++ b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp
@@ -580,7 +580,7 @@ void BattlefieldWG::OnBattleStart()
if (Creature* creature = GetCreature(*itr))
{
ShowNpc(creature, true);
- creature->setFaction(WintergraspFaction[GetDefenderTeam()]);
+ creature->SetFaction(WintergraspFaction[GetDefenderTeam()]);
}
}
@@ -664,7 +664,7 @@ void BattlefieldWG::OnBattleEnd(bool endByTimer)
if (Creature* creature = GetCreature(*itr))
{
if (!endByTimer)
- creature->setFaction(WintergraspFaction[GetDefenderTeam()]);
+ creature->SetFaction(WintergraspFaction[GetDefenderTeam()]);
HideNpc(creature);
}
}
@@ -891,9 +891,9 @@ void BattlefieldWG::OnCreatureRemove(Creature* /*creature*/)
case NPC_WINTERGRASP_DEMOLISHER:
{
uint8 team;
- if (creature->getFaction() == WintergraspFaction[TEAM_ALLIANCE])
+ if (creature->GetFaction() == WintergraspFaction[TEAM_ALLIANCE])
team = TEAM_ALLIANCE;
- else if (creature->getFaction() == WintergraspFaction[TEAM_HORDE])
+ else if (creature->GetFaction() == WintergraspFaction[TEAM_HORDE])
team = TEAM_HORDE;
else
return;
@@ -1604,12 +1604,12 @@ void BfWGGameObjectBuilding::Init(GameObject* go)
case GO_WINTERGRASP_FORTRESS_TOWER_2:
case GO_WINTERGRASP_FORTRESS_TOWER_3:
case GO_WINTERGRASP_FORTRESS_TOWER_4:
- turret->setFaction(WintergraspFaction[_wg->GetDefenderTeam()]);
+ turret->SetFaction(WintergraspFaction[_wg->GetDefenderTeam()]);
break;
case GO_WINTERGRASP_SHADOWSIGHT_TOWER:
case GO_WINTERGRASP_WINTER_S_EDGE_TOWER:
case GO_WINTERGRASP_FLAMEWATCH_TOWER:
- turret->setFaction(WintergraspFaction[_wg->GetAttackerTeam()]);
+ turret->SetFaction(WintergraspFaction[_wg->GetAttackerTeam()]);
break;
}
@@ -1629,12 +1629,12 @@ void BfWGGameObjectBuilding::Init(GameObject* go)
case GO_WINTERGRASP_FORTRESS_TOWER_2:
case GO_WINTERGRASP_FORTRESS_TOWER_3:
case GO_WINTERGRASP_FORTRESS_TOWER_4:
- turret->setFaction(WintergraspFaction[_wg->GetDefenderTeam()]);
+ turret->SetFaction(WintergraspFaction[_wg->GetDefenderTeam()]);
break;
case GO_WINTERGRASP_SHADOWSIGHT_TOWER:
case GO_WINTERGRASP_WINTER_S_EDGE_TOWER:
case GO_WINTERGRASP_FLAMEWATCH_TOWER:
- turret->setFaction(WintergraspFaction[_wg->GetAttackerTeam()]);
+ turret->SetFaction(WintergraspFaction[_wg->GetAttackerTeam()]);
break;
}
_wg->HideNpc(turret);
@@ -1689,14 +1689,14 @@ void BfWGGameObjectBuilding::UpdateTurretAttack(bool disable)
case GO_WINTERGRASP_FORTRESS_TOWER_3:
case GO_WINTERGRASP_FORTRESS_TOWER_4:
{
- creature->setFaction(WintergraspFaction[_wg->GetDefenderTeam()]);
+ creature->SetFaction(WintergraspFaction[_wg->GetDefenderTeam()]);
break;
}
case GO_WINTERGRASP_SHADOWSIGHT_TOWER:
case GO_WINTERGRASP_WINTER_S_EDGE_TOWER:
case GO_WINTERGRASP_FLAMEWATCH_TOWER:
{
- creature->setFaction(WintergraspFaction[_wg->GetAttackerTeam()]);
+ creature->SetFaction(WintergraspFaction[_wg->GetAttackerTeam()]);
break;
}
}
@@ -1719,14 +1719,14 @@ void BfWGGameObjectBuilding::UpdateTurretAttack(bool disable)
case GO_WINTERGRASP_FORTRESS_TOWER_3:
case GO_WINTERGRASP_FORTRESS_TOWER_4:
{
- creature->setFaction(WintergraspFaction[_wg->GetDefenderTeam()]);
+ creature->SetFaction(WintergraspFaction[_wg->GetDefenderTeam()]);
break;
}
case GO_WINTERGRASP_SHADOWSIGHT_TOWER:
case GO_WINTERGRASP_WINTER_S_EDGE_TOWER:
case GO_WINTERGRASP_FLAMEWATCH_TOWER:
{
- creature->setFaction(WintergraspFaction[_wg->GetAttackerTeam()]);
+ creature->SetFaction(WintergraspFaction[_wg->GetAttackerTeam()]);
break;
}
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
index 6e89bc86b3f..ebe3f5462b6 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
@@ -384,7 +384,7 @@ void BattlegroundAB::_NodeOccupied(uint8 node, Team team)
//aura should only apply to players who have accupied the node, set correct faction for trigger
if (trigger)
{
- trigger->setFaction(team == ALLIANCE ? 84 : 83);
+ trigger->SetFaction(team == ALLIANCE ? 84 : 83);
trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false);
}
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
index fd31810e4b8..1dabe1a572d 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
@@ -342,7 +342,7 @@ Creature* BattlegroundAV::AddAVCreature(uint16 cinfoid, uint16 type)
{
if (Creature* trigger = AddCreature(WORLD_TRIGGER, triggerSpawnID, BG_AV_CreaturePos[triggerSpawnID]))
{
- trigger->setFaction(newFaction);
+ trigger->SetFaction(newFaction);
trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false);
}
}
@@ -756,7 +756,7 @@ void BattlegroundAV::PopulateNode(BG_AV_Nodes node)
DelCreature(node + 302);
return;
}
- trigger->setFaction(owner == ALLIANCE ? 84 : 83);
+ trigger->SetFaction(owner == ALLIANCE ? 84 : 83);
trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false);
}
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
index 25400dd00b4..9cf74c56dd9 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
@@ -721,8 +721,7 @@ void BattlegroundEY::EventTeamLostPoint(Player* player, uint32 Point)
UpdatePointsCount(Team);
//remove bonus honor aura trigger creature when node is lost
- if (Point < EY_POINTS_MAX)
- DelCreature(Point + 6);//NULL checks are in DelCreature! 0-5 spirit guides
+ DelCreature(Point + 6);//NULL checks are in DelCreature! 0-5 spirit guides
}
void BattlegroundEY::EventTeamCapturedPoint(Player* player, uint32 Point)
@@ -774,9 +773,6 @@ void BattlegroundEY::EventTeamCapturedPoint(Player* player, uint32 Point)
UpdatePointsIcons(Team, Point);
UpdatePointsCount(Team);
- if (Point >= EY_POINTS_MAX)
- return;
-
Creature* trigger = GetBGCreature(Point + 6, false);//0-5 spirit guides
if (!trigger)
trigger = AddCreature(WORLD_TRIGGER, Point+6, BG_EY_TriggerPositions[Point], GetTeamIndexByTeamId(Team));
@@ -786,7 +782,7 @@ void BattlegroundEY::EventTeamCapturedPoint(Player* player, uint32 Point)
//aura should only apply to players who have accupied the node, set correct faction for trigger
if (trigger)
{
- trigger->setFaction(Team == ALLIANCE ? 84 : 83);
+ trigger->SetFaction(Team == ALLIANCE ? 84 : 83);
trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false);
}
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
index e93fc640d31..b8c28b586f8 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
@@ -363,9 +363,9 @@ bool BattlegroundIC::SetupBattleground()
// setting correct factions for Keep Cannons
for (uint8 i = BG_IC_NPC_KEEP_CANNON_1; i <= BG_IC_NPC_KEEP_CANNON_12; ++i)
- GetBGCreature(i)->setFaction(BG_IC_Factions[0]);
+ GetBGCreature(i)->SetFaction(BG_IC_Factions[0]);
for (uint8 i = BG_IC_NPC_KEEP_CANNON_13; i <= BG_IC_NPC_KEEP_CANNON_24; ++i)
- GetBGCreature(i)->setFaction(BG_IC_Factions[1]);
+ GetBGCreature(i)->SetFaction(BG_IC_Factions[1]);
// correcting spawn time for keeps bombs
for (uint8 i = BG_IC_GO_HUGE_SEAFORIUM_BOMBS_A_1; i < BG_IC_GO_HUGE_SEAFORIUM_BOMBS_H_4; ++i)
@@ -694,7 +694,7 @@ void BattlegroundIC::HandleCapturedNodes(ICNodePoint* node, bool recapture)
continue;
if (AddCreature(node->faction == TEAM_ALLIANCE ? NPC_GLAIVE_THROWER_A : NPC_GLAIVE_THROWER_H, type, BG_IC_DocksVehiclesGlaives[i], node->faction, RESPAWN_ONE_DAY))
- GetBGCreature(type)->setFaction(BG_IC_Factions[(node->faction == TEAM_ALLIANCE ? 0 : 1)]);
+ GetBGCreature(type)->SetFaction(BG_IC_Factions[(node->faction == TEAM_ALLIANCE ? 0 : 1)]);
}
// spawning catapults
@@ -706,7 +706,7 @@ void BattlegroundIC::HandleCapturedNodes(ICNodePoint* node, bool recapture)
continue;
if (AddCreature(NPC_CATAPULT, type, BG_IC_DocksVehiclesCatapults[i], node->faction, RESPAWN_ONE_DAY))
- GetBGCreature(type)->setFaction(BG_IC_Factions[(node->faction == TEAM_ALLIANCE ? 0 : 1)]);
+ GetBGCreature(type)->SetFaction(BG_IC_Factions[(node->faction == TEAM_ALLIANCE ? 0 : 1)]);
}
break;
case BG_IC_GO_WORKSHOP_BANNER:
@@ -738,7 +738,7 @@ void BattlegroundIC::HandleCapturedNodes(ICNodePoint* node, bool recapture)
continue;
if (AddCreature(NPC_DEMOLISHER, type, BG_IC_WorkshopVehicles[i], node->faction, RESPAWN_ONE_DAY))
- GetBGCreature(type)->setFaction(BG_IC_Factions[(node->faction == TEAM_ALLIANCE ? 0 : 1)]);
+ GetBGCreature(type)->SetFaction(BG_IC_Factions[(node->faction == TEAM_ALLIANCE ? 0 : 1)]);
}
// we check if the opossing siege engine is in use
@@ -763,7 +763,7 @@ void BattlegroundIC::HandleCapturedNodes(ICNodePoint* node, bool recapture)
if (Creature* siegeEngine = GetBGCreature(siegeType))
{
siegeEngine->AddUnitFlag(UnitFlags(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_CANNOT_SWIM | UNIT_FLAG_IMMUNE_TO_PC));
- siegeEngine->setFaction(BG_IC_Factions[(node->faction == TEAM_ALLIANCE ? 0 : 1)]);
+ siegeEngine->SetFaction(BG_IC_Factions[(node->faction == TEAM_ALLIANCE ? 0 : 1)]);
}
}
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
index 52cb90f5e0c..0abb08afd0f 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
@@ -654,13 +654,13 @@ void BattlegroundSA::OverrideGunFaction()
for (uint8 i = BG_SA_GUN_1; i <= BG_SA_GUN_10; i++)
{
if (Creature* gun = GetBGCreature(i))
- gun->setFaction(BG_SA_Factions[Attackers ? TEAM_ALLIANCE : TEAM_HORDE]);
+ gun->SetFaction(BG_SA_Factions[Attackers ? TEAM_ALLIANCE : TEAM_HORDE]);
}
for (uint8 i = BG_SA_DEMOLISHER_1; i <= BG_SA_DEMOLISHER_4; i++)
{
if (Creature* dem = GetBGCreature(i))
- dem->setFaction(BG_SA_Factions[Attackers]);
+ dem->SetFaction(BG_SA_Factions[Attackers]);
}
}
@@ -831,7 +831,7 @@ void BattlegroundSA::CaptureGraveyard(BG_SA_Graveyards i, Player* Source)
AddCreature(BG_SA_NpcEntries[j], j, BG_SA_NpcSpawnlocs[j], (Attackers == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE), 600);
if (Creature* dem = GetBGCreature(j))
- dem->setFaction(BG_SA_Factions[Attackers]);
+ dem->SetFaction(BG_SA_Factions[Attackers]);
}
UpdateWorldState(BG_SA_LEFT_GY_ALLIANCE, GraveyardStatus[i] == TEAM_ALLIANCE);
@@ -856,7 +856,7 @@ void BattlegroundSA::CaptureGraveyard(BG_SA_Graveyards i, Player* Source)
AddCreature(BG_SA_NpcEntries[j], j, BG_SA_NpcSpawnlocs[j], Attackers == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE, 600);
if (Creature* dem = GetBGCreature(j))
- dem->setFaction(BG_SA_Factions[Attackers]);
+ dem->SetFaction(BG_SA_Factions[Attackers]);
}
UpdateWorldState(BG_SA_RIGHT_GY_ALLIANCE, GraveyardStatus[i] == TEAM_ALLIANCE);
diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp
index 88670fa59fd..2d18d2d035c 100644
--- a/src/server/game/Chat/Chat.cpp
+++ b/src/server/game/Chat/Chat.cpp
@@ -892,7 +892,7 @@ GameTele const* ChatHandler::extractGameTeleFromLink(char* text)
return nullptr;
// id case (explicit or from shift link)
- if (cId[0] >= '0' || cId[0] >= '9')
+ if (cId[0] >= '0' && cId[0] <= '9')
if (uint32 id = atoi(cId))
return sObjectMgr->GetGameTele(id);
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 4bbb29d43c1..f9f68237d0d 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -501,7 +501,7 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/,
if (!GetCreatureAddon())
SetSheath(SHEATH_STATE_MELEE);
- setFaction(cInfo->faction);
+ SetFaction(cInfo->faction);
uint64 npcFlags;
uint32 unitFlags, unitFlags2, unitFlags3, dynamicFlags;
@@ -555,7 +555,7 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/,
{
if (Player* owner = Creature::GetCharmerOrOwnerPlayerOrPlayerItself()) // this check comes in case we don't have a player
{
- setFaction(owner->getFaction()); // vehicles should have same as owner faction
+ SetFaction(owner->GetFaction()); // vehicles should have same as owner faction
owner->VehicleSpellInitialize();
}
}
@@ -622,7 +622,18 @@ void Creature::Update(uint32 diff)
if (targetGuid == dbtableHighGuid) // if linking self, never respawn (check delayed to next day)
SetRespawnTime(DAY);
else
- m_respawnTime = (now > linkedRespawntime ? now : linkedRespawntime) + urand(5, MINUTE); // else copy time from master and add a little
+ {
+ // else copy time from master and add a little
+ time_t baseRespawnTime = std::max(linkedRespawntime, now);
+ time_t const offset = urand(5, MINUTE);
+
+ // linked guid can be a boss, uses std::numeric_limits<time_t>::max to never respawn in that instance
+ // we shall inherit it instead of adding and causing an overflow
+ if (baseRespawnTime <= std::numeric_limits<time_t>::max() - offset)
+ m_respawnTime = baseRespawnTime + offset;
+ else
+ m_respawnTime = std::numeric_limits<time_t>::max();
+ }
SaveRespawnTime(); // also save to DB immediately
}
}
@@ -670,10 +681,10 @@ void Creature::Update(uint32 diff)
if (!m_suppressedTarget.IsEmpty())
{
if (WorldObject const* objTarget = ObjectAccessor::GetWorldObject(*this, m_suppressedTarget))
- SetFacingToObject(objTarget);
+ SetFacingToObject(objTarget, false);
}
else
- SetFacingTo(m_suppressedOrientation);
+ SetFacingTo(m_suppressedOrientation, false);
m_shouldReacquireTarget = false;
}
@@ -2331,7 +2342,7 @@ bool Creature::CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction /
// only from same creature faction
if (checkfaction)
{
- if (getFaction() != u->getFaction())
+ if (GetFaction() != u->GetFaction())
return false;
}
else
@@ -3077,10 +3088,10 @@ void Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target)
bool const canTurnDuringCast = !spellInfo->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST);
// Face the target - we need to do this before the unit state is modified for no-turn spells
if (target)
- SetFacingToObject(target);
+ SetFacingToObject(target, false);
else if (!canTurnDuringCast)
if (Unit* victim = GetVictim())
- SetFacingToObject(victim); // ensure orientation is correct at beginning of cast
+ SetFacingToObject(victim, false); // ensure orientation is correct at beginning of cast
if (!canTurnDuringCast)
AddUnitState(UNIT_STATE_CANNOT_TURN);
@@ -3126,10 +3137,10 @@ void Creature::ReleaseFocus(Spell const* focusSpell, bool withDelay)
if (!m_suppressedTarget.IsEmpty())
{
if (WorldObject const* objTarget = ObjectAccessor::GetWorldObject(*this, m_suppressedTarget))
- SetFacingToObject(objTarget);
+ SetFacingToObject(objTarget, false);
}
else
- SetFacingTo(m_suppressedOrientation);
+ SetFacingTo(m_suppressedOrientation, false);
}
else
// tell the creature that it should reacquire its actual target after the delay expires (this is handled in ::Update)
@@ -3143,6 +3154,26 @@ void Creature::ReleaseFocus(Spell const* focusSpell, bool withDelay)
m_focusDelay = (!IsPet() && withDelay) ? GameTime::GetGameTimeMS() : 0; // don't allow re-target right away to prevent visual bugs
}
+bool Creature::IsMovementPreventedByCasting() const
+{
+ // first check if currently a movement allowed channel is active and we're not casting
+ if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
+ {
+ if (spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive())
+ if (spell->GetSpellInfo()->IsMoveAllowedChannel())
+ if (HasUnitState(UNIT_STATE_CASTING))
+ return true;
+ }
+
+ if (const_cast<Creature*>(this)->IsFocusing(nullptr, true))
+ return true;
+
+ if (HasUnitState(UNIT_STATE_CASTING))
+ return true;
+
+ return false;
+}
+
void Creature::StartPickPocketRefillTimer()
{
_pickpocketLootRestore = time(nullptr) + sWorld->getIntConfig(CONFIG_CREATURE_PICKPOCKET_REFILL);
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 1be3e00e39a..cc5608bfc3d 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -328,9 +328,11 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
void MustReacquireTarget() { m_shouldReacquireTarget = true; } // flags the Creature for forced (client displayed) target reacquisition in the next ::Update call
void DoNotReacquireTarget() { m_shouldReacquireTarget = false; m_suppressedTarget = ObjectGuid::Empty; m_suppressedOrientation = 0.0f; }
void FocusTarget(Spell const* focusSpell, WorldObject const* target);
- bool IsFocusing(Spell const* focusSpell = nullptr, bool withDelay = false);
+ bool IsFocusing(Spell const* focusSpell = nullptr, bool withDelay = false) override;
void ReleaseFocus(Spell const* focusSpell = nullptr, bool withDelay = true);
+ bool IsMovementPreventedByCasting() const override;
+
// Part of Evade mechanics
time_t GetLastDamagedTime() const { return _lastDamagedTime; }
void SetLastDamagedTime(time_t val) { _lastDamagedTime = val; }
diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp
index 1643a712f8e..07547ae9139 100644
--- a/src/server/game/Entities/Creature/CreatureGroups.cpp
+++ b/src/server/game/Entities/Creature/CreatureGroups.cpp
@@ -224,13 +224,15 @@ void CreatureGroup::FormationReset(bool dismiss)
m_Formed = !dismiss;
}
-void CreatureGroup::LeaderMoveTo(float x, float y, float z)
+void CreatureGroup::LeaderMoveTo(Position destination, uint32 id /*= 0*/, uint32 moveType /*= 0*/, bool orientation /*= false*/)
{
//! To do: This should probably get its own movement generator or use WaypointMovementGenerator.
//! If the leader's path is known, member's path can be plotted as well using formation offsets.
if (!m_leader)
return;
+ float x = destination.GetPositionX(), y = destination.GetPositionY(), z = destination.GetPositionZ();
+
float pathangle = std::atan2(m_leader->GetPositionY() - y, m_leader->GetPositionX() - x);
for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
@@ -256,12 +258,9 @@ void CreatureGroup::LeaderMoveTo(float x, float y, float z)
if (!member->IsFlying())
member->UpdateGroundPositionZ(dx, dy, dz);
- if (member->IsWithinDist(m_leader, dist + MAX_DESYNC))
- member->SetUnitMovementFlags(m_leader->GetUnitMovementFlags());
- else
- member->SetWalk(false);
+ Position point(dx, dy, dz, destination.GetOrientation());
- member->GetMotionMaster()->MovePoint(0, dx, dy, dz);
+ member->GetMotionMaster()->MoveFormation(id, point, moveType, !member->IsWithinDist(m_leader, dist + MAX_DESYNC), orientation);
member->SetHomePosition(dx, dy, dz, pathangle);
}
}
diff --git a/src/server/game/Entities/Creature/CreatureGroups.h b/src/server/game/Entities/Creature/CreatureGroups.h
index 38e86ea4c12..85eb7454432 100644
--- a/src/server/game/Entities/Creature/CreatureGroups.h
+++ b/src/server/game/Entities/Creature/CreatureGroups.h
@@ -19,6 +19,7 @@
#define _FORMATIONS_H
#include "Define.h"
+#include "Position.h"
#include "ObjectGuid.h"
#include <unordered_map>
#include <map>
@@ -87,7 +88,7 @@ class TC_GAME_API CreatureGroup
void RemoveMember(Creature* member);
void FormationReset(bool dismiss);
- void LeaderMoveTo(float x, float y, float z);
+ void LeaderMoveTo(Position destination, uint32 id = 0, uint32 moveType = 0, bool orientation = false);
void MemberAttackStart(Creature* member, Unit* target);
};
diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp
index 63578dfd872..18613f0fda2 100644
--- a/src/server/game/Entities/Creature/TemporarySummon.cpp
+++ b/src/server/game/Entities/Creature/TemporarySummon.cpp
@@ -187,7 +187,7 @@ void TempSummon::InitStats(uint32 duration)
if (owner && IsTrigger() && m_spells[0])
{
- setFaction(owner->getFaction());
+ SetFaction(owner->GetFaction());
SetLevel(owner->getLevel());
if (owner->GetTypeId() == TYPEID_PLAYER)
m_ControlledByPlayer = true;
@@ -212,9 +212,9 @@ void TempSummon::InitStats(uint32 duration)
}
if (m_Properties->Faction)
- setFaction(m_Properties->Faction);
+ SetFaction(m_Properties->Faction);
else if (IsVehicle() && owner) // properties should be vehicle
- setFaction(owner->getFaction());
+ SetFaction(owner->GetFaction());
}
void TempSummon::InitSummon()
@@ -307,7 +307,7 @@ void Minion::InitStats(uint32 duration)
SetReactState(REACT_PASSIVE);
SetCreatorGUID(GetOwner()->GetGUID());
- setFaction(GetOwner()->getFaction());
+ SetFaction(GetOwner()->GetFaction());
GetOwner()->SetMinion(this, true);
}
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 4e34c8b4785..1bc8383a51c 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -2112,7 +2112,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId, TriggerCastFlags trigge
if (Unit* owner = GetOwner())
{
- trigger->setFaction(owner->getFaction());
+ trigger->SetFaction(owner->GetFaction());
if (owner->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE))
trigger->AddUnitFlag(UNIT_FLAG_PVP_ATTACKABLE);
// copy pvp state flags from owner
@@ -2123,7 +2123,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId, TriggerCastFlags trigge
}
else
{
- trigger->setFaction(spellInfo->IsPositive() ? 35 : 14);
+ trigger->SetFaction(spellInfo->IsPositive() ? 35 : 14);
// Set owner guid for target if no owner available - needed by trigger auras
// - trigger gets despawned and there's no caster avalible (see AuraEffect::TriggerSpell())
trigger->CastSpell(target ? target : trigger, spellInfo, triggered, nullptr, nullptr, target ? target->GetGUID() : ObjectGuid::Empty);
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index 99235c38da3..56eabab98d1 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -30,6 +30,7 @@
#include "ItemEnchantmentMgr.h"
#include "ItemPackets.h"
#include "Log.h"
+#include "LootItemStorage.h"
#include "LootMgr.h"
#include "Map.h"
#include "ObjectAccessor.h"
@@ -763,7 +764,7 @@ void Item::SaveToDB(CharacterDatabaseTransaction& trans)
// Delete the items if this is a container
if (!loot.isLooted())
- ItemContainerDeleteLootMoneyAndLootItemsFromDB();
+ sLootItemStorage->RemoveStoredLootForContainer(GetGUID().GetCounter());
delete this;
return;
@@ -1058,7 +1059,7 @@ void Item::DeleteFromDB(CharacterDatabaseTransaction& trans)
// Delete the items if this is a container
if (!loot.isLooted())
- ItemContainerDeleteLootMoneyAndLootItemsFromDB();
+ sLootItemStorage->RemoveStoredLootForContainer(GetGUID().GetCounter());
}
/*static*/
@@ -2141,191 +2142,6 @@ uint32 Item::GetSellPrice(ItemTemplate const* proto, uint32 quality, uint32 item
return 0;
}
-void Item::ItemContainerSaveLootToDB()
-{
- // Saves the money and item loot associated with an openable item to the DB
- if (loot.isLooted()) // no money and no loot
- return;
-
- CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
-
- loot.containerID = GetGUID(); // Save this for when a LootItem is removed
-
- // Save money
- if (loot.gold > 0)
- {
- CharacterDatabasePreparedStatement* stmt_money = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
- stmt_money->setUInt64(0, loot.containerID.GetCounter());
- trans->Append(stmt_money);
-
- stmt_money = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_MONEY);
- stmt_money->setUInt64(0, loot.containerID.GetCounter());
- stmt_money->setUInt32(1, loot.gold);
- trans->Append(stmt_money);
- }
-
- // Save items
- if (!loot.isLooted())
- {
- CharacterDatabasePreparedStatement* stmt_items = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS);
- stmt_items->setUInt64(0, loot.containerID.GetCounter());
- trans->Append(stmt_items);
-
- // Now insert the items
- for (LootItemList::const_iterator _li = loot.items.begin(); _li != loot.items.end(); ++_li)
- {
- // When an item is looted, it doesn't get removed from the items collection
- // but we don't want to resave it.
- if (!_li->canSave)
- continue;
- // Conditions are not checked when loot is generated, it is checked when loot is sent to a player.
- // For items that are lootable, loot is saved to the DB immediately, that means that loot can be
- // saved to the DB that the player never should have gotten. This check prevents that, so that only
- // items that the player should get in loot are in the DB.
- // IE: Horde items are not saved to the DB for Ally players.
- Player* const guid = GetOwner();
- if (!_li->AllowedForPlayer(guid))
- continue;
-
- stmt_items = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_ITEMS);
-
- // container_id, item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, context, bonus_list_ids
- stmt_items->setUInt64(0, loot.containerID.GetCounter());
- stmt_items->setUInt32(1, _li->itemid);
- stmt_items->setUInt32(2, _li->count);
- stmt_items->setBool(3, _li->follow_loot_rules);
- stmt_items->setBool(4, _li->freeforall);
- stmt_items->setBool(5, _li->is_blocked);
- stmt_items->setBool(6, _li->is_counted);
- stmt_items->setBool(7, _li->is_underthreshold);
- stmt_items->setBool(8, _li->needs_quest);
- stmt_items->setUInt32(9, _li->randomBonusListId);
- stmt_items->setUInt8(10, AsUnderlyingType(_li->context));
- std::ostringstream bonusListIDs;
- for (int32 bonusListID : _li->BonusListIDs)
- bonusListIDs << bonusListID << ' ';
- stmt_items->setString(11, bonusListIDs.str());
- trans->Append(stmt_items);
- }
- }
-
- CharacterDatabase.CommitTransaction(trans);
-}
-
-bool Item::ItemContainerLoadLootFromDB()
-{
- // Loads the money and item loot associated with an openable item from the DB
- // Default. If there are no records for this item then it will be rolled for in Player::SendLoot()
- m_lootGenerated = false;
-
- // Save this for later use
- loot.containerID = GetGUID();
-
- // First, see if there was any money loot. This gets added directly to the container.
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_MONEY);
- stmt->setUInt64(0, loot.containerID.GetCounter());
- PreparedQueryResult money_result = CharacterDatabase.Query(stmt);
-
- if (money_result)
- {
- Field* fields = money_result->Fetch();
- loot.gold = fields[0].GetUInt32();
- }
-
- // Next, load any items that were saved
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_ITEMS);
- stmt->setUInt64(0, loot.containerID.GetCounter());
- PreparedQueryResult item_result = CharacterDatabase.Query(stmt);
-
- if (item_result)
- {
- // Get a LootTemplate for the container item. This is where
- // the saved loot was originally rolled from, we will copy conditions from it
- LootTemplate const* lt = LootTemplates_Item.GetLootFor(GetEntry());
- if (lt)
- {
- do
- {
- // Create an empty LootItem
- LootItem loot_item = LootItem();
-
- // Fill in the rest of the LootItem from the DB
- Field* fields = item_result->Fetch();
-
- // item_id, itm_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, context, bonus_list_ids
- loot_item.itemid = fields[0].GetUInt32();
- loot_item.count = fields[1].GetUInt32();
- loot_item.follow_loot_rules = fields[2].GetBool();
- loot_item.freeforall = fields[3].GetBool();
- loot_item.is_blocked = fields[4].GetBool();
- loot_item.is_counted = fields[5].GetBool();
- loot_item.canSave = true;
- loot_item.is_underthreshold = fields[6].GetBool();
- loot_item.needs_quest = fields[7].GetBool();
- loot_item.randomBonusListId = fields[8].GetUInt32();
- loot_item.context = ItemContext(fields[9].GetUInt8());
- Tokenizer bonusLists(fields[10].GetString(), ' ');
- std::transform(bonusLists.begin(), bonusLists.end(), std::back_inserter(loot_item.BonusListIDs), [](char const* token)
- {
- return int32(strtol(token, NULL, 10));
- });
-
- // Copy the extra loot conditions from the item in the loot template
- lt->CopyConditions(&loot_item);
-
- // If container item is in a bag, add that player as an allowed looter
- if (GetBagSlot())
- loot_item.AddAllowedLooter(GetOwner());
-
- // Finally add the LootItem to the container
- loot.items.push_back(loot_item);
-
- // Increment unlooted count
- loot.unlootedCount++;
-
- }
- while (item_result->NextRow());
- }
- }
-
- // Mark the item if it has loot so it won't be generated again on open
- m_lootGenerated = !loot.isLooted();
-
- return m_lootGenerated;
-}
-
-void Item::ItemContainerDeleteLootItemsFromDB()
-{
- // Deletes items associated with an openable item from the DB
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS);
- stmt->setUInt64(0, GetGUID().GetCounter());
- CharacterDatabase.Execute(stmt);
-}
-
-void Item::ItemContainerDeleteLootItemFromDB(uint32 itemID)
-{
- // Deletes a single item associated with an openable item from the DB
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM);
- stmt->setUInt64(0, GetGUID().GetCounter());
- stmt->setUInt32(1, itemID);
- CharacterDatabase.Execute(stmt);
-}
-
-void Item::ItemContainerDeleteLootMoneyFromDB()
-{
- // Deletes the money loot associated with an openable item from the DB
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
- stmt->setUInt64(0, GetGUID().GetCounter());
- CharacterDatabase.Execute(stmt);
-}
-
-void Item::ItemContainerDeleteLootMoneyAndLootItemsFromDB()
-{
- // Deletes money and items associated with an openable item from the DB
- ItemContainerDeleteLootMoneyFromDB();
- ItemContainerDeleteLootItemsFromDB();
-}
-
uint32 Item::GetItemLevel(Player const* owner) const
{
ItemTemplate const* itemTemplate = GetTemplate();
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index c4c5ee62d5a..007b9ef46c5 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -231,14 +231,6 @@ class TC_GAME_API Item : public Object
virtual void DeleteFromDB(CharacterDatabaseTransaction& trans);
static void DeleteFromInventoryDB(CharacterDatabaseTransaction& trans, ObjectGuid::LowType itemGuid);
- // Lootable items and their contents
- void ItemContainerSaveLootToDB();
- bool ItemContainerLoadLootFromDB();
- void ItemContainerDeleteLootItemsFromDB();
- void ItemContainerDeleteLootItemFromDB(uint32 itemID);
- void ItemContainerDeleteLootMoneyFromDB();
- void ItemContainerDeleteLootMoneyAndLootItemsFromDB();
-
void DeleteFromInventoryDB(CharacterDatabaseTransaction& trans);
void SaveRefundDataToDB();
void DeleteRefundDataFromDB(CharacterDatabaseTransaction* trans);
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 94fd3e932c8..5e79eb1316c 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1889,7 +1889,7 @@ Creature* WorldObject::SummonTrigger(float x, float y, float z, float ang, uint3
//summon->SetName(GetName());
if (GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT)
{
- summon->setFaction(((Unit*)this)->getFaction());
+ summon->SetFaction(((Unit*)this)->GetFaction());
summon->SetLevel(((Unit*)this)->getLevel());
}
diff --git a/src/server/game/Entities/Object/Updates/ViewerDependentValues.h b/src/server/game/Entities/Object/Updates/ViewerDependentValues.h
index 52813dd4c82..1901e5e623d 100644
--- a/src/server/game/Entities/Object/Updates/ViewerDependentValues.h
+++ b/src/server/game/Entities/Object/Updates/ViewerDependentValues.h
@@ -147,7 +147,7 @@ public:
FactionTemplateEntry const* ft2 = receiver->GetFactionTemplateEntry();
if (ft1 && ft2 && !ft1->IsFriendlyTo(ft2))
// pretend that all other HOSTILE players have own faction, to allow follow, heal, rezz (trade wont work)
- factionTemplate = receiver->getFaction();
+ factionTemplate = receiver->GetFaction();
}
return factionTemplate;
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index 9c16502dd25..8852af1be8c 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -186,7 +186,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
PhasingHandler::InheritPhaseShift(this, owner);
setPetType(petType);
- setFaction(owner->getFaction());
+ SetFaction(owner->GetFaction());
SetCreatedBySpell(summonSpellId);
if (IsCritter())
@@ -1676,7 +1676,7 @@ void Pet::CastPetAuras(bool current)
if (!IsPermanentPetFor(owner))
return;
- for (PetAuraSet::const_iterator itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end();)
+ for (auto itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end();)
{
PetAura const* pa = *itr;
++itr;
@@ -1708,7 +1708,7 @@ bool Pet::IsPetAura(Aura const* aura)
Player* owner = GetOwner();
// if the owner has that pet aura, return true
- for (PetAuraSet::const_iterator itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end(); ++itr)
+ for (auto itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end(); ++itr)
{
if ((*itr)->GetAura(GetEntry()) == aura->GetId())
return true;
diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h
index 2e17b976be6..09a6e0a8afe 100644
--- a/src/server/game/Entities/Pet/Pet.h
+++ b/src/server/game/Entities/Pet/Pet.h
@@ -40,6 +40,7 @@ typedef std::unordered_map<uint32, PetSpell> PetSpellMap;
typedef std::vector<uint32> AutoSpellList;
class Player;
+class PetAura;
class TC_GAME_API Pet : public Guardian
{
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index b932d9e35c4..3dd310f4b52 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -75,6 +75,7 @@
#include "LFGMgr.h"
#include "Language.h"
#include "Log.h"
+#include "LootItemStorage.h"
#include "LootMgr.h"
#include "LootPackets.h"
#include "Mail.h"
@@ -90,6 +91,7 @@
#include "OutdoorPvPMgr.h"
#include "Pet.h"
#include "PetPackets.h"
+#include "PoolMgr.h"
#include "PhasingHandler.h"
#include "QueryCallback.h"
#include "QueryHolder.h"
@@ -2198,13 +2200,13 @@ void Player::SetGameMaster(bool on)
if (on)
{
m_ExtraFlags |= PLAYER_EXTRA_GM_ON;
- setFaction(35);
+ SetFaction(35);
AddPlayerFlag(PLAYER_FLAGS_GM);
AddUnitFlag2(UNIT_FLAG2_ALLOW_CHEAT_SPELLS);
if (Pet* pet = GetPet())
{
- pet->setFaction(35);
+ pet->SetFaction(35);
pet->getHostileRefManager().setOnlineOfflineState(false);
}
@@ -2228,7 +2230,7 @@ void Player::SetGameMaster(bool on)
if (Pet* pet = GetPet())
{
- pet->setFaction(getFaction());
+ pet->SetFaction(GetFaction());
pet->getHostileRefManager().setOnlineOfflineState(true);
}
@@ -2936,7 +2938,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
if (active)
{
- if (spellInfo->IsPassive() && IsNeedCastPassiveSpellAtLearn(spellInfo))
+ if (spellInfo->IsPassive() && HandlePassiveSpellLearn(spellInfo))
CastSpell(this, spellId, true);
}
else if (IsInWorld())
@@ -3063,7 +3065,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
// also cast passive spells (including all talents without SPELL_EFFECT_LEARN_SPELL) with additional checks
else if (spellInfo->IsPassive())
{
- if (IsNeedCastPassiveSpellAtLearn(spellInfo))
+ if (HandlePassiveSpellLearn(spellInfo))
CastSpell(this, spellId, true);
}
else if (spellInfo->HasEffect(SPELL_EFFECT_SKILL_STEP))
@@ -3194,7 +3196,7 @@ void Player::RemoveTemporarySpell(uint32 spellId)
m_spells.erase(itr);
}
-bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const
+bool Player::HandlePassiveSpellLearn(SpellInfo const* spellInfo)
{
// note: form passives activated with shapeshift spells be implemented by HandleShapeshiftBoosts instead of spell_learn_spell
// talent dependent passives activated at form apply have proper stance data
@@ -3206,12 +3208,16 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const
need_cast &= IsCurrentSpecMasterySpell(spellInfo);
// Check EquippedItemClass
- // passive spells which apply aura and have an item requirement are to be added in Player::ApplyItemDependentAuras
- if (spellInfo->IsPassive() && spellInfo->EquippedItemClass >= 0)
+ // passive spells which apply aura and have an item requirement are to be added manually, instead of casted
+ if (spellInfo->EquippedItemClass >= 0)
{
for (SpellEffectInfo const* effectInfo : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
if (effectInfo && effectInfo->IsAura())
+ {
+ if (!HasAura(spellInfo->Id) && HasItemFitToSpellRequirements(spellInfo))
+ AddAura(spellInfo->Id, this);
return false;
+ }
}
//Check CasterAuraStates
@@ -6292,7 +6298,7 @@ void Player::setFactionForRace(uint8 race)
m_team = TeamForRace(race);
ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race);
- setFaction(rEntry ? rEntry->FactionID : 0);
+ SetFaction(rEntry ? rEntry->FactionID : 0);
}
ReputationRank Player::GetReputationRank(uint32 faction) const
@@ -6415,8 +6421,8 @@ void Player::RewardReputation(Unit* victim, float rate)
FactionEntry const* factionEntry1 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction1);
uint32 current_reputation_rank1 = GetReputationMgr().GetRank(factionEntry1);
- if (factionEntry1 && current_reputation_rank1 <= Rep->ReputationMaxCap1)
- GetReputationMgr().ModifyReputation(factionEntry1, donerep1);
+ if (factionEntry1)
+ GetReputationMgr().ModifyReputation(factionEntry1, donerep1, current_reputation_rank1 > Rep->ReputationMaxCap1);
}
if (Rep->RepFaction2 && (!Rep->TeamDependent || team == HORDE))
@@ -6426,8 +6432,8 @@ void Player::RewardReputation(Unit* victim, float rate)
FactionEntry const* factionEntry2 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction2);
uint32 current_reputation_rank2 = GetReputationMgr().GetRank(factionEntry2);
- if (factionEntry2 && current_reputation_rank2 <= Rep->ReputationMaxCap2)
- GetReputationMgr().ModifyReputation(factionEntry2, donerep2);
+ if (factionEntry2)
+ GetReputationMgr().ModifyReputation(factionEntry2, donerep2, current_reputation_rank2 > Rep->ReputationMaxCap2);
}
}
@@ -6479,7 +6485,7 @@ void Player::RewardReputation(Quest const* quest)
rep = CalculateReputationGain(REPUTATION_SOURCE_QUEST, GetQuestLevel(quest), rep, quest->RewardFactionId[i], noQuestBonus);
bool noSpillover = (quest->GetRewardReputationMask() & (1 << i)) != 0;
- GetReputationMgr().ModifyReputation(factionEntry, rep, noSpillover);
+ GetReputationMgr().ModifyReputation(factionEntry, rep, false, noSpillover);
}
}
@@ -6937,7 +6943,7 @@ void Player::ModifyCurrency(uint32 id, int32 count, bool printLog/* = true*/, bo
{
if (currency->Flags & CURRENCY_FLAG_HIGH_PRECISION)
count /= 100;
- GetReputationMgr().ModifyReputation(factionEntry, count, true);
+ GetReputationMgr().ModifyReputation(factionEntry, count, false, true);
return;
}
@@ -8834,9 +8840,12 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
loot = &item->loot;
+ // Store container id
+ loot->containerID = item->GetGUID();
+
// If item doesn't already have loot, attempt to load it. If that
- // fails then this is first time opening, generate loot
- if (!item->m_lootGenerated && !item->ItemContainerLoadLootFromDB())
+ // fails then this is first time opening, generate loot
+ if (!item->m_lootGenerated && !sLootItemStorage->LoadStoredLoot(item, this))
{
item->m_lootGenerated = true;
loot->clear();
@@ -8859,7 +8868,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
// Force save the loot and money items that were just rolled
// Also saves the container item ID in Loot struct (not to DB)
if (loot->gold > 0 || loot->unlootedCount > 0)
- item->ItemContainerSaveLootToDB();
+ sLootItemStorage->AddNewStoredLoot(loot, this);
break;
}
@@ -12799,6 +12808,7 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount());
sScriptMgr->OnItemRemove(this, pItem);
+ ItemTemplate const* pProto = pItem->GetTemplate();
if (bag == INVENTORY_SLOT_BAG_0)
{
SetInvSlot(slot, ObjectGuid::Empty);
@@ -12806,10 +12816,8 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
// equipment and equipped bags can have applied bonuses
if (slot < INVENTORY_SLOT_BAG_END)
{
- ItemTemplate const* pProto = pItem->GetTemplate();
-
// item set bonuses applied only at equip and removed at unequip, and still active for broken items
- if (pProto && pProto->GetItemSet())
+ if (pProto->GetItemSet())
RemoveItemsSetItem(this, pProto);
_ApplyItemMods(pItem, slot, false);
@@ -12843,9 +12851,8 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
// Delete rolled money / loot from db.
// MUST be done before RemoveFromWorld() or GetTemplate() fails
- if (ItemTemplate const* pTmp = pItem->GetTemplate())
- if (pTmp->GetFlags() & ITEM_FLAG_HAS_LOOT)
- pItem->ItemContainerDeleteLootMoneyAndLootItemsFromDB();
+ if (pProto->GetFlags() & ITEM_FLAG_HAS_LOOT)
+ sLootItemStorage->RemoveStoredLootForContainer(pItem->GetGUID().GetCounter());
if (IsInWorld() && update)
{
@@ -13762,7 +13769,7 @@ void Player::SwapItem(uint16 src, uint16 dst)
{
if (Item* bagItem = bag->GetItemByPos(i))
{
- if (bagItem->m_lootGenerated)
+ if (bagItem->GetGUID() == GetLootGUID())
{
m_session->DoLootRelease(GetLootGUID());
released = true; // so we don't need to look at dstBag
@@ -13779,7 +13786,7 @@ void Player::SwapItem(uint16 src, uint16 dst)
{
if (Item* bagItem = bag->GetItemByPos(i))
{
- if (bagItem->m_lootGenerated)
+ if (bagItem->GetGUID() == GetLootGUID())
{
m_session->DoLootRelease(GetLootGUID());
break;
@@ -13868,7 +13875,13 @@ void Player::RemoveItemFromBuyBackSlot(uint32 slot, bool del)
{
pItem->RemoveFromWorld();
if (del)
+ {
+ if (ItemTemplate const* itemTemplate = pItem->GetTemplate())
+ if (itemTemplate->GetFlags() & ITEM_FLAG_HAS_LOOT)
+ sLootItemStorage->RemoveStoredLootForContainer(pItem->GetGUID().GetCounter());
+
pItem->SetState(ITEM_REMOVED, this);
+ }
}
m_items[slot] = nullptr;
@@ -15204,8 +15217,8 @@ bool Player::CanSeeStartQuest(Quest const* quest)
{
if (!DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) && SatisfyQuestClass(quest, false) && SatisfyQuestRace(quest, false) &&
SatisfyQuestSkill(quest, false) && SatisfyQuestExclusiveGroup(quest, false) && SatisfyQuestReputation(quest, false) &&
- SatisfyQuestDependentQuests(quest, false) && SatisfyQuestNextChain(quest, false) &&
- SatisfyQuestPrevChain(quest, false) && SatisfyQuestDay(quest, false) && SatisfyQuestWeek(quest, false) &&
+ SatisfyQuestDependentQuests(quest, false) &&
+ SatisfyQuestDay(quest, false) && SatisfyQuestWeek(quest, false) &&
SatisfyQuestMonth(quest, false) && SatisfyQuestSeasonal(quest, false))
{
return int32(getLevel() + sWorld->getIntConfig(CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF)) >= GetQuestMinLevel(quest);
@@ -15221,7 +15234,6 @@ bool Player::CanTakeQuest(Quest const* quest, bool msg)
&& SatisfyQuestClass(quest, msg) && SatisfyQuestRace(quest, msg) && SatisfyQuestLevel(quest, msg)
&& SatisfyQuestSkill(quest, msg) && SatisfyQuestReputation(quest, msg)
&& SatisfyQuestDependentQuests(quest, msg) && SatisfyQuestTimed(quest, msg)
- && SatisfyQuestNextChain(quest, msg) && SatisfyQuestPrevChain(quest, msg)
&& SatisfyQuestDay(quest, msg) && SatisfyQuestWeek(quest, msg)
&& SatisfyQuestMonth(quest, msg) && SatisfyQuestSeasonal(quest, msg)
&& SatisfyQuestConditions(quest, msg);
@@ -15259,7 +15271,7 @@ bool Player::CanCompleteQuest(uint32 quest_id)
if (!qInfo)
return false;
- if (!qInfo->IsRepeatable() && m_RewardedQuests.find(quest_id) != m_RewardedQuests.end())
+ if (!qInfo->IsRepeatable() && GetQuestRewardStatus(quest_id))
return false; // not allow re-complete quest
// auto complete quest
@@ -15652,10 +15664,10 @@ uint32 Player::GetQuestMoneyReward(Quest const* quest) const
uint32 Player::GetQuestXPReward(Quest const* quest)
{
- bool rewarded = (m_RewardedQuests.find(quest->GetQuestId()) != m_RewardedQuests.end());
+ bool rewarded = IsQuestRewarded(quest->GetQuestId()) && !quest->IsDFQuest();
// Not give XP in case already completed once repeatable quest
- if (rewarded && !quest->IsDFQuest())
+ if (rewarded)
return 0;
uint32 XP = quest->XPValue(this) * sWorld->getRate(RATE_XP_QUEST);
@@ -15807,7 +15819,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
SendNewItem(item, quest->RewardItemCount[i], true, false);
}
else if (quest->IsDFQuest())
- SendItemRetrievalMail(quest->RewardItemId[i], quest->RewardItemCount[i], ItemContext::Quest_Reward);
+ SendItemRetrievalMail(itemId, quest->RewardItemCount[i], ItemContext::Quest_Reward);
}
}
}
@@ -15886,12 +15898,6 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
if (quest->CanIncreaseRewardedQuestCounters())
SetRewardedQuest(quest_id);
- // StoreNewItem, mail reward, etc. save data directly to the database
- // to prevent exploitable data desynchronisation we save the quest status to the database too
- // (to prevent rewarding this quest another time while rewards were already given out)
- CharacterDatabaseTransaction trans = CharacterDatabaseTransaction(nullptr);
- _SaveQuestStatus(trans);
-
SendQuestReward(quest, questGiver ? questGiver->ToCreature() : nullptr, XP, !announce);
// cast spells after mark quest complete (some spells have quest completed state requirements in spell_area data)
@@ -15927,6 +15933,9 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
UpdateCriteria(CRITERIA_TYPE_COMPLETE_QUEST_COUNT);
UpdateCriteria(CRITERIA_TYPE_COMPLETE_QUEST, quest->GetQuestId());
+ // make full db save
+ SaveToDB(false);
+
if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id))
SetQuestCompletedBit(questBit, true);
@@ -15957,13 +15966,15 @@ void Player::FailQuest(uint32 questId)
{
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
{
- // Already complete quests shouldn't turn failed.
- if (GetQuestStatus(questId) == QUEST_STATUS_COMPLETE && !quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED))
- return;
+ QuestStatus qStatus = GetQuestStatus(questId);
- // You can't fail a quest if you don't have it, or if it's already rewarded.
- if (GetQuestStatus(questId) == QUEST_STATUS_NONE || GetQuestStatus(questId) == QUEST_STATUS_REWARDED)
- return;
+ // we can only fail incomplete quest or...
+ if (qStatus != QUEST_STATUS_INCOMPLETE)
+ {
+ // completed timed quest with no requirements
+ if (qStatus != QUEST_STATUS_COMPLETE || !quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED) || !quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_COMPLETED_AT_START))
+ return;
+ }
SetQuestStatus(questId, QUEST_STATUS_FAILED);
@@ -16344,7 +16355,7 @@ bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) const
}
// alternative quest already started or completed - but don't check rewarded states if both are repeatable
- if (GetQuestStatus(exclude_Id) != QUEST_STATUS_NONE || (!(qInfo->IsRepeatable() && Nquest->IsRepeatable()) && (m_RewardedQuests.find(exclude_Id) != m_RewardedQuests.end())))
+ if (GetQuestStatus(exclude_Id) != QUEST_STATUS_NONE || (!(qInfo->IsRepeatable() && Nquest->IsRepeatable()) && GetQuestRewardStatus(exclude_Id)))
{
if (msg)
{
@@ -16358,62 +16369,6 @@ bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) const
return true;
}
-bool Player::SatisfyQuestNextChain(Quest const* qInfo, bool msg) const
-{
- uint32 nextQuest = qInfo->GetNextQuestInChain();
- if (!nextQuest)
- return true;
-
- // next quest in chain already started or completed
- if (GetQuestStatus(nextQuest) != QUEST_STATUS_NONE) // GetQuestStatus returns QUEST_STATUS_COMPLETED for rewarded quests
- {
- if (msg)
- {
- SendCanTakeQuestResponse(QUEST_ERR_NONE);
- TC_LOG_DEBUG("misc", "Player::SatisfyQuestNextChain: Sent QUEST_ERR_NONE (QuestID: %u) because player '%s' (%s) already did or started next quest in chain.",
- qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str());
- }
- return false;
- }
-
- // check for all quests further up the chain
- // only necessary if there are quest chains with more than one quest that can be skipped
- //return SatisfyQuestNextChain(qInfo->GetNextQuestInChain(), msg);
- return true;
-}
-
-bool Player::SatisfyQuestPrevChain(Quest const* qInfo, bool msg)
-{
- // No previous quest in chain
- if (qInfo->PrevChainQuests.empty())
- return true;
-
- for (uint32 prevQuestId : qInfo->PrevChainQuests)
- {
- auto itr = m_QuestStatus.find(prevQuestId);
-
- // If any of the previous quests in chain active, return false
- if (itr != m_QuestStatus.end() && itr->second.Status != QUEST_STATUS_NONE)
- {
- if (msg)
- {
- SendCanTakeQuestResponse(QUEST_ERR_NONE);
- TC_LOG_DEBUG("misc", "Player::SatisfyQuestNextChain: Sent QUEST_ERR_NONE (QuestID: %u) because player '%s' (%s) already did or started next quest in chain.",
- qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str());
- }
- return false;
- }
-
- // check for all quests further down the chain
- // only necessary if there are quest chains with more than one quest that can be skipped
- //if (!SatisfyQuestPrevChain(prevId, msg))
- // return false;
- }
-
- // No previous quest in chain active
- return true;
-}
-
bool Player::SatisfyQuestDay(Quest const* qInfo, bool /*msg*/) const
{
if (!qInfo->IsDaily() && !qInfo->IsDFQuest())
@@ -16541,7 +16496,7 @@ bool Player::GetQuestRewardStatus(uint32 quest_id) const
// for repeatable quests: rewarded field is set after first reward only to prevent getting XP more than once
if (!qInfo->IsRepeatable())
- return m_RewardedQuests.find(quest_id) != m_RewardedQuests.end();
+ return IsQuestRewarded(quest_id);
return false;
}
@@ -16556,14 +16511,8 @@ QuestStatus Player::GetQuestStatus(uint32 quest_id) const
if (itr != m_QuestStatus.end())
return itr->second.Status;
- if (Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest_id))
- {
- if (qInfo->IsSeasonal() && !qInfo->IsRepeatable())
- return SatisfyQuestSeasonal(qInfo, false) ? QUEST_STATUS_NONE : QUEST_STATUS_REWARDED;
-
- if (!qInfo->IsRepeatable() && IsQuestRewarded(quest_id))
- return QUEST_STATUS_REWARDED;
- }
+ if (GetQuestRewardStatus(quest_id))
+ return QUEST_STATUS_REWARDED;
}
return QUEST_STATUS_NONE;
}
@@ -16571,7 +16520,22 @@ QuestStatus Player::GetQuestStatus(uint32 quest_id) const
bool Player::CanShareQuest(uint32 quest_id) const
{
Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest_id);
- return qInfo && qInfo->HasFlag(QUEST_FLAGS_SHARABLE) && IsActiveQuest(quest_id);
+ if (qInfo && qInfo->HasFlag(QUEST_FLAGS_SHARABLE))
+ {
+ QuestStatusMap::const_iterator itr = m_QuestStatus.find(quest_id);
+ if (itr != m_QuestStatus.end())
+ {
+ // in pool and not currently available (wintergrasp weekly, dalaran weekly) - can't share
+ if (sPoolMgr->IsPartOfAPool<Quest>(quest_id) && !sPoolMgr->IsSpawnedObject<Quest>(quest_id))
+ {
+ SendPushToPartyResponse(this, QUEST_PUSH_NOT_DAILY);
+ return false;
+ }
+
+ return true;
+ }
+ }
+ return false;
}
void Player::SetQuestStatus(uint32 questId, QuestStatus status, bool update /*= true*/)
@@ -16617,6 +16581,18 @@ void Player::RemoveRewardedQuest(uint32 questId, bool update /*= true*/)
if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(questId))
SetQuestCompletedBit(questBit, false);
+ // Remove seasonal quest also
+ Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId);
+ if (qInfo->IsSeasonal())
+ {
+ uint16 eventId = qInfo->GetEventIdForQuest();
+ if (m_seasonalquests.find(eventId) != m_seasonalquests.end())
+ {
+ m_seasonalquests[eventId].erase(questId);
+ m_SeasonalQuestChanged = true;
+ }
+ }
+
if (update)
SendQuestUpdate(questId);
}
@@ -16875,8 +16851,10 @@ void Player::AreaExploredOrEventHappens(uint32 questId)
{
q_status.Explored = true;
m_QuestStatusSave[questId] = QUEST_DEFAULT_SAVE_TYPE;
- SetQuestSlotState(log_slot, QUEST_STATE_COMPLETE);
- SendQuestComplete(questId);
+
+ // if we cannot complete quest send exploration succeded (to mark exploration on client)
+ if (!CanCompleteQuest(questId))
+ SendQuestComplete(questId);
}**/
}
if (CanCompleteQuest(questId))
@@ -17651,7 +17629,7 @@ void Player::SendQuestConfirmAccept(Quest const* quest, Player* receiver) const
receiver->GetSession()->SendPacket(packet.Write());
}
-void Player::SendPushToPartyResponse(Player* player, QuestPushReason reason) const
+void Player::SendPushToPartyResponse(Player const* player, QuestPushReason reason) const
{
if (player)
{
@@ -19840,7 +19818,8 @@ void Player::_LoadBoundInstances(PreparedQueryResult result)
Group* group = GetGroup();
- //QueryResult* result = CharacterDatabase.PQuery("SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid));
+ // 0 1 2 3 4 5 6
+ // SELECT id, permanent, map, difficulty, extendState, resettime, entranceId FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = ?
if (result)
{
do
@@ -19853,7 +19832,7 @@ void Player::_LoadBoundInstances(PreparedQueryResult result)
uint8 difficulty = fields[3].GetUInt8();
BindExtensionState extendState = BindExtensionState(fields[4].GetUInt8());
- time_t resetTime = time_t(fields[5].GetUInt32());
+ time_t resetTime = time_t(fields[5].GetUInt64());
// the resettime for normal instances is only saved when the InstanceSave is unloaded
// so the value read from the DB may be wrong here but only if the InstanceSave is loaded
// and in that case it is not used
@@ -20874,12 +20853,25 @@ void Player::_SaveInventory(CharacterDatabaseTransaction& trans)
for (uint8 i = BUYBACK_SLOT_START; i < BUYBACK_SLOT_END; ++i)
{
Item* item = m_items[i];
- if (!item || item->GetState() == ITEM_NEW)
+ if (!item)
+ continue;
+
+ if (item->GetState() == ITEM_NEW)
+ {
+ if (ItemTemplate const* itemTemplate = item->GetTemplate())
+ if (itemTemplate->GetFlags() & ITEM_FLAG_HAS_LOOT)
+ sLootItemStorage->RemoveStoredLootForContainer(item->GetGUID().GetCounter());
+
continue;
+ }
item->DeleteFromInventoryDB(trans);
item->DeleteFromDB(trans);
m_items[i]->FSetState(ITEM_NEW);
+
+ if (ItemTemplate const* itemTemplate = item->GetTemplate())
+ if (itemTemplate->GetFlags() & ITEM_FLAG_HAS_LOOT)
+ sLootItemStorage->RemoveStoredLootForContainer(item->GetGUID().GetCounter());
}
// Updated played time for refundable items. We don't do this in Player::Update because there's simply no need for it,
@@ -21275,7 +21267,7 @@ void Player::_SaveWeeklyQuestStatus(CharacterDatabaseTransaction& trans)
void Player::_SaveSeasonalQuestStatus(CharacterDatabaseTransaction& trans)
{
- if (!m_SeasonalQuestChanged || m_seasonalquests.empty())
+ if (!m_SeasonalQuestChanged)
return;
// we don't need transactions here.
@@ -21283,6 +21275,11 @@ void Player::_SaveSeasonalQuestStatus(CharacterDatabaseTransaction& trans)
stmt->setUInt64(0, GetGUID().GetCounter());
trans->Append(stmt);
+ m_SeasonalQuestChanged = false;
+
+ if (m_seasonalquests.empty())
+ return;
+
for (SeasonalEventQuestMap::const_iterator iter = m_seasonalquests.begin(); iter != m_seasonalquests.end(); ++iter)
{
uint16 eventId = iter->first;
@@ -21298,8 +21295,6 @@ void Player::_SaveSeasonalQuestStatus(CharacterDatabaseTransaction& trans)
trans->Append(stmt);
}
}
-
- m_SeasonalQuestChanged = false;
}
void Player::_SaveMonthlyQuestStatus(CharacterDatabaseTransaction& trans)
@@ -21401,13 +21396,14 @@ void Player::_SaveSpells(CharacterDatabaseTransaction& trans)
if (itr->second->state == PLAYERSPELL_REMOVED)
{
delete itr->second;
- m_spells.erase(itr++);
+ itr = m_spells.erase(itr);
+ continue;
}
- else
- {
+
+ if (itr->second->state != PLAYERSPELL_TEMPORARY)
itr->second->state = PLAYERSPELL_UNCHANGED;
- ++itr;
- }
+
+ ++itr;
}
}
@@ -21838,6 +21834,20 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
}
}
+void Player::AddPetAura(PetAura const* petSpell)
+{
+ m_petAuras.insert(petSpell);
+ if (Pet* pet = GetPet())
+ pet->CastPetAura(petSpell);
+}
+
+void Player::RemovePetAura(PetAura const* petSpell)
+{
+ m_petAuras.erase(petSpell);
+ if (Pet* pet = GetPet())
+ pet->RemoveAurasDueToSpell(petSpell->GetAura(pet->GetEntry()));
+}
+
void Player::StopCastingCharm()
{
Unit* charm = GetCharm();
@@ -22622,7 +22632,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
float discount = GetReputationPriceDiscount(npc);
totalcost = uint32(ceil(totalcost * discount));
firstcost = uint32(ceil(firstcost * discount));
- m_taxi.SetFlightMasterFactionTemplateId(npc->getFaction());
+ m_taxi.SetFlightMasterFactionTemplateId(npc->GetFaction());
}
else
m_taxi.SetFlightMasterFactionTemplateId(0);
@@ -26225,7 +26235,7 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot, AELootResult* aeResult/*
// LootItem is being removed (looted) from the container, delete it from the DB.
if (!loot->containerID.IsEmpty())
- loot->DeleteLootItemFromContainerItemDB(item->itemid);
+ sLootItemStorage->RemoveStoredLootItemForContainer(loot->containerID.GetCounter(), item->itemid, item->count);
}
else
SendEquipError(msg, nullptr, nullptr, item->itemid);
@@ -28217,7 +28227,7 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
PhasingHandler::InheritPhaseShift(pet, this);
pet->SetCreatorGUID(GetGUID());
- pet->setFaction(getFaction());
+ pet->SetFaction(GetFaction());
pet->SetNpcFlags(UNIT_NPC_FLAG_NONE);
pet->SetNpcFlags2(UNIT_NPC_FLAG_2_NONE);
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 0eacdb13fe1..dafedb22e77 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -78,6 +78,7 @@ class Item;
class LootStore;
class OutdoorPvP;
class Pet;
+class PetAura;
class PlayerAI;
class PlayerAchievementMgr;
class PlayerMenu;
@@ -1097,6 +1098,11 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
Pet* SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 despwtime);
void RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent = false);
+ // pet auras
+ std::unordered_set<PetAura const*> m_petAuras;
+ void AddPetAura(PetAura const* petSpell);
+ void RemovePetAura(PetAura const* petSpell);
+
/// Handles said message in regular chat based on declared language and in config pre-defined Range.
void Say(std::string const& text, Language language, WorldObject const* = nullptr) override;
void Say(uint32 textId, WorldObject const* target = nullptr) override;
@@ -1352,8 +1358,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool SatisfyQuestConditions(Quest const* qInfo, bool msg);
bool SatisfyQuestTimed(Quest const* qInfo, bool msg) const;
bool SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) const;
- bool SatisfyQuestNextChain(Quest const* qInfo, bool msg) const;
- bool SatisfyQuestPrevChain(Quest const* qInfo, bool msg);
bool SatisfyQuestDay(Quest const* qInfo, bool msg) const;
bool SatisfyQuestWeek(Quest const* qInfo, bool msg) const;
bool SatisfyQuestMonth(Quest const* qInfo, bool msg) const;
@@ -1419,7 +1423,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void SendQuestTimerFailed(uint32 questID) const;
void SendCanTakeQuestResponse(QuestFailedReason reason, bool sendErrorMessage = true, std::string reasonText = "") const;
void SendQuestConfirmAccept(Quest const* quest, Player* receiver) const;
- void SendPushToPartyResponse(Player* player, QuestPushReason reason) const;
+ void SendPushToPartyResponse(Player const* player, QuestPushReason reason) const;
void SendQuestUpdateAddCredit(Quest const* quest, ObjectGuid guid, QuestObjective const& obj, uint16 count) const;
void SendQuestUpdateAddCreditSimple(QuestObjective const& obj) const;
void SendQuestUpdateAddPlayer(Quest const* quest, uint16 newCount) const;
@@ -1556,7 +1560,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool HasActiveSpell(uint32 spell) const; // show in spellbook
SpellInfo const* GetCastSpellInfo(SpellInfo const* spellInfo) const override;
bool IsSpellFitByClassAndRace(uint32 spell_id) const;
- bool IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const;
+ bool HandlePassiveSpellLearn(SpellInfo const* spellInfo);
bool IsCurrentSpecMasterySpell(SpellInfo const* spellInfo) const;
void SendProficiency(ItemClass itemClass, uint32 itemSubclassMask) const;
diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp
index 2170ba4d7c7..88fb805a71d 100644
--- a/src/server/game/Entities/Unit/StatSystem.cpp
+++ b/src/server/game/Entities/Unit/StatSystem.cpp
@@ -577,7 +577,7 @@ void Player::UpdateHealingDonePercentMod()
SetUpdateFieldStatValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::ModHealingDonePercent), value);
}
-const float m_diminishing_k[MAX_CLASSES] =
+float const m_diminishing_k[MAX_CLASSES] =
{
0.9560f, // Warrior
0.9560f, // Paladin
@@ -593,27 +593,50 @@ const float m_diminishing_k[MAX_CLASSES] =
0.9830f // Demon Hunter
};
-void Player::UpdateParryPercentage()
+// helper function
+float CalculateDiminishingReturns(float const (&capArray)[MAX_CLASSES], uint8 playerClass, float nonDiminishValue, float diminishValue)
{
- const float parry_cap[MAX_CLASSES] =
- {
- 65.631440f, // Warrior
- 65.631440f, // Paladin
- 145.560408f, // Hunter
- 145.560408f, // Rogue
- 0.0f, // Priest
- 65.631440f, // DK
- 145.560408f, // Shaman
- 0.0f, // Mage
- 0.0f, // Warlock
- 90.6425f, // Monk
- 0.0f, // Druid
- 65.631440f // Demon Hunter
- };
+ // 1 1 k cx
+ // --- = --- + --- <=> x' = --------
+ // x' c x x + ck
+
+ // where:
+ // k is m_diminishing_k for that class
+ // c is capArray for that class
+ // x is chance before DR (diminishValue)
+ // x' is chance after DR (our result)
+
+ uint32 const classIdx = playerClass - 1;
+
+ float const k = m_diminishing_k[classIdx];
+ float const c = capArray[classIdx];
+
+ float result = c * diminishValue / (diminishValue + c * k);
+ result += nonDiminishValue;
+ return result;
+}
+
+float const parry_cap[MAX_CLASSES] =
+{
+ 65.631440f, // Warrior
+ 65.631440f, // Paladin
+ 145.560408f, // Hunter
+ 145.560408f, // Rogue
+ 0.0f, // Priest
+ 65.631440f, // DK
+ 145.560408f, // Shaman
+ 0.0f, // Mage
+ 0.0f, // Warlock
+ 90.6425f, // Monk
+ 0.0f, // Druid
+ 65.631440f // Demon Hunter
+};
+void Player::UpdateParryPercentage()
+{
// No parry
float value = 0.0f;
- uint32 pclass = getClass()-1;
+ uint32 pclass = getClass() - 1;
if (CanParry() && parry_cap[pclass] > 0.0f)
{
float nondiminishing = 5.0f;
@@ -621,8 +644,9 @@ void Player::UpdateParryPercentage()
float diminishing = GetRatingBonusValue(CR_PARRY);
// Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
nondiminishing += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
+
// apply diminishing formula to diminishing parry chance
- value = nondiminishing + diminishing * parry_cap[pclass] / (diminishing + parry_cap[pclass] * m_diminishing_k[pclass]);
+ value = CalculateDiminishingReturns(parry_cap, getClass(), nondiminishing, diminishing);
if (sWorld->getBoolConfig(CONFIG_STATS_LIMITS_ENABLE))
value = value > sWorld->getFloatConfig(CONFIG_STATS_LIMITS_PARRY) ? sWorld->getFloatConfig(CONFIG_STATS_LIMITS_PARRY) : value;
@@ -631,33 +655,33 @@ void Player::UpdateParryPercentage()
SetUpdateFieldStatValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::ParryPercentage), value);
}
-void Player::UpdateDodgePercentage()
+float const dodge_cap[MAX_CLASSES] =
{
- const float dodge_cap[MAX_CLASSES] =
- {
- 65.631440f, // Warrior
- 65.631440f, // Paladin
- 145.560408f, // Hunter
- 145.560408f, // Rogue
- 150.375940f, // Priest
- 65.631440f, // DK
- 145.560408f, // Shaman
- 150.375940f, // Mage
- 150.375940f, // Warlock
- 145.560408f, // Monk
- 116.890707f, // Druid
- 145.560408f // Demon Hunter
- };
+ 65.631440f, // Warrior
+ 65.631440f, // Paladin
+ 145.560408f, // Hunter
+ 145.560408f, // Rogue
+ 150.375940f, // Priest
+ 65.631440f, // DK
+ 145.560408f, // Shaman
+ 150.375940f, // Mage
+ 150.375940f, // Warlock
+ 145.560408f, // Monk
+ 116.890707f, // Druid
+ 145.560408f // Demon Hunter
+};
+void Player::UpdateDodgePercentage()
+{
float diminishing = 0.0f, nondiminishing = 0.0f;
GetDodgeFromAgility(diminishing, nondiminishing);
// Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
nondiminishing += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
// Dodge from rating
diminishing += GetRatingBonusValue(CR_DODGE);
+
// apply diminishing formula to diminishing dodge chance
- uint32 pclass = getClass()-1;
- float value = nondiminishing + (diminishing * dodge_cap[pclass] / (diminishing + dodge_cap[pclass] * m_diminishing_k[pclass]));
+ float value = CalculateDiminishingReturns(dodge_cap, getClass(), nondiminishing, diminishing);
if (sWorld->getBoolConfig(CONFIG_STATS_LIMITS_ENABLE))
value = value > sWorld->getFloatConfig(CONFIG_STATS_LIMITS_DODGE) ? sWorld->getFloatConfig(CONFIG_STATS_LIMITS_DODGE) : value;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 0f809261bc0..ad69398d494 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -285,12 +285,12 @@ SpellNonMeleeDamage::SpellNonMeleeDamage(Unit* _attacker, Unit* _target, uint32
}
Unit::Unit(bool isWorldObject) :
- WorldObject(isWorldObject), m_playerMovingMe(NULL), m_lastSanctuaryTime(0),
+ WorldObject(isWorldObject), m_playerMovingMe(nullptr), m_lastSanctuaryTime(0),
IsAIEnabled(false), NeedChangeAI(false), LastCharmerGUID(),
m_ControlledByPlayer(false), movespline(new Movement::MoveSpline()),
- i_AI(NULL), i_disabledAI(NULL), m_AutoRepeatFirstCast(false), m_procDeep(0),
+ i_AI(nullptr), i_disabledAI(nullptr), m_AutoRepeatFirstCast(false), m_procDeep(0),
m_removedAurasCount(0), i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_ThreatManager(this),
- m_vehicle(NULL), m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE),
+ m_vehicle(nullptr), m_vehicleKit(nullptr), m_unitTypeMask(UNIT_MASK_NONE),
m_HostileRefManager(this), _aiAnimKitId(0), _movementAnimKitId(0), _meleeAnimKitId(0),
_spellHistory(new SpellHistory(this))
{
@@ -389,10 +389,11 @@ Unit::Unit(bool isWorldObject) :
m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
- _lastLiquid = NULL;
+ _lastLiquid = nullptr;
_oldFactionId = 0;
_isWalkingBeforeCharm = false;
+ _instantCast = false;
}
////////////////////////////////////////////////////////////
@@ -1474,27 +1475,22 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
GetTypeId() != TYPEID_PLAYER && !ToCreature()->IsControlledByPlayer() && !victim->HasInArc(float(M_PI), this)
&& (victim->GetTypeId() == TYPEID_PLAYER || !victim->ToCreature()->isWorldBoss())&& !victim->IsVehicle())
{
- // -probability is between 0% and 40%
// 20% base chance
- float Probability = 20.0f;
+ float chance = 20.0f;
// there is a newbie protection, at level 10 just 7% base chance; assuming linear function
if (victim->getLevel() < 30)
- Probability = 0.65f * victim->GetLevelForTarget(this) + 0.5f;
-
- uint32 VictimDefense = victim->GetMaxSkillValueForLevel(this);
- uint32 AttackerMeleeSkill = GetMaxSkillValueForLevel();
-
- Probability *= AttackerMeleeSkill/(float)VictimDefense*0.16f;
+ chance = 0.65f * victim->GetLevelForTarget(this) + 0.5f;
- if (Probability < 0)
- Probability = 0;
+ uint32 const victimDefense = victim->GetMaxSkillValueForLevel(this);
+ uint32 const attackerMeleeSkill = GetMaxSkillValueForLevel();
- if (Probability > 40.0f)
- Probability = 40.0f;
+ chance *= attackerMeleeSkill / float(victimDefense) * 0.16f;
- if (roll_chance_f(Probability))
- CastSpell(victim, 1604, true);
+ // -probability is between 0% and 40%
+ RoundToInterval(chance, 0.0f, 40.0f);
+ if (roll_chance_f(chance))
+ CastSpell(victim, 1604 /*SPELL_DAZED*/, true);
}
if (GetTypeId() == TYPEID_PLAYER)
@@ -1676,31 +1672,30 @@ uint32 Unit::CalcSpellResistedDamage(Unit* attacker, Unit* victim, uint32 damage
return 0;
}
- float averageResist = GetEffectiveResistChance(this, schoolMask, victim, spellInfo);
-
- float discreteResistProbability[11];
- for (uint32 i = 0; i < 11; ++i)
- {
- discreteResistProbability[i] = 0.5f - 2.5f * std::fabs(0.1f * i - averageResist);
- if (discreteResistProbability[i] < 0.0f)
- discreteResistProbability[i] = 0.0f;
- }
+ float const averageResist = CalculateAverageResistReduction(schoolMask, victim, spellInfo);
+ float discreteResistProbability[11] = { };
if (averageResist <= 0.1f)
{
discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
discreteResistProbability[1] = 5.0f * averageResist;
discreteResistProbability[2] = 2.5f * averageResist;
}
+ else
+ {
+ for (uint32 i = 0; i < 11; ++i)
+ discreteResistProbability[i] = std::max(0.5f - 2.5f * std::fabs(0.1f * i - averageResist), 0.0f);
+ }
- uint32 resistance = 0;
- float r = float(rand_norm());
- float probabilitySum = discreteResistProbability[0];
+ float roll = float(rand_norm());
+ float probabilitySum = 0.0f;
- while (r >= probabilitySum && resistance < 10)
- probabilitySum += discreteResistProbability[++resistance];
+ uint32 resistance = 0;
+ for (; resistance < 11; ++resistance)
+ if (roll < (probabilitySum += discreteResistProbability[resistance]))
+ break;
- float damageResisted = float(damage * resistance / 10);
+ float damageResisted = damage * resistance / 10.f;
if (damageResisted > 0.0f) // if any damage was resisted
{
int32 ignoredResistance = 0;
@@ -1714,31 +1709,31 @@ uint32 Unit::CalcSpellResistedDamage(Unit* attacker, Unit* victim, uint32 damage
if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC))
{
uint32 damageAfterArmor = CalcArmorReducedDamage(attacker, victim, damage, spellInfo, BASE_ATTACK);
- uint32 armorReduction = damage - damageAfterArmor;
- if (armorReduction < damageResisted) // pick the lower one, the weakest resistance counts
- damageResisted = armorReduction;
+ float armorReduction = damage - damageAfterArmor;
+
+ // pick the lower one, the weakest resistance counts
+ damageResisted = std::min(damageResisted, armorReduction);
}
}
- return damageResisted;
+ damageResisted = std::max(damageResisted, 0.f);
+ return uint32(damageResisted);
}
-float Unit::GetEffectiveResistChance(Unit const* owner, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo)
+float Unit::CalculateAverageResistReduction(SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo) const
{
float victimResistance = float(victim->GetResistance(schoolMask));
- if (owner)
+
+ // pets inherit 100% of masters penetration
+ // excluding traps
+ Player const* player = GetSpellModOwner();
+ if (player && GetEntry() != WORLD_TRIGGER)
{
- // pets inherit 100% of masters penetration
- // excluding traps
- Player const* player = owner->GetSpellModOwner();
- if (player && owner->GetEntry() != WORLD_TRIGGER)
- {
- victimResistance += float(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
- victimResistance -= float(player->GetSpellPenetrationItemMod());
- }
- else
- victimResistance += float(owner->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
+ victimResistance += float(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
+ victimResistance -= float(player->GetSpellPenetrationItemMod());
}
+ else
+ victimResistance += float(GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
// holy resistance exists in pve and comes from level difference, ignore template values
if (schoolMask & SPELL_SCHOOL_MASK_HOLY)
@@ -1749,8 +1744,10 @@ float Unit::GetEffectiveResistChance(Unit const* owner, SpellSchoolMask schoolMa
victimResistance = 0.0f;
victimResistance = std::max(victimResistance, 0.0f);
- if (owner)
- victimResistance += std::max((float(victim->GetLevelForTarget(owner)) - float(owner->GetLevelForTarget(victim))) * 5.0f, 0.0f);
+
+ // level-based resistance does not apply to binary spells, and cannot be overcome by spell penetration
+ if (!spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))
+ victimResistance += std::max((float(victim->GetLevelForTarget(this)) - float(GetLevelForTarget(victim))) * 5.0f, 0.0f);
static uint32 const bossLevel = 83;
static float const bossResistanceConstant = 510.0f;
@@ -2030,7 +2027,7 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr
return; // ignore ranged case
if (GetTypeId() == TYPEID_UNIT && !HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
- SetFacingToObject(victim); // update client side facing to face the target (prevents visual glitches when casting untargeted spells)
+ SetFacingToObject(victim, false); // update client side facing to face the target (prevents visual glitches when casting untargeted spells)
// melee attack spell cast at main hand attack only - no normal melee dmg dealt
if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL] && !extra)
@@ -2111,7 +2108,7 @@ void Unit::FakeAttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BA
return; // ignore ranged case
if (GetTypeId() == TYPEID_UNIT && !HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
- SetFacingToObject(victim); // update client side facing to face the target (prevents visual glitches when casting untargeted spells)
+ SetFacingToObject(victim, false); // update client side facing to face the target (prevents visual glitches when casting untargeted spells)
CalcDamageInfo damageInfo;
damageInfo.attacker = this;
@@ -2534,7 +2531,6 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
return SPELL_MISS_NONE;
}
-/// @todo need use unit spell resistances in calculations
SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const
{
// Can`t miss on dead target (on skinning for example)
@@ -2590,23 +2586,21 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
int32 tmp = 10000 - HitChance;
int32 rand = irand(0, 9999);
- if (rand < tmp)
+ if (tmp > 0 && rand < tmp)
return SPELL_MISS_MISS;
// Chance resist mechanic (select max value from every mechanic spell effect)
int32 resist_chance = victim->GetMechanicResistChance(spellInfo) * 100;
- tmp += resist_chance;
// Roll chance
- if (rand < tmp)
+ if (resist_chance > 0 && rand < (tmp += resist_chance))
return SPELL_MISS_RESIST;
// cast by caster in front of victim
if (!victim->HasUnitState(UNIT_STATE_CONTROLLED) && (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)))
{
int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
- tmp += deflect_chance;
- if (rand < tmp)
+ if (deflect_chance > 0 && rand < (tmp += deflect_chance))
return SPELL_MISS_DEFLECT;
}
@@ -2623,18 +2617,6 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
// Resist
SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect /*= false*/)
{
- if (spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
- return SPELL_MISS_NONE;
-
- // Check for immune
- if (victim->IsImmunedToSpell(spellInfo, this))
- return SPELL_MISS_IMMUNE;
-
- // Damage immunity is only checked if the spell has damage effects, this immunity must not prevent aura apply
- // returns SPELL_MISS_IMMUNE in that case, for other spells, the SMSG_SPELL_GO must show hit
- if (spellInfo->HasOnlyDamageEffects() && victim->IsImmunedToDamage(spellInfo))
- return SPELL_MISS_IMMUNE;
-
// All positive spells can`t miss
/// @todo client not show miss log for this spells - so need find info for this in dbc and use it!
if (spellInfo->IsPositive() && !IsHostileTo(victim)) // prevent from affecting enemy by "positive" spell
@@ -2657,6 +2639,18 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, boo
return SPELL_MISS_REFLECT;
}
+ if (spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
+ return SPELL_MISS_NONE;
+
+ // Check for immune
+ if (victim->IsImmunedToSpell(spellInfo, this))
+ return SPELL_MISS_IMMUNE;
+
+ // Damage immunity is only checked if the spell has damage effects, this immunity must not prevent aura apply
+ // returns SPELL_MISS_IMMUNE in that case, for other spells, the SMSG_SPELL_GO must show hit
+ if (spellInfo->HasOnlyDamageEffects() && victim->IsImmunedToDamage(spellInfo))
+ return SPELL_MISS_IMMUNE;
+
switch (spellInfo->DmgClass)
{
case SPELL_DAMAGE_CLASS_RANGED:
@@ -2748,7 +2742,7 @@ float Unit::GetUnitParryChance(WeaponAttackType attType, Unit const* victim) con
float Unit::GetUnitMissChance(WeaponAttackType attType) const
{
- float miss_chance = 5.00f;
+ float miss_chance = 5.0f;
if (attType == RANGED_ATTACK)
miss_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
@@ -4671,7 +4665,7 @@ int32 Unit::GetTotalAuraModifier(AuraType auratype, std::function<bool(AuraEffec
{
// Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
// If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
- if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), aurEff->GetAmount(), sameEffectSpellGroup))
+ if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), static_cast<uint32>(auratype), aurEff->GetAmount(), sameEffectSpellGroup))
modifier += aurEff->GetAmount();
}
}
@@ -4698,7 +4692,7 @@ float Unit::GetTotalAuraMultiplier(AuraType auratype, std::function<bool(AuraEff
{
// Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
// If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
- if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), aurEff->GetAmount(), sameEffectSpellGroup))
+ if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), static_cast<uint32>(auratype), aurEff->GetAmount(), sameEffectSpellGroup))
AddPct(multiplier, aurEff->GetAmount());
}
}
@@ -5435,15 +5429,15 @@ void Unit::UpdateDisplayPower()
FactionTemplateEntry const* Unit::GetFactionTemplateEntry() const
{
- FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(getFaction());
+ FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(GetFaction());
if (!entry)
{
if (Player const* player = ToPlayer())
- TC_LOG_ERROR("entities.unit", "Player %s has invalid faction (faction template id) #%u", player->GetName().c_str(), getFaction());
+ TC_LOG_ERROR("entities.unit", "Player %s has invalid faction (faction template id) #%u", player->GetName().c_str(), GetFaction());
else if (Creature const* creature = ToCreature())
- TC_LOG_ERROR("entities.unit", "Creature (template id: %u) has invalid faction (faction template id) #%u", creature->GetCreatureTemplate()->Entry, getFaction());
+ TC_LOG_ERROR("entities.unit", "Creature (template id: %u) has invalid faction (faction template id) #%u", creature->GetCreatureTemplate()->Entry, GetFaction());
else
- TC_LOG_ERROR("entities.unit", "Unit (name=%s, type=%u) has invalid faction (faction template id) #%u", GetName().c_str(), uint32(GetTypeId()), getFaction());
+ TC_LOG_ERROR("entities.unit", "Unit (name=%s, type=%u) has invalid faction (faction template id) #%u", GetName().c_str(), uint32(GetTypeId()), GetFaction());
ABORT();
}
@@ -8658,7 +8652,7 @@ void Unit::SetSpeedRate(UnitMoveType mtype, float rate)
m_speed_rate[mtype] = rate;
- propagateSpeedChange();
+ PropagateSpeedChange();
// Spline packets are for creatures and move_update are for players
static OpcodeServer const moveTypeToOpcode[MAX_MOVE_TYPE][3] =
@@ -8845,7 +8839,8 @@ void Unit::TauntApply(Unit* taunter)
if (target && target == taunter)
return;
- SetInFront(taunter);
+ if (!IsFocusing(nullptr, true))
+ SetInFront(taunter);
if (creature->IsAIEnabled)
creature->AI()->AttackStart(taunter);
@@ -8884,7 +8879,8 @@ void Unit::TauntFadeOut(Unit* taunter)
if (target && target != taunter)
{
- SetInFront(target);
+ if (!IsFocusing(nullptr, true))
+ SetInFront(target);
if (creature->IsAIEnabled)
creature->AI()->AttackStart(target);
}
@@ -8966,7 +8962,7 @@ Unit* Creature::SelectVictim()
if (target && _IsTargetAcceptable(target) && CanCreatureAttack(target))
{
- if (!IsFocusing())
+ if (!IsFocusing(nullptr, true))
SetInFront(target);
return target;
}
@@ -9162,7 +9158,7 @@ void Unit::ModSpellCastTime(SpellInfo const* spellInfo, int32 & castTime, Spell*
if (!(spellInfo->HasAttribute(SPELL_ATTR0_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR0_TRADESPELL) || spellInfo->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS)) &&
((GetTypeId() == TYPEID_PLAYER && spellInfo->SpellFamilyName) || GetTypeId() == TYPEID_UNIT))
- castTime = int32(float(castTime) * m_unitData->ModCastingSpeed);
+ castTime = CanInstantCast() ? 0 : int32(float(castTime) * m_unitData->ModCastingSpeed);
else if (spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) && !spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG))
castTime = int32(float(castTime) * m_modAttackSpeedPct[RANGED_ATTACK]);
else if (IsPartOfSkillLine(SKILL_COOKING, spellInfo->Id) && HasAura(67556)) // cooking with Chef Hat.
@@ -9215,11 +9211,11 @@ void Unit::IncrDiminishing(SpellInfo const* auraSpellInfo)
++diminish.hitCount;
}
-float Unit::ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, int32& duration, Unit* caster, DiminishingLevels previousLevel)
+bool Unit::ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, int32& duration, Unit* caster, DiminishingLevels previousLevel) const
{
DiminishingGroup const group = auraSpellInfo->GetDiminishingReturnsGroupForSpell();
if (duration == -1 || group == DIMINISHING_NONE)
- return 1.0f;
+ return true;
int32 const limitDuration = auraSpellInfo->GetDiminishingReturnsLimitDuration();
@@ -9239,7 +9235,6 @@ float Unit::ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, int32& du
}
float mod = 1.0f;
-
switch (group)
{
case DIMINISHING_TAUNT:
@@ -9296,7 +9291,7 @@ float Unit::ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, int32& du
}
duration = int32(duration * mod);
- return mod;
+ return (duration != 0);
}
void Unit::ApplyDiminishingAura(DiminishingGroup group, bool apply)
@@ -9587,7 +9582,13 @@ void Unit::UpdateDamageDoneMods(WeaponAttackType attackType)
break;
}
- float amount = GetTotalAuraModifier(SPELL_AURA_MOD_DAMAGE_DONE, std::bind(&Unit::CheckAttackFitToAuraRequirement, this, attackType, std::placeholders::_1));
+ float amount = GetTotalAuraModifier(SPELL_AURA_MOD_DAMAGE_DONE, [&](AuraEffect const* aurEff) -> bool
+ {
+ if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
+ return false;
+
+ return CheckAttackFitToAuraRequirement(attackType, aurEff);
+ });
SetStatFlatModifier(unitMod, TOTAL_VALUE, amount);
}
@@ -10661,9 +10662,9 @@ void Unit::SendPetAIReaction(ObjectGuid guid)
owner->ToPlayer()->SendDirectMessage(packet.Write());
}
-void Unit::propagateSpeedChange()
+void Unit::PropagateSpeedChange()
{
- GetMotionMaster()->propagateSpeedChange();
+ GetMotionMaster()->PropagateSpeedChange();
}
///----------End of Pet responses methods----------
@@ -11161,26 +11162,6 @@ void Unit::SetContestedPvP(Player* attackedPlayer)
}
}
-void Unit::AddPetAura(PetAura const* petSpell)
-{
- if (GetTypeId() != TYPEID_PLAYER)
- return;
-
- m_petAuras.insert(petSpell);
- if (Pet* pet = ToPlayer()->GetPet())
- pet->CastPetAura(petSpell);
-}
-
-void Unit::RemovePetAura(PetAura const* petSpell)
-{
- if (GetTypeId() != TYPEID_PLAYER)
- return;
-
- m_petAuras.erase(petSpell);
- if (Pet* pet = ToPlayer()->GetPet())
- pet->RemoveAurasDueToSpell(petSpell->GetAura(pet->GetEntry()));
-}
-
Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget, uint32 spell_id)
{
if (GetTypeId() != TYPEID_PLAYER)
@@ -11224,7 +11205,7 @@ Pet* Unit::CreateTamedPetFrom(uint32 creatureEntry, uint32 spell_id)
bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)
{
pet->SetCreatorGUID(GetGUID());
- pet->setFaction(getFaction());
+ pet->SetFaction(GetFaction());
pet->SetCreatedBySpell(spell_id);
if (GetTypeId() == TYPEID_PLAYER)
@@ -11520,7 +11501,7 @@ void Unit::Kill(Unit* victim, bool durabilityLoss)
{
// the reset time is set but not added to the scheduler
// until the players leave the instance
- time_t resettime = creature->GetRespawnTimeEx() + 2 * HOUR;
+ time_t resettime = GameTime::GetGameTime() + 2 * HOUR;
if (InstanceSave* save = sInstanceSaveMgr->GetInstanceSave(creature->GetInstanceId()))
if (save->GetResetTime() < resettime)
save->SetResetTime(resettime);
@@ -11880,8 +11861,8 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
if (aurApp && aurApp->GetRemoveMode())
return false;
- _oldFactionId = getFaction();
- setFaction(charmer->getFaction());
+ _oldFactionId = GetFaction();
+ SetFaction(charmer->GetFaction());
// Set charmed
charmer->SetCharm(this, true);
@@ -11997,7 +11978,7 @@ void Unit::RemoveCharmedBy(Unit* charmer)
if (_oldFactionId)
{
- setFaction(_oldFactionId);
+ SetFaction(_oldFactionId);
_oldFactionId = 0;
}
else
@@ -12089,13 +12070,13 @@ void Unit::RestoreFaction()
{
if (Unit* owner = GetOwner())
{
- setFaction(owner->getFaction());
+ SetFaction(owner->GetFaction());
return;
}
}
if (CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate()) // normal creature
- setFaction(cinfo->faction);
+ SetFaction(cinfo->faction);
}
}
@@ -12190,7 +12171,7 @@ bool Unit::IsInPartyWith(Unit const* unit) const
(u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_UNIT && u2->ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT))
return true;
- return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->getFaction() == u2->getFaction();
+ return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->GetFaction() == u2->GetFaction();
}
bool Unit::IsInRaidWith(Unit const* unit) const
@@ -12209,7 +12190,7 @@ bool Unit::IsInRaidWith(Unit const* unit) const
(u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_UNIT && u2->ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT))
return true;
- return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->getFaction() == u2->getFaction();
+ return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->GetFaction() == u2->GetFaction();
}
void Unit::GetPartyMembers(std::list<Unit*> &TagUnitMap)
@@ -12426,25 +12407,23 @@ void Unit::ApplyResilience(Unit const* victim, int32* damage) const
// Melee based spells can be miss, parry or dodge on this step
// Crit or block - determined on damage calculation phase! (and can be both in some time)
-float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, uint32 spellId) const
+float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, uint32 spellId) const
{
//calculate miss chance
float missChance = victim->GetUnitMissChance(attType);
+ // melee attacks while dual wielding have +19% chance to miss
if (!spellId && haveOffhandWeapon() && !IsInFeralForm())
- missChance += 19;
-
- // Calculate hit chance
- float hitChance = 100.0f;
+ missChance += 19.0f;
// Spellmod from SPELLMOD_RESIST_MISS_CHANCE
+ float resistMissChance = 100.0f;
if (spellId)
{
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, hitChance);
+ modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, resistMissChance);
}
-
- missChance += hitChance - 100.0f;
+ missChance -= resistMissChance - 100.0f;
if (attType == RANGED_ATTACK)
missChance -= m_modRangedHitChance;
@@ -12452,10 +12431,7 @@ float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, u
missChance -= m_modMeleeHitChance;
// Limit miss chance from 0 to 60%
- if (missChance < 0.0f)
- return 0.0f;
- if (missChance > 77.0f)
- return 77.0f;
+ RoundToInterval(missChance, 0.f, 60.f);
return missChance;
}
@@ -13562,7 +13538,7 @@ void Unit::SendClearTarget()
int32 Unit::GetResistance(SpellSchoolMask mask) const
{
Optional<int32> resist;
- for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
+ for (int32 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
{
int32 schoolResistance = GetResistance(SpellSchools(i)) + GetBonusResistanceMod(SpellSchools(i));
if (mask & (1 << i) && (!resist || *resist > schoolResistance))
@@ -13651,7 +13627,8 @@ void Unit::SetInFront(WorldObject const* target)
void Unit::SetFacingTo(float ori, bool force)
{
- if (!force && !IsStopped())
+ // do not face when already moving
+ if (!force && (!IsStopped() || !movespline->Finalized()))
return;
Movement::MoveSplineInit init(this);
@@ -13665,7 +13642,7 @@ void Unit::SetFacingTo(float ori, bool force)
void Unit::SetFacingToObject(WorldObject const* object, bool force)
{
// do not face when already moving
- if (!force && !IsStopped())
+ if (!force && (!IsStopped() || !movespline->Finalized()))
return;
/// @todo figure out under what conditions creature will move towards object instead of facing it where it currently is.
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 7db8583f69f..48ab77e3856 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -200,7 +200,6 @@ class Item;
class Minion;
class MotionMaster;
class Pet;
-class PetAura;
class Spell;
class SpellCastTargets;
class SpellEffectInfo;
@@ -948,7 +947,7 @@ class TC_GAME_API Unit : public WorldObject
DiminishingLevels GetDiminishing(DiminishingGroup group);
void IncrDiminishing(SpellInfo const* auraSpellInfo);
- float ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, int32& duration, Unit* caster, DiminishingLevels previousLevel);
+ bool ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, int32& duration, Unit* caster, DiminishingLevels previousLevel) const;
void ApplyDiminishingAura(DiminishingGroup group, bool apply);
void ClearDiminishings();
@@ -1042,7 +1041,7 @@ class TC_GAME_API Unit : public WorldObject
int32 GetResistance(SpellSchoolMask mask) const;
void SetResistance(SpellSchools school, int32 val) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::Resistances, school), val); }
void SetBonusResistanceMod(SpellSchools school, int32 val) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::BonusResistanceMods, school), val); }
- float GetEffectiveResistChance(Unit const* owner, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo = nullptr);
+ float CalculateAverageResistReduction(SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo = nullptr) const;
uint64 GetHealth() const { return m_unitData->Health; }
uint64 GetMaxHealth() const { return m_unitData->MaxHealth; }
@@ -1119,8 +1118,8 @@ class TC_GAME_API Unit : public WorldObject
void SetSheath(SheathState sheathed) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::SheatheState), sheathed); }
// faction template id
- uint32 getFaction() const { return m_unitData->FactionTemplate; }
- void setFaction(uint32 faction) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::FactionTemplate), faction); }
+ uint32 GetFaction() const { return m_unitData->FactionTemplate; }
+ void SetFaction(uint32 faction) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::FactionTemplate), faction); }
FactionTemplateEntry const* GetFactionTemplateEntry() const;
ReputationRank GetReactionTo(Unit const* target) const;
@@ -1383,8 +1382,8 @@ class TC_GAME_API Unit : public WorldObject
void UpdateMovementForcesModMagnitude();
void SetInFront(WorldObject const* target);
- void SetFacingTo(float ori, bool force = false);
- void SetFacingToObject(WorldObject const* object, bool force = false);
+ void SetFacingTo(float const ori, bool force = true);
+ void SetFacingToObject(WorldObject const* object, bool force = true);
void SendChangeCurrentVictimOpcode(HostileReference* pHostileReference);
void SendClearThreatListOpcode();
@@ -1659,8 +1658,8 @@ class TC_GAME_API Unit : public WorldObject
virtual SpellInfo const* GetCastSpellInfo(SpellInfo const* spellInfo) const;
uint32 GetCastSpellXSpellVisualId(SpellInfo const* spellInfo) const;
- // Check if our current channel spell has attribute SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING
- bool IsMovementPreventedByCasting() const;
+ virtual bool IsFocusing(Spell const* /*focusSpell*/ = nullptr, bool /*withDelay*/ = false) { return false; }
+ virtual bool IsMovementPreventedByCasting() const;
SpellHistory* GetSpellHistory() { return _spellHistory; }
SpellHistory const* GetSpellHistory() const { return _spellHistory; }
@@ -1915,7 +1914,7 @@ class TC_GAME_API Unit : public WorldObject
void SendPetAIReaction(ObjectGuid guid);
///----------End of Pet responses methods----------
- void propagateSpeedChange();
+ void PropagateSpeedChange();
// reactive attacks
void ClearAllReactives();
@@ -1929,12 +1928,6 @@ class TC_GAME_API Unit : public WorldObject
bool CanProc() const { return !m_procDeep; }
void SetCantProc(bool apply);
- // pet auras
- typedef std::set<PetAura const*> PetAuraSet;
- PetAuraSet m_petAuras;
- void AddPetAura(PetAura const* petSpell);
- void RemovePetAura(PetAura const* petSpell);
-
uint32 GetModelForForm(ShapeshiftForm form, uint32 spellId) const;
// Redirect Threat
@@ -1997,6 +1990,9 @@ class TC_GAME_API Unit : public WorldObject
ObjectGuid GetTarget() const { return m_unitData->Target; }
virtual void SetTarget(ObjectGuid const& /*guid*/) = 0;
+ void SetInstantCast(bool set) { _instantCast = set; }
+ bool CanInstantCast() const { return _instantCast; }
+
// Movement info
Movement::MoveSpline * movespline;
@@ -2149,6 +2145,7 @@ class TC_GAME_API Unit : public WorldObject
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
+ bool _instantCast;
uint32 _oldFactionId; ///< faction before charm
bool _isWalkingBeforeCharm; ///< Are we walking before we were charmed?
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 4ab04447914..f519c69948f 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -4529,8 +4529,6 @@ void ObjectMgr::LoadQuests()
qinfo->GetQuestId(), qinfo->_nextQuestInChain, qinfo->_nextQuestInChain);
qinfo->_nextQuestInChain = 0;
}
- else
- qNextItr->second->PrevChainQuests.push_back(qinfo->GetQuestId());
}
for (uint8 j = 0; j < QUEST_REWARD_CURRENCY_COUNT; ++j)
@@ -4617,9 +4615,9 @@ void ObjectMgr::LoadQuests()
if (qinfo->_nextQuestID)
{
- auto qNextItr = _questTemplates.find(qinfo->GetNextQuestId());
+ auto qNextItr = _questTemplates.find(qinfo->_nextQuestID);
if (qNextItr == _questTemplates.end())
- TC_LOG_ERROR("sql.sql", "Quest %d has NextQuestId %u, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId());
+ TC_LOG_ERROR("sql.sql", "Quest %d has NextQuestId %u, but no such quest", qinfo->GetQuestId(), qinfo->_nextQuestID);
else
qNextItr->second->DependentPreviousQuests.push_back(qinfo->GetQuestId());
}
@@ -4628,6 +4626,27 @@ void ObjectMgr::LoadQuests()
_exclusiveQuestGroups.insert(std::pair<int32, uint32>(qinfo->_exclusiveGroup, qinfo->GetQuestId()));
if (qinfo->_limitTime)
qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED);
+
+ // Special flag to determine if quest is completed from the start, used to determine if we can fail timed quest if it is completed
+ if (!qinfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_CAST | QUEST_SPECIAL_FLAGS_SPEAKTO | QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT))
+ {
+ bool addFlag = true;
+ if (qinfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_DELIVER))
+ {
+ for (QuestObjective const& obj : qinfo->GetObjectives())
+ {
+ if (obj.Type == QUEST_OBJECTIVE_ITEM)
+ if (static_cast<uint32>(obj.ObjectID) != qinfo->GetSrcItemId() || static_cast<uint32>(obj.Amount) > qinfo->GetSrcItemCount())
+ {
+ addFlag = false;
+ break;
+ }
+ }
+ }
+
+ if (addFlag)
+ qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_COMPLETED_AT_START);
+ }
}
// check QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE
diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp
index e4ccc62f5dc..95454d49f90 100644
--- a/src/server/game/Handlers/AuctionHouseHandler.cpp
+++ b/src/server/game/Handlers/AuctionHouseHandler.cpp
@@ -52,7 +52,7 @@ void WorldSession::HandleAuctionBrowseQuery(WorldPackets::AuctionHouse::AuctionB
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
- AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction());
TC_LOG_DEBUG("auctionHouse", "Auctionhouse search (%s), searchedname: %s, levelmin: %u, levelmax: %u, filters: %u",
browseQuery.Auctioneer.ToString().c_str(), browseQuery.Name.c_str(), browseQuery.MinLevel, browseQuery.MaxLevel, AsUnderlyingType(browseQuery.Filters));
@@ -115,7 +115,7 @@ void WorldSession::HandleAuctionCancelCommoditiesPurchase(WorldPackets::AuctionH
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
- AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction());
auctionHouse->CancelCommodityQuote(_player->GetGUID());
}
@@ -136,7 +136,7 @@ void WorldSession::HandleAuctionConfirmCommoditiesPurchase(WorldPackets::Auction
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
- AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction());
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
if (auctionHouse->BuyCommodity(trans, _player, confirmCommoditiesPurchase.ItemID, confirmCommoditiesPurchase.Quantity, throttle.DelayUntilNext))
@@ -190,7 +190,7 @@ void WorldSession::HandleAuctionListBidderItems(WorldPackets::AuctionHouse::Auct
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
- AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction());
WorldPackets::AuctionHouse::AuctionListBidderItemsResult result;
@@ -218,7 +218,7 @@ void WorldSession::HandleAuctionListBucketsByBucketKeys(WorldPackets::AuctionHou
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
- AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction());
WorldPackets::AuctionHouse::AuctionListBucketsResult listBucketsResult;
@@ -248,7 +248,7 @@ void WorldSession::HandleAuctionListItemsByBucketKey(WorldPackets::AuctionHouse:
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
- AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction());
WorldPackets::AuctionHouse::AuctionListItemsResult listItemsResult;
listItemsResult.DesiredDelay = uint32(throttle.DelayUntilNext.count());
@@ -279,7 +279,7 @@ void WorldSession::HandleAuctionListItemsByItemID(WorldPackets::AuctionHouse::Au
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
- AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction());
WorldPackets::AuctionHouse::AuctionListItemsResult listItemsResult;
listItemsResult.DesiredDelay = uint32(throttle.DelayUntilNext.count());
@@ -311,7 +311,7 @@ void WorldSession::HandleAuctionListOwnerItems(WorldPackets::AuctionHouse::Aucti
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
- AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction());
WorldPackets::AuctionHouse::AuctionListOwnerItemsResult result;
@@ -345,7 +345,7 @@ void WorldSession::HandleAuctionPlaceBid(WorldPackets::AuctionHouse::AuctionPlac
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
- AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction());
AuctionPosting* auction = auctionHouse->GetAuction(placeBid.AuctionID);
if (!auction || auction->IsCommodity())
@@ -467,7 +467,7 @@ void WorldSession::HandleAuctionRemoveItem(WorldPackets::AuctionHouse::AuctionRe
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
- AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction());
AuctionPosting* auction = auctionHouse->GetAuction(removeItem.AuctionID);
Player* player = GetPlayer();
@@ -529,7 +529,7 @@ void WorldSession::HandleAuctionReplicateItems(WorldPackets::AuctionHouse::Aucti
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
- AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction());
WorldPackets::AuctionHouse::AuctionReplicateResponse response;
@@ -569,7 +569,7 @@ void WorldSession::HandleAuctionSellCommodity(WorldPackets::AuctionHouse::Auctio
}
uint32 houseId = 0;
- AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->getFaction(), &houseId);
+ AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->GetFaction(), &houseId);
if (!auctionHouseEntry)
{
TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (%s) has wrong faction.", sellCommodity.Auctioneer.ToString().c_str());
@@ -645,7 +645,7 @@ void WorldSession::HandleAuctionSellCommodity(WorldPackets::AuctionHouse::Auctio
}
Seconds auctionTime = Seconds(int64(std::chrono::duration_cast<Seconds>(Minutes(sellCommodity.RunTime)).count() * double(sWorld->getRate(RATE_AUCTION_TIME))));
- AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction());
uint64 deposit = AuctionHouseMgr::GetCommodityAuctionDeposit(items2.begin()->second.first->GetTemplate(), Minutes(sellCommodity.RunTime), totalCount);
if (!_player->HasEnoughMoney(deposit))
@@ -793,7 +793,7 @@ void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSell
}
uint32 houseId = 0;
- AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->getFaction(), &houseId);
+ AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->GetFaction(), &houseId);
if (!auctionHouseEntry)
{
TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (%s) has wrong faction.", sellItem.Auctioneer.ToString().c_str());
@@ -837,7 +837,7 @@ void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSell
}
Seconds auctionTime = Seconds(int64(std::chrono::duration_cast<Seconds>(Minutes(sellItem.RunTime)).count() * double(sWorld->getRate(RATE_AUCTION_TIME))));
- AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction());
uint64 deposit = AuctionHouseMgr::GetItemAuctionDeposit(_player, item, Minutes(sellItem.RunTime));
if (!_player->HasEnoughMoney(deposit))
@@ -947,7 +947,7 @@ void WorldSession::HandleAuctionStartCommoditiesPurchase(WorldPackets::AuctionHo
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
- AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
+ AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->GetFaction());
WorldPackets::AuctionHouse::AuctionCommodityQuote auctionCommodityQuote;
@@ -972,7 +972,7 @@ void WorldSession::SendAuctionHello(ObjectGuid guid, Creature* unit)
return;
}
- AuctionHouseEntry const* ahEntry = AuctionHouseMgr::GetAuctionHouseEntry(unit->getFaction(), nullptr);
+ AuctionHouseEntry const* ahEntry = AuctionHouseMgr::GetAuctionHouseEntry(unit->GetFaction(), nullptr);
if (!ahEntry)
return;
diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp
index 7335b5f3676..68911435766 100644
--- a/src/server/game/Handlers/LootHandler.cpp
+++ b/src/server/game/Handlers/LootHandler.cpp
@@ -28,6 +28,7 @@
#include "GuildMgr.h"
#include "Item.h"
#include "Log.h"
+#include "LootItemStorage.h"
#include "LootMgr.h"
#include "LootPackets.h"
#include "Object.h"
@@ -255,7 +256,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPackets::Loot::LootMoney& /*packet
// Delete the money loot record from the DB
if (!loot->containerID.IsEmpty())
- loot->DeleteLootMoneyFromContainerItemDB();
+ sLootItemStorage->RemoveStoredMoneyForContainer(loot->containerID.GetCounter());
// Delete container if empty
if (loot->isLooted() && guid.IsItem())
diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp
index 08981180970..1cda9ba2f1c 100644
--- a/src/server/game/Handlers/NPCHandler.cpp
+++ b/src/server/game/Handlers/NPCHandler.cpp
@@ -159,7 +159,7 @@ void WorldSession::HandleGossipHelloOpcode(WorldPackets::NPC::Hello& packet)
}
// set faction visible if needed
- if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction()))
+ if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->GetFaction()))
_player->GetReputationMgr().SetVisible(factionTemplateEntry);
GetPlayer()->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK);
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 8dc2523afcc..73bc95f2caf 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -331,13 +331,15 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
{
if (unit_target)
{
- pet->SetInFront(unit_target);
+ if (!pet->IsFocusing())
+ pet->SetInFront(unit_target);
if (Player* player = unit_target->ToPlayer())
pet->SendUpdateToPlayer(player);
}
else if (Unit* unit_target2 = spell->m_targets.GetUnitTarget())
{
- pet->SetInFront(unit_target2);
+ if (!pet->IsFocusing())
+ pet->SetInFront(unit_target2);
if (Player* player = unit_target2->ToPlayer())
pet->SendUpdateToPlayer(player);
}
diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp
index b56e0ec130c..aeafff6d1cc 100644
--- a/src/server/game/Handlers/QuestHandler.cpp
+++ b/src/server/game/Handlers/QuestHandler.cpp
@@ -350,46 +350,41 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPackets::Quest::Quest
{
//For AutoSubmition was added plr case there as it almost same exclute AI script cases.
Creature* creatureQGiver = object->ToCreature();
- if (!creatureQGiver || !sScriptMgr->OnQuestReward(_player, creatureQGiver, quest, packet.ItemChoiceID))
+ // Send next quest
+ if (Quest const* nextQuest = _player->GetNextQuest(packet.QuestGiverGUID, quest))
{
- // Send next quest
- if (Quest const* nextQuest = _player->GetNextQuest(packet.QuestGiverGUID, quest))
+ // Only send the quest to the player if the conditions are met
+ if (_player->CanTakeQuest(nextQuest, false))
{
- // Only send the quest to the player if the conditions are met
- if (_player->CanTakeQuest(nextQuest, false))
- {
- if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true))
- _player->AddQuestAndCheckCompletion(nextQuest, object);
+ if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true))
+ _player->AddQuestAndCheckCompletion(nextQuest, object);
- _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, packet.QuestGiverGUID, true, false);
- }
+ _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, packet.QuestGiverGUID, true, false);
}
-
- if (creatureQGiver)
- creatureQGiver->GetAI()->sQuestReward(_player, quest, packet.ItemChoiceID);
}
+
+ if (creatureQGiver && !sScriptMgr->OnQuestReward(_player, creatureQGiver, quest, packet.ItemChoiceID))
+ creatureQGiver->GetAI()->sQuestReward(_player, quest, packet.ItemChoiceID);
break;
}
case TYPEID_GAMEOBJECT:
{
GameObject* questGiver = object->ToGameObject();
- if (!sScriptMgr->OnQuestReward(_player, questGiver, quest, packet.ItemChoiceID))
+ // Send next quest
+ if (Quest const* nextQuest = _player->GetNextQuest(packet.QuestGiverGUID, quest))
{
- // Send next quest
- if (Quest const* nextQuest = _player->GetNextQuest(packet.QuestGiverGUID, quest))
+ // Only send the quest to the player if the conditions are met
+ if (_player->CanTakeQuest(nextQuest, false))
{
- // Only send the quest to the player if the conditions are met
- if (_player->CanTakeQuest(nextQuest, false))
- {
- if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true))
- _player->AddQuestAndCheckCompletion(nextQuest, object);
+ if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true))
+ _player->AddQuestAndCheckCompletion(nextQuest, object);
- _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, packet.QuestGiverGUID, true, false);
- }
+ _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, packet.QuestGiverGUID, true, false);
}
+ }
+ if (!sScriptMgr->OnQuestReward(_player, questGiver, quest, packet.ItemChoiceID))
questGiver->AI()->QuestReward(_player, quest, packet.ItemChoiceID);
- }
break;
}
default:
@@ -590,7 +585,10 @@ void WorldSession::HandlePushQuestToParty(WorldPackets::Quest::PushQuestToParty&
Group* group = sender->GetGroup();
if (!group)
+ {
+ sender->SendPushToPartyResponse(sender, QUEST_PUSH_NOT_IN_PARTY);
return;
+ }
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
@@ -611,6 +609,12 @@ void WorldSession::HandlePushQuestToParty(WorldPackets::Quest::PushQuestToParty&
continue;
}
+ if (!receiver->SatisfyQuestDay(quest, false))
+ {
+ sender->SendPushToPartyResponse(receiver, QUEST_PUSH_DIFFERENT_SERVER_DAILY);
+ continue;
+ }
+
if (!receiver->CanTakeQuest(quest, false))
{
sender->SendPushToPartyResponse(receiver, QUEST_PUSH_INVALID);
diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp
index 903e4f084d6..fdeee7535a1 100644
--- a/src/server/game/Instances/InstanceSaveMgr.cpp
+++ b/src/server/game/Instances/InstanceSaveMgr.cpp
@@ -168,7 +168,7 @@ void InstanceSaveManager::RemoveInstanceSave(uint32 InstanceId)
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_INSTANCE_RESETTIME);
- stmt->setUInt32(0, uint32(resettime));
+ stmt->setUInt64(0, uint64(resettime));
stmt->setUInt32(1, InstanceId);
CharacterDatabase.Execute(stmt);
@@ -222,7 +222,7 @@ void InstanceSave::SaveToDB()
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_INSTANCE_SAVE);
stmt->setUInt32(0, m_instanceid);
stmt->setUInt16(1, GetMapId());
- stmt->setUInt32(2, uint32(GetResetTimeForDB()));
+ stmt->setUInt64(2, uint64(GetResetTimeForDB()));
stmt->setUInt8(3, uint8(GetDifficultyID()));
stmt->setUInt32(4, completedEncounters);
stmt->setString(5, data);
@@ -329,8 +329,7 @@ void InstanceSaveManager::LoadResetTimes()
typedef std::pair<ResetTimeMapDiffInstances::const_iterator, ResetTimeMapDiffInstances::const_iterator> ResetTimeMapDiffInstancesBounds;
ResetTimeMapDiffInstances mapDiffResetInstances;
- QueryResult result = CharacterDatabase.Query("SELECT id, map, difficulty, resettime FROM instance ORDER BY id ASC");
- if (result)
+ if (QueryResult result = CharacterDatabase.Query("SELECT id, map, difficulty, resettime FROM instance ORDER BY id ASC"))
{
do
{
@@ -346,7 +345,7 @@ void InstanceSaveManager::LoadResetTimes()
// Mark instance id as being used
sMapMgr->RegisterInstanceId(instanceId);
- if (time_t resettime = time_t(fields[3].GetUInt32()))
+ if (time_t resettime = time_t(fields[3].GetUInt64()))
{
uint32 mapid = fields[1].GetUInt16();
uint32 difficulty = fields[2].GetUInt8();
@@ -357,24 +356,6 @@ void InstanceSaveManager::LoadResetTimes()
}
while (result->NextRow());
- // update reset time for normal instances with the max creature respawn time + X hours
- if (PreparedQueryResult result2 = CharacterDatabase.Query(CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAX_CREATURE_RESPAWNS)))
- {
- do
- {
- Field* fields = result2->Fetch();
- uint32 instance = fields[1].GetUInt32();
- time_t resettime = time_t(fields[0].GetUInt32() + 2 * HOUR);
- InstResetTimeMapDiffType::iterator itr = instResetTime.find(instance);
- if (itr != instResetTime.end() && itr->second.second != resettime)
- {
- CharacterDatabase.DirectPExecute("UPDATE instance SET resettime = '" UI64FMTD "' WHERE id = '%u'", uint64(resettime), instance);
- itr->second.second = resettime;
- }
- }
- while (result2->NextRow());
- }
-
// schedule the reset times
for (InstResetTimeMapDiffType::iterator itr = instResetTime.begin(); itr != instResetTime.end(); ++itr)
if (itr->second.second > now)
@@ -383,28 +364,37 @@ void InstanceSaveManager::LoadResetTimes()
// load the global respawn times for raid/heroic instances
uint32 diff = sWorld->getIntConfig(CONFIG_INSTANCE_RESET_TIME_HOUR) * HOUR;
- result = CharacterDatabase.Query("SELECT mapid, difficulty, resettime FROM instance_reset");
- if (result)
+ if (QueryResult result = CharacterDatabase.Query("SELECT mapid, difficulty, resettime FROM instance_reset"))
{
do
{
Field* fields = result->Fetch();
uint32 mapid = fields[0].GetUInt16();
Difficulty difficulty = Difficulty(fields[1].GetUInt8());
- uint64 oldresettime = fields[2].GetUInt32();
+ uint64 oldresettime = fields[2].GetUInt64();
MapDifficultyEntry const* mapDiff = sDB2Manager.GetMapDifficultyData(mapid, difficulty);
if (!mapDiff)
{
TC_LOG_ERROR("misc", "InstanceSaveManager::LoadResetTimes: invalid mapid(%u)/difficulty(%u) pair in instance_reset!", mapid, uint32(difficulty));
- CharacterDatabase.DirectPExecute("DELETE FROM instance_reset WHERE mapid = '%u' AND difficulty = '%u'", mapid, uint32(difficulty));
+
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GLOBAL_INSTANCE_RESETTIME);
+ stmt->setUInt16(0, uint16(mapid));
+ stmt->setUInt8(1, uint8(difficulty));
+ CharacterDatabase.DirectExecute(stmt);
continue;
}
// update the reset time if the hour in the configs changes
uint64 newresettime = (oldresettime / DAY) * DAY + diff;
if (oldresettime != newresettime)
- CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '%u' WHERE mapid = '%u' AND difficulty = '%u'", uint32(newresettime), mapid, uint32(difficulty));
+ {
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GLOBAL_INSTANCE_RESETTIME);
+ stmt->setUInt64(0, uint64(newresettime));
+ stmt->setUInt16(1, uint16(mapid));
+ stmt->setUInt8(2, uint8(difficulty));
+ CharacterDatabase.DirectExecute(stmt);
+ }
InitializeResetTimeFor(mapid, difficulty, newresettime);
} while (result->NextRow());
@@ -433,7 +423,12 @@ void InstanceSaveManager::LoadResetTimes()
{
// initialize the reset time
t = today + period + diff;
- CharacterDatabase.DirectPExecute("INSERT INTO instance_reset VALUES ('%u', '%u', '%u')", mapid, uint32(difficulty), (uint32)t);
+
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GLOBAL_INSTANCE_RESETTIME);
+ stmt->setUInt16(0, uint16(mapid));
+ stmt->setUInt8(1, uint8(difficulty));
+ stmt->setUInt64(2, uint64(t));
+ CharacterDatabase.DirectExecute(stmt);
}
if (t < now)
@@ -442,7 +437,12 @@ void InstanceSaveManager::LoadResetTimes()
// calculate the next reset time
t = (t / DAY) * DAY;
t += ((today - t) / period + 1) * period + diff;
- CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '" UI64FMTD "' WHERE mapid = '%u' AND difficulty= '%u'", (uint64)t, mapid, uint32(difficulty));
+
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GLOBAL_INSTANCE_RESETTIME);
+ stmt->setUInt64(0, uint64(t));
+ stmt->setUInt16(1, uint16(mapid));
+ stmt->setUInt8(2, uint8(difficulty));
+ CharacterDatabase.DirectExecute(stmt);
}
InitializeResetTimeFor(mapid, difficulty, t);
@@ -702,7 +702,7 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b
// Update it in the DB
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GLOBAL_INSTANCE_RESETTIME);
- stmt->setUInt32(0, next_reset);
+ stmt->setUInt64(0, uint64(next_reset));
stmt->setUInt16(1, uint16(mapid));
stmt->setUInt8(2, uint8(difficulty));
diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp
index 88365d6641f..9e4dc90cab9 100644
--- a/src/server/game/Loot/Loot.cpp
+++ b/src/server/game/Loot/Loot.cpp
@@ -54,7 +54,6 @@ LootItem::LootItem(LootStoreItem const& li)
is_underthreshold = 0;
is_counted = 0;
rollWinnerGUID = ObjectGuid::Empty;
- canSave = true;
}
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
@@ -104,33 +103,6 @@ Loot::~Loot()
clear();
}
-void Loot::DeleteLootItemFromContainerItemDB(uint32 itemID)
-{
- // Deletes a single item associated with an openable item from the DB
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM);
- stmt->setUInt64(0, containerID.GetCounter());
- stmt->setUInt32(1, itemID);
- CharacterDatabase.Execute(stmt);
-
- // Mark the item looted to prevent resaving
- for (LootItemList::iterator _itr = items.begin(); _itr != items.end(); ++_itr)
- {
- if (_itr->itemid != itemID)
- continue;
-
- _itr->canSave = false;
- break;
- }
-}
-
-void Loot::DeleteLootMoneyFromContainerItemDB()
-{
- // Deletes money loot associated with an openable item from the DB
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
- stmt->setUInt64(0, containerID.GetCounter());
- CharacterDatabase.Execute(stmt);
-}
-
void Loot::clear()
{
for (NotNormalLootItemMap::const_iterator itr = PlayerQuestItems.begin(); itr != PlayerQuestItems.end(); ++itr)
diff --git a/src/server/game/Loot/Loot.h b/src/server/game/Loot/Loot.h
index 27f9c89f040..1aaed3f3cf7 100644
--- a/src/server/game/Loot/Loot.h
+++ b/src/server/game/Loot/Loot.h
@@ -148,7 +148,6 @@ struct TC_GAME_API LootItem
bool is_counted : 1;
bool needs_quest : 1; // quest drop
bool follow_loot_rules : 1;
- bool canSave;
// Constructor, copies most fields from LootStoreItem, generates random count and random suffixes/properties
// Should be called for non-reference LootStoreItem entries only (reference = 0)
@@ -156,8 +155,7 @@ struct TC_GAME_API LootItem
// Empty constructor for creating an empty LootItem to be filled in with DB data
LootItem() : itemid(0), randomBonusListId(0), context(ItemContext::NONE), count(0), is_looted(false), is_blocked(false),
- freeforall(false), is_underthreshold(false), is_counted(false), needs_quest(false), follow_loot_rules(false),
- canSave(true){ };
+ freeforall(false), is_underthreshold(false), is_counted(false), needs_quest(false), follow_loot_rules(false) { };
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
bool AllowedForPlayer(Player const* player) const;
@@ -230,10 +228,6 @@ struct TC_GAME_API Loot
ObjectGuid const& GetGUID() const { return _GUID; }
void SetGUID(ObjectGuid const& guid) { _GUID = guid; }
- // For deleting items at loot removal since there is no backward interface to the Item()
- void DeleteLootItemFromContainerItemDB(uint32 itemID);
- void DeleteLootMoneyFromContainerItemDB();
-
// if loot becomes invalid this reference is used to inform the listener
void addLootValidatorRef(LootValidatorRef* pLootValidatorRef)
{
diff --git a/src/server/game/Loot/LootItemStorage.cpp b/src/server/game/Loot/LootItemStorage.cpp
new file mode 100644
index 00000000000..4e3464eb31c
--- /dev/null
+++ b/src/server/game/Loot/LootItemStorage.cpp
@@ -0,0 +1,365 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * 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 "DatabaseEnv.h"
+#include "Item.h"
+#include "ItemTemplate.h"
+#include "Log.h"
+#include "LootItemStorage.h"
+#include "LootMgr.h"
+#include "ObjectMgr.h"
+#include "Player.h"
+
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/thread/locks.hpp>
+
+#include <unordered_map>
+
+namespace
+{
+ std::unordered_map<uint64, StoredLootContainer> _lootItemStore;
+}
+
+StoredLootItem::StoredLootItem(LootItem const& lootItem) : ItemId(lootItem.itemid), Count(lootItem.count), FollowRules(lootItem.follow_loot_rules),
+FFA(lootItem.freeforall), Blocked(lootItem.is_blocked), Counted(lootItem.is_counted), UnderThreshold(lootItem.is_underthreshold),
+NeedsQuest(lootItem.needs_quest), RandomBonusListId(lootItem.randomBonusListId), Context(lootItem.context), BonusListIDs(lootItem.BonusListIDs)
+{
+}
+
+LootItemStorage* LootItemStorage::instance()
+{
+ static LootItemStorage instance;
+ return &instance;
+}
+
+boost::shared_mutex* LootItemStorage::GetLock()
+{
+ static boost::shared_mutex _lock;
+ return &_lock;
+}
+
+void LootItemStorage::LoadStorageFromDB()
+{
+ uint32 oldMSTime = getMSTime();
+ _lootItemStore.clear();
+ uint32 count = 0;
+
+ CharacterDatabaseTransaction trans = CharacterDatabaseTransaction(nullptr);
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_ITEMS);
+ PreparedQueryResult result = CharacterDatabase.Query(stmt);
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint64 key = fields[0].GetUInt64();
+ auto itr = _lootItemStore.find(key);
+ if (itr == _lootItemStore.end())
+ {
+ bool added;
+ std::tie(itr, added) = _lootItemStore.emplace(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(key));
+
+ ASSERT(added);
+ }
+
+ StoredLootContainer& storedContainer = itr->second;
+
+ LootItem lootItem;
+ lootItem.itemid = fields[1].GetUInt32();
+ lootItem.count = fields[2].GetUInt32();
+ lootItem.follow_loot_rules = fields[3].GetBool();
+ lootItem.freeforall = fields[4].GetBool();
+ lootItem.is_blocked = fields[5].GetBool();
+ lootItem.is_counted = fields[6].GetBool();
+ lootItem.is_underthreshold = fields[7].GetBool();
+ lootItem.needs_quest = fields[8].GetBool();
+ lootItem.randomBonusListId = fields[9].GetUInt32();
+ lootItem.context = ItemContext(fields[10].GetUInt8());
+ Tokenizer bonusLists(fields[11].GetString(), ' ');
+ std::transform(bonusLists.begin(), bonusLists.end(), std::back_inserter(lootItem.BonusListIDs), [](char const* token)
+ {
+ return int32(strtol(token, NULL, 10));
+ });
+
+ storedContainer.AddLootItem(lootItem, trans);
+
+ ++count;
+ } while (result->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded %u stored item loots in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ }
+ else
+ TC_LOG_INFO("server.loading", ">> Loaded 0 stored item loots");
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_MONEY);
+ result = CharacterDatabase.Query(stmt);
+ if (result)
+ {
+ count = 0;
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint64 key = fields[0].GetUInt64();
+ auto itr = _lootItemStore.find(key);
+ if (itr == _lootItemStore.end())
+ {
+ bool added;
+ std::tie(itr, added) = _lootItemStore.emplace(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(key));
+
+ ASSERT(added);
+ }
+
+ StoredLootContainer& storedContainer = itr->second;
+ storedContainer.AddMoney(fields[1].GetUInt32(), trans);
+
+ ++count;
+ } while (result->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded %u stored item money in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ }
+ else
+ TC_LOG_INFO("server.loading", ">> Loaded 0 stored item money");
+}
+
+bool LootItemStorage::LoadStoredLoot(Item* item, Player* player)
+{
+ Loot* loot = &item->loot;
+ StoredLootContainer const* container = nullptr;
+
+ // read
+ {
+ boost::shared_lock<boost::shared_mutex> lock(*GetLock());
+
+ auto itr = _lootItemStore.find(loot->containerID.GetCounter());
+ if (itr == _lootItemStore.end())
+ return false;
+
+ container = &itr->second;
+ }
+
+ // container is never null at this point
+ loot->gold = container->GetMoney();
+
+ if (LootTemplate const* lt = LootTemplates_Item.GetLootFor(item->GetEntry()))
+ {
+ for (auto const& storedItemPair : container->GetLootItems())
+ {
+ LootItem li;
+ li.itemid = storedItemPair.first;
+ li.count = storedItemPair.second.Count;
+ li.follow_loot_rules = storedItemPair.second.FollowRules;
+ li.freeforall = storedItemPair.second.FFA;
+ li.is_blocked = storedItemPair.second.Blocked;
+ li.is_counted = storedItemPair.second.Counted;
+ li.is_underthreshold = storedItemPair.second.UnderThreshold;
+ li.needs_quest = storedItemPair.second.NeedsQuest;
+ li.randomBonusListId = storedItemPair.second.RandomBonusListId;
+ li.context = storedItemPair.second.Context;
+ li.BonusListIDs = storedItemPair.second.BonusListIDs;
+
+ // Copy the extra loot conditions from the item in the loot template
+ lt->CopyConditions(&li);
+
+ // If container item is in a bag, add that player as an allowed looter
+ if (item->GetBagSlot())
+ li.AddAllowedLooter(player);
+
+ // Finally add the LootItem to the container
+ loot->items.push_back(li);
+
+ // Increment unlooted count
+ ++loot->unlootedCount;
+ }
+ }
+
+ // Mark the item if it has loot so it won't be generated again on open
+ item->m_lootGenerated = true;
+ return true;
+}
+
+void LootItemStorage::RemoveStoredMoneyForContainer(uint64 containerId)
+{
+ // write
+ boost::unique_lock<boost::shared_mutex> lock(*GetLock());
+
+ auto itr = _lootItemStore.find(containerId);
+ if (itr == _lootItemStore.end())
+ return;
+
+ itr->second.RemoveMoney();
+}
+
+void LootItemStorage::RemoveStoredLootForContainer(uint64 containerId)
+{
+ // write
+ {
+ boost::unique_lock<boost::shared_mutex> lock(*GetLock());
+ _lootItemStore.erase(containerId);
+ }
+
+ CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS);
+ stmt->setUInt64(0, containerId);
+ trans->Append(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
+ stmt->setUInt64(0, containerId);
+ trans->Append(stmt);
+
+ CharacterDatabase.CommitTransaction(trans);
+}
+
+void LootItemStorage::RemoveStoredLootItemForContainer(uint64 containerId, uint32 itemId, uint32 count)
+{
+ // write
+ boost::unique_lock<boost::shared_mutex> lock(*GetLock());
+
+ auto itr = _lootItemStore.find(containerId);
+ if (itr == _lootItemStore.end())
+ return;
+
+ itr->second.RemoveItem(itemId, count);
+}
+
+void LootItemStorage::AddNewStoredLoot(Loot* loot, Player* player)
+{
+ // Saves the money and item loot associated with an openable item to the DB
+ if (loot->isLooted()) // no money and no loot
+ return;
+
+ // read
+ {
+ boost::shared_lock<boost::shared_mutex> lock(*GetLock());
+
+ auto itr = _lootItemStore.find(loot->containerID.GetCounter());
+ if (itr != _lootItemStore.end())
+ {
+ TC_LOG_ERROR("misc", "Trying to store item loot by player: %s for container id: %lu that is already in storage!", player->GetGUID().ToString().c_str(), loot->containerID.GetCounter());
+ return;
+ }
+ }
+
+ StoredLootContainer container(loot->containerID.GetCounter());
+
+ CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
+ if (loot->gold)
+ container.AddMoney(loot->gold, trans);
+
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS);
+ stmt->setUInt64(0, loot->containerID.GetCounter());
+ trans->Append(stmt);
+
+ for (LootItem const& li : loot->items)
+ {
+ // Conditions are not checked when loot is generated, it is checked when loot is sent to a player.
+ // For items that are lootable, loot is saved to the DB immediately, that means that loot can be
+ // saved to the DB that the player never should have gotten. This check prevents that, so that only
+ // items that the player should get in loot are in the DB.
+ // IE: Horde items are not saved to the DB for Ally players.
+ if (!li.AllowedForPlayer(player))
+ continue;
+
+ // Don't save currency tokens
+ ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(li.itemid);
+ if (!itemTemplate || itemTemplate->IsCurrencyToken())
+ continue;
+
+ container.AddLootItem(li, trans);
+ }
+
+ CharacterDatabase.CommitTransaction(trans);
+
+ // write
+ {
+ boost::unique_lock<boost::shared_mutex> lock(*GetLock());
+ _lootItemStore.emplace(loot->containerID.GetCounter(), std::move(container));
+ }
+}
+
+void StoredLootContainer::AddLootItem(LootItem const& lootItem, CharacterDatabaseTransaction& trans)
+{
+ _lootItems.emplace(std::piecewise_construct, std::forward_as_tuple(lootItem.itemid), std::forward_as_tuple(lootItem));
+ if (!trans)
+ return;
+
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_ITEMS);
+
+ // container_id, item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix
+ stmt->setUInt64(0, _containerId);
+ stmt->setUInt32(1, lootItem.itemid);
+ stmt->setUInt32(2, lootItem.count);
+ stmt->setBool(3, lootItem.follow_loot_rules);
+ stmt->setBool(4, lootItem.freeforall);
+ stmt->setBool(5, lootItem.is_blocked);
+ stmt->setBool(6, lootItem.is_counted);
+ stmt->setBool(7, lootItem.is_underthreshold);
+ stmt->setBool(8, lootItem.needs_quest);
+ stmt->setInt32(9, lootItem.randomBonusListId);
+ stmt->setUInt8(10, AsUnderlyingType(lootItem.context));
+ std::ostringstream bonusListIDs;
+ for (int32 bonusListID : lootItem.BonusListIDs)
+ bonusListIDs << bonusListID << ' ';
+ stmt->setString(11, bonusListIDs.str());
+ trans->Append(stmt);
+}
+
+void StoredLootContainer::AddMoney(uint32 money, CharacterDatabaseTransaction& trans)
+{
+ _money = money;
+ if (!trans)
+ return;
+
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
+ stmt->setUInt64(0, _containerId);
+ trans->Append(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_MONEY);
+ stmt->setUInt64(0, _containerId);
+ stmt->setUInt32(1, _money);
+ trans->Append(stmt);
+}
+
+void StoredLootContainer::RemoveMoney()
+{
+ _money = 0;
+
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
+ stmt->setUInt64(0, _containerId);
+ CharacterDatabase.Execute(stmt);
+}
+
+void StoredLootContainer::RemoveItem(uint32 itemId, uint32 count)
+{
+ auto bounds = _lootItems.equal_range(itemId);
+ for (auto itr = bounds.first; itr != bounds.second; ++itr)
+ {
+ if (itr->second.Count == count)
+ {
+ _lootItems.erase(itr);
+ break;
+ }
+ }
+
+ // Deletes a single item associated with an openable item from the DB
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM);
+ stmt->setUInt64(0, _containerId);
+ stmt->setUInt32(1, itemId);
+ stmt->setUInt32(2, count);
+ CharacterDatabase.Execute(stmt);
+}
diff --git a/src/server/game/Loot/LootItemStorage.h b/src/server/game/Loot/LootItemStorage.h
new file mode 100644
index 00000000000..7855559ce1e
--- /dev/null
+++ b/src/server/game/Loot/LootItemStorage.h
@@ -0,0 +1,99 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LOOTITEMSTORAGE_H
+#define __LOOTITEMSTORAGE_H
+
+#include "DatabaseEnvFwd.h"
+#include "Define.h"
+#include "DBCEnums.h"
+#include "ItemEnchantmentMgr.h"
+
+#include <unordered_map>
+#include <vector>
+
+class Item;
+class Player;
+struct Loot;
+struct LootItem;
+
+namespace boost
+{
+ class shared_mutex;
+}
+
+struct StoredLootItem
+{
+ explicit StoredLootItem(LootItem const& lootItem);
+
+ uint32 ItemId;
+ uint32 Count;
+ bool FollowRules;
+ bool FFA;
+ bool Blocked;
+ bool Counted;
+ bool UnderThreshold;
+ bool NeedsQuest;
+ ItemRandomBonusListId RandomBonusListId;
+ ItemContext Context;
+ std::vector<int32> BonusListIDs;
+};
+
+class StoredLootContainer
+{
+ public:
+ typedef std::unordered_multimap<uint32 /*itemId*/, StoredLootItem> StoredLootItemContainer;
+
+ explicit StoredLootContainer(uint64 containerId) : _containerId(containerId), _money(0) { }
+
+ void AddLootItem(LootItem const& lootItem, CharacterDatabaseTransaction& trans);
+ void AddMoney(uint32 money, CharacterDatabaseTransaction& trans);
+
+ void RemoveMoney();
+ void RemoveItem(uint32 itemId, uint32 count);
+
+ uint32 GetContainer() const { return _containerId; }
+ uint32 GetMoney() const { return _money; }
+ StoredLootItemContainer const& GetLootItems() const { return _lootItems; }
+
+ private:
+ StoredLootItemContainer _lootItems;
+ uint64 const _containerId;
+ uint32 _money;
+};
+
+class LootItemStorage
+{
+ public:
+ static LootItemStorage* instance();
+ static boost::shared_mutex* GetLock();
+
+ void LoadStorageFromDB();
+ bool LoadStoredLoot(Item* item, Player* player);
+ void RemoveStoredMoneyForContainer(uint64 containerId);
+ void RemoveStoredLootForContainer(uint64 containerId);
+ void RemoveStoredLootItemForContainer(uint64 containerId, uint32 itemId, uint32 count);
+ void AddNewStoredLoot(Loot* loot, Player* player);
+
+ private:
+ LootItemStorage() { }
+ ~LootItemStorage() { }
+};
+
+#define sLootItemStorage LootItemStorage::instance()
+
+#endif
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 7b83e3412d5..24392412710 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -3982,7 +3982,7 @@ void Map::SaveCreatureRespawnTime(ObjectGuid::LowType dbGuid, time_t respawnTime
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CREATURE_RESPAWN);
stmt->setUInt64(0, dbGuid);
- stmt->setUInt32(1, uint32(respawnTime));
+ stmt->setUInt64(1, uint64(respawnTime));
stmt->setUInt16(2, GetId());
stmt->setUInt32(3, GetInstanceId());
CharacterDatabase.Execute(stmt);
@@ -4012,7 +4012,7 @@ void Map::SaveGORespawnTime(ObjectGuid::LowType dbGuid, time_t respawnTime)
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GO_RESPAWN);
stmt->setUInt64(0, dbGuid);
- stmt->setUInt32(1, uint32(respawnTime));
+ stmt->setUInt64(1, uint64(respawnTime));
stmt->setUInt16(2, GetId());
stmt->setUInt32(3, GetInstanceId());
CharacterDatabase.Execute(stmt);
@@ -4040,7 +4040,7 @@ void Map::LoadRespawnTimes()
{
Field* fields = result->Fetch();
ObjectGuid::LowType loguid = fields[0].GetUInt64();
- uint32 respawnTime = fields[1].GetUInt32();
+ uint64 respawnTime = fields[1].GetUInt64();
_creatureRespawnTimes[loguid] = time_t(respawnTime);
} while (result->NextRow());
@@ -4055,7 +4055,7 @@ void Map::LoadRespawnTimes()
{
Field* fields = result->Fetch();
ObjectGuid::LowType loguid = fields[0].GetUInt64();
- uint32 respawnTime = fields[1].GetUInt32();
+ uint64 respawnTime = fields[1].GetUInt64();
_goRespawnTimes[loguid] = time_t(respawnTime);
} while (result->NextRow());
diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp
index 3e775d238a4..3b446733bbb 100644
--- a/src/server/game/Movement/MotionMaster.cpp
+++ b/src/server/game/Movement/MotionMaster.cpp
@@ -30,8 +30,10 @@
#include "WaypointMovementGenerator.h"
#include "RandomMovementGenerator.h"
#include "SplineChainMovementGenerator.h"
+#include "FormationMovementGenerator.h"
#include "MoveSpline.h"
#include "MoveSplineInit.h"
+#include "PathGenerator.h"
inline bool IsStatic(MovementGenerator* movement)
{
@@ -76,7 +78,7 @@ void MotionMaster::InitDefault()
if (_owner->GetTypeId() == TYPEID_UNIT)
{
MovementGenerator* movement = FactorySelector::selectMovementGenerator(_owner->ToCreature());
- Mutate(movement == NULL ? &si_idleMovement : movement, MOTION_SLOT_IDLE);
+ Mutate(movement == nullptr ? &si_idleMovement : movement, MOTION_SLOT_IDLE);
}
else
{
@@ -89,9 +91,6 @@ void MotionMaster::UpdateMotion(uint32 diff)
if (!_owner)
return;
- if (_owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) // what about UNIT_STATE_DISTRACTED? Why is this not included?
- return;
-
ASSERT(!empty());
_cleanFlag |= MMCF_UPDATE;
@@ -174,12 +173,12 @@ MovementGenerator* MotionMaster::GetMotionSlot(int slot) const
return _slot[slot];
}
-void MotionMaster::propagateSpeedChange()
+void MotionMaster::PropagateSpeedChange()
{
for (int i = 0; i <= _top; ++i)
{
if (_slot[i])
- _slot[i]->unitSpeedChanged();
+ _slot[i]->UnitSpeedChanged();
}
}
@@ -713,6 +712,15 @@ void MotionMaster::MoveRotate(uint32 time, RotateDirection direction)
Mutate(new RotateMovementGenerator(time, direction), MOTION_SLOT_ACTIVE);
}
+void MotionMaster::MoveFormation(uint32 id, Position destination, uint32 moveType, bool forceRun /*= false*/, bool forceOrientation /*= false*/)
+{
+ if (_owner->GetTypeId() == TYPEID_UNIT)
+ {
+ TC_LOG_DEBUG("misc", "MotionMaster::MoveFormation: Creature (Entry: %u %s) targeted point (Id: %u X: %f Y: %f Z: %f).", _owner->GetEntry(), _owner->GetGUID().ToString().c_str(), id, destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ());
+ Mutate(new FormationMovementGenerator(id, destination, moveType, forceRun, forceOrientation), MOTION_SLOT_ACTIVE);
+ }
+}
+
/******************** Private methods ********************/
void MotionMaster::pop()
diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h
index c496a0ec4ec..7cb72c353f7 100644
--- a/src/server/game/Movement/MotionMaster.h
+++ b/src/server/game/Movement/MotionMaster.h
@@ -66,6 +66,7 @@ enum MovementGeneratorType : uint8
ROTATE_MOTION_TYPE = 15,
EFFECT_MOTION_TYPE = 16,
SPLINE_CHAIN_MOTION_TYPE = 17, // SplineChainMovementGenerator.h
+ FORMATION_MOTION_TYPE = 18, // FormationMovementGenerator.h
MAX_MOTION_TYPE // limit
};
@@ -125,7 +126,7 @@ class TC_GAME_API MotionMaster
MovementGeneratorType GetMotionSlotType(int slot) const;
MovementGenerator* GetMotionSlot(int slot) const;
- void propagateSpeedChange();
+ void PropagateSpeedChange();
bool GetDestination(float &x, float &y, float &z);
@@ -176,6 +177,8 @@ class TC_GAME_API MotionMaster
void MovePath(uint32 path_id, bool repeatable);
void MoveRotate(uint32 time, RotateDirection direction);
+ void MoveFormation(uint32 id, Position destination, uint32 moveType, bool forceRun = false, bool forceOrientation = false);
+
private:
typedef std::vector<MovementGenerator*> MovementList;
diff --git a/src/server/game/Movement/MovementGenerator.h b/src/server/game/Movement/MovementGenerator.h
index a28ffca0172..fdf5506dd15 100755
--- a/src/server/game/Movement/MovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerator.h
@@ -33,14 +33,12 @@ class TC_GAME_API MovementGenerator
virtual void Initialize(Unit*) = 0;
virtual void Finalize(Unit*) = 0;
-
virtual void Reset(Unit*) = 0;
-
- virtual bool Update(Unit*, uint32 time_diff) = 0;
+ virtual bool Update(Unit*, uint32 diff) = 0;
virtual MovementGeneratorType GetMovementGeneratorType() const = 0;
- virtual void unitSpeedChanged() { }
+ 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; }
@@ -52,42 +50,39 @@ class MovementGeneratorMedium : public MovementGenerator
public:
void Initialize(Unit* u) override
{
- //u->AssertIsType<T>();
(static_cast<D*>(this))->DoInitialize(static_cast<T*>(u));
}
void Finalize(Unit* u) override
{
- //u->AssertIsType<T>();
(static_cast<D*>(this))->DoFinalize(static_cast<T*>(u));
}
void Reset(Unit* u) override
{
- //u->AssertIsType<T>();
(static_cast<D*>(this))->DoReset(static_cast<T*>(u));
}
bool Update(Unit* u, uint32 time_diff) override
{
- //u->AssertIsType<T>();
return (static_cast<D*>(this))->DoUpdate(static_cast<T*>(u), time_diff);
}
};
struct SelectableMovement : public FactoryHolder<MovementGenerator, MovementGeneratorType>
{
- SelectableMovement(MovementGeneratorType mgt) : FactoryHolder<MovementGenerator, MovementGeneratorType>(mgt) { }
+ SelectableMovement(MovementGeneratorType movementGeneratorType) : FactoryHolder<MovementGenerator, MovementGeneratorType>(movementGeneratorType) { }
};
-template<class REAL_MOVEMENT>
+template<class Movement>
struct MovementGeneratorFactory : public SelectableMovement
{
- MovementGeneratorFactory(MovementGeneratorType mgt) : SelectableMovement(mgt) { }
+ MovementGeneratorFactory(MovementGeneratorType movementGeneratorType) : SelectableMovement(movementGeneratorType) { }
MovementGenerator* Create(void *) const override;
};
typedef FactoryHolder<MovementGenerator, MovementGeneratorType> MovementGeneratorCreator;
typedef FactoryHolder<MovementGenerator, MovementGeneratorType>::FactoryHolderRegistry MovementGeneratorRegistry;
+
#endif
diff --git a/src/server/game/Movement/MovementGeneratorImpl.h b/src/server/game/Movement/MovementGeneratorImpl.h
index 346fae28d1f..0b5474b22b3 100644
--- a/src/server/game/Movement/MovementGeneratorImpl.h
+++ b/src/server/game/Movement/MovementGeneratorImpl.h
@@ -20,10 +20,10 @@
#include "MovementGenerator.h"
-template<class MOVEMENT_GEN>
-inline MovementGenerator*
-MovementGeneratorFactory<MOVEMENT_GEN>::Create(void * /*data*/) const
+template<class Movement>
+inline MovementGenerator* MovementGeneratorFactory<Movement>::Create(void * /*data*/) const
{
- return (new MOVEMENT_GEN());
+ return (new Movement());
}
+
#endif
diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
index 37b0cf912ad..0432241432d 100755
--- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
@@ -16,92 +16,95 @@
*/
#include "Creature.h"
-#include "ConfusedMovementGenerator.h"
+#include "Player.h"
#include "PathGenerator.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
-#include "Player.h"
#include "Random.h"
+#include "ConfusedMovementGenerator.h"
template<class T>
-void ConfusedMovementGenerator<T>::DoInitialize(T* unit)
+ConfusedMovementGenerator<T>::~ConfusedMovementGenerator()
{
- unit->AddUnitState(UNIT_STATE_CONFUSED);
- unit->AddUnitFlag(UNIT_FLAG_CONFUSED);
- unit->GetPosition(i_x, i_y, i_z);
+ delete _path;
+}
- if (!unit->IsAlive() || unit->IsStopped())
+template<class T>
+void ConfusedMovementGenerator<T>::DoInitialize(T* owner)
+{
+ if (!owner || !owner->IsAlive())
return;
- unit->StopMoving();
- unit->AddUnitState(UNIT_STATE_CONFUSED_MOVE);
+ owner->AddUnitState(UNIT_STATE_CONFUSED);
+ owner->AddUnitFlag(UNIT_FLAG_CONFUSED);
+ owner->StopMoving();
+
+ _timer.Reset(0);
+ owner->GetPosition(_reference.m_positionX, _reference.m_positionY, _reference.m_positionZ);
}
template<class T>
-void ConfusedMovementGenerator<T>::DoReset(T* unit)
+void ConfusedMovementGenerator<T>::DoReset(T* owner)
{
- i_nextMoveTime.Reset(0);
-
- if (!unit->IsAlive() || unit->IsStopped())
- return;
-
- unit->StopMoving();
- unit->AddUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
+ DoInitialize(owner);
}
template<class T>
-bool ConfusedMovementGenerator<T>::DoUpdate(T* unit, uint32 diff)
+bool ConfusedMovementGenerator<T>::DoUpdate(T* owner, uint32 diff)
{
- if (unit->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
- return true;
+ if (!owner || !owner->IsAlive())
+ return false;
- if (i_nextMoveTime.Passed())
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
{
- // currently moving, update location
- unit->AddUnitState(UNIT_STATE_CONFUSED_MOVE);
-
- if (unit->movespline->Finalized())
- i_nextMoveTime.Reset(urand(800, 1500));
+ _interrupt = true;
+ owner->StopMoving();
+ return true;
}
else
+ _interrupt = false;
+
+ // waiting for next move
+ _timer.Update(diff);
+ if (!_interrupt && _timer.Passed() && owner->movespline->Finalized())
{
- // waiting for next move
- i_nextMoveTime.Update(diff);
- if (i_nextMoveTime.Passed())
+ // start moving
+ owner->AddUnitState(UNIT_STATE_CONFUSED_MOVE);
+
+ Position destination(_reference);
+ float distance = 4.0f * frand(0.0f, 1.0f) - 2.0f;
+ float angle = frand(0.0f, 1.0f) * float(M_PI) * 2.0f;
+ owner->MovePositionToFirstCollision(destination, distance, angle);
+
+ if (!_path)
+ _path = new PathGenerator(owner);
+
+ _path->SetPathLengthLimit(30.0f);
+ bool result = _path->CalculatePath(destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ());
+ if (!result || (_path->GetPathType() & PATHFIND_NOPATH))
{
- // start moving
- 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;
- }
-
- Movement::MoveSplineInit init(unit);
- init.MovebyPath(path.GetPath());
- init.SetWalk(true);
- init.Launch();
+ _timer.Reset(100);
+ return true;
}
+
+ Movement::MoveSplineInit init(owner);
+ init.MovebyPath(_path->GetPath());
+ init.SetWalk(true);
+ int32 traveltime = init.Launch();
+ _timer.Reset(traveltime + urand(800, 1500));
}
return true;
}
+template<class T>
+void ConfusedMovementGenerator<T>::DoFinalize(T*) { }
+
template<>
void ConfusedMovementGenerator<Player>::DoFinalize(Player* unit)
{
unit->RemoveUnitFlag(UNIT_FLAG_CONFUSED);
- unit->ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
+ unit->ClearUnitState(UNIT_STATE_CONFUSED);
unit->StopMoving();
}
@@ -114,6 +117,8 @@ void ConfusedMovementGenerator<Creature>::DoFinalize(Creature* unit)
unit->SetTarget(unit->EnsureVictim()->GetGUID());
}
+template ConfusedMovementGenerator<Player>::~ConfusedMovementGenerator();
+template ConfusedMovementGenerator<Creature>::~ConfusedMovementGenerator();
template void ConfusedMovementGenerator<Player>::DoInitialize(Player*);
template void ConfusedMovementGenerator<Creature>::DoInitialize(Creature*);
template void ConfusedMovementGenerator<Player>::DoReset(Player*);
diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h
index a67afb72024..7d4cd073457 100755
--- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h
@@ -25,16 +25,21 @@ template<class T>
class ConfusedMovementGenerator : public MovementGeneratorMedium< T, ConfusedMovementGenerator<T> >
{
public:
- explicit ConfusedMovementGenerator() : i_nextMoveTime(0), i_x(0), i_y(0), i_z(0) { }
+ explicit ConfusedMovementGenerator() : _path(nullptr), _timer(0), _reference(0.f, 0.f, 0.f), _interrupt(false) { }
+ ~ConfusedMovementGenerator();
+
+ MovementGeneratorType GetMovementGeneratorType() const override { return CONFUSED_MOTION_TYPE; }
void DoInitialize(T*);
void DoFinalize(T*);
void DoReset(T*);
bool DoUpdate(T*, uint32);
- MovementGeneratorType GetMovementGeneratorType() const override { return CONFUSED_MOTION_TYPE; }
private:
- TimeTracker i_nextMoveTime;
- float i_x, i_y, i_z;
+ PathGenerator* _path;
+ TimeTracker _timer;
+ Position _reference;
+ bool _interrupt;
};
+
#endif
diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
index bfe3f4399d0..a1d179c23ce 100644
--- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
@@ -15,176 +15,203 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "Creature.h"
+#include "VMapFactory.h"
#include "CreatureAI.h"
-#include "FleeingMovementGenerator.h"
-#include "PathGenerator.h"
#include "ObjectAccessor.h"
+#include "Creature.h"
+#include "Player.h"
+#include "PathGenerator.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#include "PhasingHandler.h"
-#include "Player.h"
-#include "VMapFactory.h"
+#include "FleeingMovementGenerator.h"
#define MIN_QUIET_DISTANCE 28.0f
#define MAX_QUIET_DISTANCE 43.0f
template<class T>
-void FleeingMovementGenerator<T>::_setTargetLocation(T* owner)
+FleeingMovementGenerator<T>::~FleeingMovementGenerator()
+{
+ delete _path;
+}
+
+template<class T>
+void FleeingMovementGenerator<T>::DoInitialize(T* owner)
{
if (!owner)
return;
- if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
+ owner->AddUnitFlag(UNIT_FLAG_FLEEING);
+ owner->AddUnitState(UNIT_STATE_FLEEING);
+ SetTargetLocation(owner);
+}
+
+template<class T>
+void FleeingMovementGenerator<T>::DoFinalize(T *)
+{
+}
+
+template<>
+void FleeingMovementGenerator<Player>::DoFinalize(Player* owner)
+{
+ owner->RemoveUnitFlag(UNIT_FLAG_FLEEING);
+ owner->ClearUnitState(UNIT_STATE_FLEEING);
+ owner->StopMoving();
+}
+
+template<>
+void FleeingMovementGenerator<Creature>::DoFinalize(Creature* owner)
+{
+ owner->RemoveUnitFlag(UNIT_FLAG_FLEEING);
+ owner->ClearUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE);
+ if (owner->GetVictim())
+ owner->SetTarget(owner->EnsureVictim()->GetGUID());
+}
+
+template<class T>
+void FleeingMovementGenerator<T>::DoReset(T* owner)
+{
+ DoInitialize(owner);
+}
+
+template<class T>
+bool FleeingMovementGenerator<T>::DoUpdate(T* owner, uint32 diff)
+{
+ if (!owner || !owner->IsAlive())
+ return false;
+
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
+ {
+ _interrupt = true;
+ owner->StopMoving();
+ return true;
+ }
+ else
+ _interrupt = false;
+
+ _timer.Update(diff);
+ if (!_interrupt && _timer.Passed() && owner->movespline->Finalized())
+ SetTargetLocation(owner);
+
+ return true;
+}
+
+template<class T>
+void FleeingMovementGenerator<T>::SetTargetLocation(T* owner)
+{
+ if (!owner)
return;
- if (owner->IsMovementPreventedByCasting())
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
{
- owner->CastStop();
+ _interrupt = true;
+ owner->StopMoving();
return;
}
owner->AddUnitState(UNIT_STATE_FLEEING_MOVE);
- float x, y, z;
- _getPoint(owner, x, y, z);
+ Position destination = owner->GetPosition();
+ GetPoint(owner, destination);
// Add LOS check for target point
- Position mypos = owner->GetPosition();
- bool isInLOS = VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(
- PhasingHandler::GetTerrainMapId(owner->GetPhaseShift(), owner->GetMap(), mypos.m_positionX, mypos.m_positionY),
- mypos.m_positionX, mypos.m_positionY, mypos.m_positionZ + 2.0f, x, y, z + 2.0f, VMAP::ModelIgnoreFlags::Nothing);
- if (!isInLOS)
+ Position currentPosition = owner->GetPosition();
+ if (!VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(PhasingHandler::GetTerrainMapId(owner->GetPhaseShift(), owner->GetMap(), currentPosition.m_positionX, currentPosition.m_positionY), currentPosition.m_positionX, currentPosition.m_positionY, currentPosition.m_positionZ + 2.0f, destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ() + 2.0f, VMAP::ModelIgnoreFlags::Nothing))
{
- i_nextCheckTime.Reset(200);
+ _timer.Reset(200);
return;
}
- PathGenerator path(owner);
- path.SetPathLengthLimit(30.0f);
- bool result = path.CalculatePath(x, y, z);
- if (!result || (path.GetPathType() & PATHFIND_NOPATH))
+ if (!_path)
+ _path = new PathGenerator(owner);
+
+ _path->SetPathLengthLimit(30.0f);
+ bool result = _path->CalculatePath(destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ());
+ if (!result || (_path->GetPathType() & PATHFIND_NOPATH))
{
- i_nextCheckTime.Reset(100);
+ _timer.Reset(100);
return;
}
Movement::MoveSplineInit init(owner);
- init.MovebyPath(path.GetPath());
+ init.MovebyPath(_path->GetPath());
init.SetWalk(false);
int32 traveltime = init.Launch();
- i_nextCheckTime.Reset(traveltime + urand(800, 1500));
+ _timer.Reset(traveltime + urand(800, 1500));
}
template<class T>
-void FleeingMovementGenerator<T>::_getPoint(T* owner, float &x, float &y, float &z)
+void FleeingMovementGenerator<T>::GetPoint(T* owner, Position &position)
{
- float dist_from_caster, angle_to_caster;
- if (Unit* fright = ObjectAccessor::GetUnit(*owner, i_frightGUID))
+ float casterDistance, casterAngle;
+ if (Unit* fleeTarget = ObjectAccessor::GetUnit(*owner, _fleeTargetGUID))
{
- dist_from_caster = fright->GetDistance(owner);
- if (dist_from_caster > 0.2f)
- angle_to_caster = fright->GetAngle(owner);
+ casterDistance = fleeTarget->GetDistance(owner);
+ if (casterDistance > 0.2f)
+ casterAngle = fleeTarget->GetAngle(owner);
else
- angle_to_caster = frand(0, 2 * static_cast<float>(M_PI));
+ casterAngle = frand(0.0f, 2.0f * float(M_PI));
}
else
{
- dist_from_caster = 0.0f;
- angle_to_caster = frand(0, 2 * static_cast<float>(M_PI));
+ casterDistance = 0.0f;
+ casterAngle = frand(0.0f, 2.0f * float(M_PI));
}
- float dist, angle;
- if (dist_from_caster < MIN_QUIET_DISTANCE)
+ float distance, angle;
+ if (casterDistance < MIN_QUIET_DISTANCE)
{
- 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);
+ distance = frand(0.4f, 1.3f) * (MIN_QUIET_DISTANCE - casterDistance);
+ angle = casterAngle + frand(-float(M_PI) / 8.0f, float(M_PI) / 8.0f);
}
- else if (dist_from_caster > MAX_QUIET_DISTANCE)
+ else if (casterDistance > MAX_QUIET_DISTANCE)
{
- 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);
+ distance = frand(0.4f, 1.0f) * (MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
+ angle = -casterAngle + frand(-float(M_PI) / 4.0f, float(M_PI) / 4.0f);
}
else // we are inside quiet range
{
- dist = frand(0.6f, 1.2f)*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
- angle = frand(0, 2*static_cast<float>(M_PI));
+ distance = frand(0.6f, 1.2f) * (MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
+ angle = frand(0.0f, 2.0f * float(M_PI));
}
- Position pos = owner->GetFirstCollisionPosition(dist, angle);
- x = pos.m_positionX;
- y = pos.m_positionY;
- z = pos.m_positionZ;
-}
-
-template<class T>
-void FleeingMovementGenerator<T>::DoInitialize(T* owner)
-{
- if (!owner)
- return;
-
- owner->AddUnitFlag(UNIT_FLAG_FLEEING);
- owner->AddUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE);
- _setTargetLocation(owner);
+ owner->MovePositionToFirstCollision(position, distance, angle);
}
-template<>
-void FleeingMovementGenerator<Player>::DoFinalize(Player* owner)
-{
- owner->RemoveUnitFlag(UNIT_FLAG_FLEEING);
- owner->ClearUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE);
- owner->StopMoving();
-}
-
-template<>
-void FleeingMovementGenerator<Creature>::DoFinalize(Creature* owner)
-{
- owner->RemoveUnitFlag(UNIT_FLAG_FLEEING);
- owner->ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
- if (owner->GetVictim())
- owner->SetTarget(owner->EnsureVictim()->GetGUID());
-}
+template FleeingMovementGenerator<Player>::~FleeingMovementGenerator();
+template FleeingMovementGenerator<Creature>::~FleeingMovementGenerator();
+template void FleeingMovementGenerator<Player>::DoInitialize(Player*);
+template void FleeingMovementGenerator<Creature>::DoInitialize(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);
+template void FleeingMovementGenerator<Player>::SetTargetLocation(Player*);
+template void FleeingMovementGenerator<Creature>::SetTargetLocation(Creature*);
+template void FleeingMovementGenerator<Player>::GetPoint(Player*, Position &);
+template void FleeingMovementGenerator<Creature>::GetPoint(Creature*, Position &);
-template<class T>
-void FleeingMovementGenerator<T>::DoReset(T* owner)
-{
- DoInitialize(owner);
-}
+//---- TimedFleeingMovementGenerator
-template<class T>
-bool FleeingMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
+bool TimedFleeingMovementGenerator::Update(Unit* owner, uint32 time_diff)
{
- if (!owner || !owner->IsAlive())
+ if (!owner->IsAlive())
return false;
- if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
- {
- owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE);
- return true;
- }
-
- i_nextCheckTime.Update(time_diff);
- if (i_nextCheckTime.Passed() && owner->movespline->Finalized())
- _setTargetLocation(owner);
+ _totalFleeTime.Update(time_diff);
+ if (_totalFleeTime.Passed())
+ return false;
- return true;
+ // This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, uint32) version
+ // 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);
}
-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->RemoveUnitFlag(UNIT_FLAG_FLEEING);
- owner->ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
+ owner->ClearUnitState(UNIT_STATE_FLEEING);
+ owner->StopMoving();
if (Unit* victim = owner->GetVictim())
{
if (owner->IsAlive())
@@ -194,23 +221,3 @@ void TimedFleeingMovementGenerator::Finalize(Unit* owner)
}
}
}
-
-bool TimedFleeingMovementGenerator::Update(Unit* owner, uint32 time_diff)
-{
- if (!owner->IsAlive())
- return false;
-
- if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
- {
- owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE);
- return true;
- }
-
- i_totalFleeTime.Update(time_diff);
- if (i_totalFleeTime.Passed())
- return false;
-
- // This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, uint32) version
- // 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 025e783be5b..7481e340154 100755
--- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h
@@ -19,41 +19,43 @@
#define TRINITY_FLEEINGMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
+#include "Timer.h"
template<class T>
class FleeingMovementGenerator : public MovementGeneratorMedium< T, FleeingMovementGenerator<T> >
{
public:
- FleeingMovementGenerator(ObjectGuid fright) : i_frightGUID(fright), i_nextCheckTime(0) { }
+ explicit FleeingMovementGenerator(ObjectGuid fleeTargetGUID) : _path(nullptr), _fleeTargetGUID(fleeTargetGUID), _timer(0), _interrupt(false) { }
+ ~FleeingMovementGenerator();
+
+ MovementGeneratorType GetMovementGeneratorType() const override { return FLEEING_MOTION_TYPE; }
void DoInitialize(T*);
void DoFinalize(T*);
void DoReset(T*);
bool DoUpdate(T*, uint32);
- MovementGeneratorType GetMovementGeneratorType() const override { return FLEEING_MOTION_TYPE; }
-
private:
- void _setTargetLocation(T*);
- void _getPoint(T*, float &x, float &y, float &z);
+ void SetTargetLocation(T*);
+ void GetPoint(T*, Position &position);
- ObjectGuid i_frightGUID;
- TimeTracker i_nextCheckTime;
+ PathGenerator* _path;
+ ObjectGuid _fleeTargetGUID;
+ TimeTracker _timer;
+ bool _interrupt;
};
class TimedFleeingMovementGenerator : public FleeingMovementGenerator<Creature>
{
public:
- TimedFleeingMovementGenerator(ObjectGuid fright, uint32 time) :
- FleeingMovementGenerator<Creature>(fright),
- i_totalFleeTime(time) { }
+ explicit TimedFleeingMovementGenerator(ObjectGuid fleeTargetGUID, uint32 time) : FleeingMovementGenerator<Creature>(fleeTargetGUID), _totalFleeTime(time) { }
MovementGeneratorType GetMovementGeneratorType() const override { return TIMED_FLEEING_MOTION_TYPE; }
bool Update(Unit*, uint32) override;
void Finalize(Unit*) override;
private:
- TimeTracker i_totalFleeTime;
+ TimeTracker _totalFleeTime;
};
#endif
diff --git a/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.cpp
new file mode 100644
index 00000000000..a1382ec673e
--- /dev/null
+++ b/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.cpp
@@ -0,0 +1,130 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * 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 "Creature.h"
+#include "CreatureAI.h"
+#include "MoveSplineInit.h"
+#include "MoveSpline.h"
+#include "FormationMovementGenerator.h"
+
+void FormationMovementGenerator::DoInitialize(Creature* owner)
+{
+ owner->AddUnitState(UNIT_STATE_ROAMING);
+
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
+ {
+ _interrupt = true;
+ owner->StopMoving();
+ return;
+ }
+
+ owner->AddUnitState(UNIT_STATE_ROAMING_MOVE);
+
+ Movement::MoveSplineInit init(owner);
+ init.MoveTo(_destination.GetPositionX(), _destination.GetPositionY(), _destination.GetPositionZ());
+ if (_orientation)
+ init.SetFacing(_destination.GetOrientation());
+
+ switch (_moveType)
+ {
+ case 2: // WAYPOINT_MOVE_TYPE_LAND
+ init.SetAnimation(Movement::ToGround);
+ break;
+ case 3: // WAYPOINT_MOVE_TYPE_TAKEOFF
+ init.SetAnimation(Movement::ToFly);
+ break;
+ case 1: // WAYPOINT_MOVE_TYPE_RUN
+ init.SetWalk(false);
+ break;
+ case 0: // WAYPOINT_MOVE_TYPE_WALK
+ init.SetWalk(true);
+ break;
+ }
+
+ if (_run)
+ init.SetWalk(false);
+
+ init.Launch();
+}
+
+bool FormationMovementGenerator::DoUpdate(Creature* owner, uint32 /*diff*/)
+{
+ if (!owner)
+ return false;
+
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
+ {
+ _interrupt = true;
+ owner->StopMoving();
+ return true;
+ }
+
+ if ((_interrupt && owner->movespline->Finalized()) || (_recalculateSpeed && !owner->movespline->Finalized()))
+ {
+ _recalculateSpeed = false;
+ _interrupt = false;
+
+ owner->AddUnitState(UNIT_STATE_ROAMING_MOVE);
+
+ Movement::MoveSplineInit init(owner);
+ init.MoveTo(_destination.GetPositionX(), _destination.GetPositionY(), _destination.GetPositionZ());
+ if (_orientation)
+ init.SetFacing(_destination.GetOrientation());
+
+ switch (_moveType)
+ {
+ case 2: // WAYPOINT_MOVE_TYPE_LAND
+ init.SetAnimation(Movement::ToGround);
+ break;
+ case 3: // WAYPOINT_MOVE_TYPE_TAKEOFF
+ init.SetAnimation(Movement::ToFly);
+ break;
+ case 1: // WAYPOINT_MOVE_TYPE_RUN
+ init.SetWalk(false);
+ break;
+ case 0: // WAYPOINT_MOVE_TYPE_WALK
+ init.SetWalk(true);
+ break;
+ }
+
+ if (_run)
+ init.SetWalk(false);
+ init.Launch();
+ }
+
+ return !owner->movespline->Finalized();
+}
+
+void FormationMovementGenerator::DoFinalize(Creature* owner)
+{
+ owner->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
+
+ if (owner->movespline->Finalized())
+ MovementInform(owner);
+}
+
+void FormationMovementGenerator::DoReset(Creature* owner)
+{
+ owner->StopMoving();
+ DoInitialize(owner);
+}
+
+void FormationMovementGenerator::MovementInform(Creature* owner)
+{
+ if (owner->AI())
+ owner->AI()->MovementInform(FORMATION_MOTION_TYPE, _movementId);
+}
diff --git a/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.h
new file mode 100644
index 00000000000..27ab7d50da5
--- /dev/null
+++ b/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TRINITY_FORMATIONMOVEMENTGENERATOR_H
+#define TRINITY_FORMATIONMOVEMENTGENERATOR_H
+
+#include "MovementGenerator.h"
+
+class FormationMovementGenerator : public MovementGeneratorMedium< Creature, FormationMovementGenerator >
+{
+ public:
+ explicit FormationMovementGenerator(uint32 id, Position destination, uint32 moveType, bool run, bool orientation) : _movementId(id), _destination(destination), _moveType(moveType), _run(run), _orientation(orientation), _recalculateSpeed(false), _interrupt(false) { }
+
+ MovementGeneratorType GetMovementGeneratorType() const override { return FORMATION_MOTION_TYPE; }
+
+ void DoInitialize(Creature*);
+ void DoFinalize(Creature*);
+ void DoReset(Creature*);
+ bool DoUpdate(Creature*, uint32);
+
+ void UnitSpeedChanged() override { _recalculateSpeed = true; }
+
+ private:
+ void MovementInform(Creature*);
+
+ uint32 _movementId;
+ Position _destination;
+ uint32 _moveType;
+ bool _run;
+ bool _orientation;
+ bool _recalculateSpeed;
+ bool _interrupt;
+};
+
+#endif // TRINITY_FORMATIONMOVEMENTGENERATOR_H
diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
index e8fa2ba6c53..041961ce91c 100644
--- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
@@ -15,36 +15,31 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "HomeMovementGenerator.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
+#include "PathGenerator.h"
+#include "HomeMovementGenerator.h"
-void HomeMovementGenerator<Creature>::DoInitialize(Creature* owner)
-{
- _setTargetLocation(owner);
-}
+template<class T>
+HomeMovementGenerator<T>::~HomeMovementGenerator() { }
-void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner)
+template<>
+HomeMovementGenerator<Creature>::~HomeMovementGenerator()
{
- if (arrived)
- {
- owner->ClearUnitState(UNIT_STATE_EVADE);
- owner->SetWalk(true);
- owner->LoadCreaturesAddon();
- owner->AI()->JustReachedHome();
- owner->SetSpawnHealth();
- }
+ delete _path;
}
-void HomeMovementGenerator<Creature>::DoReset(Creature*) { }
+template<class T>
+void HomeMovementGenerator<T>::SetTargetLocation(T*) { }
-void HomeMovementGenerator<Creature>::_setTargetLocation(Creature* owner)
+template<>
+void HomeMovementGenerator<Creature>::SetTargetLocation(Creature* owner)
{
if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
{ // if we are ROOT/STUNNED/DISTRACTED even after aura clear, finalize on next update - otherwise we would get stuck in evade
- skipToHome = true;
+ _skipToHome = true;
return;
}
@@ -60,14 +55,55 @@ void HomeMovementGenerator<Creature>::_setTargetLocation(Creature* owner)
init.SetWalk(false);
init.Launch();
- skipToHome = false;
- arrived = false;
+ _skipToHome = false;
+ _arrived = false;
owner->ClearUnitState(UNIT_STATE_ALL_ERASABLE & ~UNIT_STATE_EVADE);
}
-bool HomeMovementGenerator<Creature>::DoUpdate(Creature* owner, const uint32 /*time_diff*/)
+template<class T>
+void HomeMovementGenerator<T>::DoInitialize(T*) { }
+
+template<>
+void HomeMovementGenerator<Creature>::DoInitialize(Creature* owner)
+{
+ SetTargetLocation(owner);
+}
+
+template<class T>
+void HomeMovementGenerator<T>::DoFinalize(T*) { }
+
+template<>
+void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner)
+{
+ if (_arrived)
+ {
+ owner->ClearUnitState(UNIT_STATE_EVADE);
+ owner->SetWalk(true);
+ owner->LoadCreaturesAddon();
+ owner->AI()->JustReachedHome();
+ owner->SetSpawnHealth();
+ }
+}
+
+template<class T>
+void HomeMovementGenerator<T>::DoReset(T*) { }
+
+template<>
+void HomeMovementGenerator<Creature>::DoReset(Creature* owner)
+{
+ DoInitialize(owner);
+}
+
+template<class T>
+bool HomeMovementGenerator<T>::DoUpdate(T*, uint32)
+{
+ return false;
+}
+
+template<>
+bool HomeMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 /*diff*/)
{
- arrived = skipToHome || owner->movespline->Finalized();
- return !arrived;
+ _arrived = _skipToHome || owner->movespline->Finalized();
+ return !_arrived;
}
diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h
index d3489a249f3..5e1c25d9361 100644
--- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h
@@ -20,28 +20,26 @@
#include "MovementGenerator.h"
-class Creature;
-
-template < class T >
-class HomeMovementGenerator;
-
-template <>
-class HomeMovementGenerator<Creature> : public MovementGeneratorMedium< Creature, HomeMovementGenerator<Creature> >
+template <class T>
+class HomeMovementGenerator : public MovementGeneratorMedium< T, HomeMovementGenerator<T> >
{
public:
+ explicit HomeMovementGenerator() : _path(nullptr), _arrived(false), _skipToHome(false) { }
+ ~HomeMovementGenerator();
- HomeMovementGenerator() : arrived(false), skipToHome(false) { }
- ~HomeMovementGenerator() { }
-
- void DoInitialize(Creature*);
- void DoFinalize(Creature*);
- void DoReset(Creature*);
- bool DoUpdate(Creature*, const uint32);
MovementGeneratorType GetMovementGeneratorType() const override { return HOME_MOTION_TYPE; }
+ void DoInitialize(T*);
+ void DoFinalize(T*);
+ void DoReset(T*);
+ bool DoUpdate(T*, uint32);
+
private:
- void _setTargetLocation(Creature*);
- bool arrived;
- bool skipToHome;
+ void SetTargetLocation(T*);
+
+ PathGenerator* _path;
+ bool _arrived;
+ bool _skipToHome;
};
+
#endif
diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp
index 811dc54fa79..76b1aca3cc2 100644
--- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp
@@ -35,6 +35,8 @@ void IdleMovementGenerator::Reset(Unit* owner)
owner->StopMoving();
}
+//----------------------------------------------------//
+
void RotateMovementGenerator::Initialize(Unit* owner)
{
if (!owner->IsStopped())
@@ -50,27 +52,29 @@ void RotateMovementGenerator::Initialize(Unit* owner)
bool RotateMovementGenerator::Update(Unit* owner, uint32 diff)
{
float angle = owner->GetOrientation();
- angle += (float(diff) * static_cast<float>(M_PI * 2) / m_maxDuration) * (m_direction == ROTATE_DIRECTION_LEFT ? 1.0f : -1.0f);
+ angle += (float(diff) * static_cast<float>(M_PI * 2) / _maxDuration) * (_direction == ROTATE_DIRECTION_LEFT ? 1.0f : -1.0f);
angle = G3D::wrap(angle, 0.0f, float(G3D::twoPi()));
owner->SetOrientation(angle); // UpdateSplinePosition does not set orientation with UNIT_STATE_ROTATING
owner->SetFacingTo(angle); // Send spline movement to clients
- if (m_duration > diff)
- m_duration -= diff;
+ if (_duration > diff)
+ _duration -= diff;
else
return false;
return true;
}
-void RotateMovementGenerator::Finalize(Unit* unit)
+void RotateMovementGenerator::Finalize(Unit* owner)
{
- unit->ClearUnitState(UNIT_STATE_ROTATING);
- if (unit->GetTypeId() == TYPEID_UNIT)
- unit->ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, 0);
+ owner->ClearUnitState(UNIT_STATE_ROTATING);
+ if (owner->GetTypeId() == TYPEID_UNIT)
+ owner->ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, 0);
}
+//----------------------------------------------------//
+
void DistractMovementGenerator::Initialize(Unit* owner)
{
// Distracted creatures stand up if not standing
@@ -92,17 +96,19 @@ void DistractMovementGenerator::Finalize(Unit* owner)
}
}
-bool DistractMovementGenerator::Update(Unit* /*owner*/, uint32 time_diff)
+bool DistractMovementGenerator::Update(Unit* /*owner*/, uint32 diff)
{
- if (time_diff > m_timer)
+ if (diff > _timer)
return false;
- m_timer -= time_diff;
+ _timer -= diff;
return true;
}
-void AssistanceDistractMovementGenerator::Finalize(Unit* unit)
+//----------------------------------------------------//
+
+void AssistanceDistractMovementGenerator::Finalize(Unit* owner)
{
- unit->ClearUnitState(UNIT_STATE_DISTRACTED);
- unit->ToCreature()->SetReactState(REACT_AGGRESSIVE);
+ owner->ClearUnitState(UNIT_STATE_DISTRACTED);
+ owner->ToCreature()->SetReactState(REACT_AGGRESSIVE);
}
diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h
index 022bda5a394..9bb58419433 100755
--- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h
@@ -19,11 +19,11 @@
#define TRINITY_IDLEMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
+#include "Timer.h"
class IdleMovementGenerator : public MovementGenerator
{
public:
-
void Initialize(Unit*) override;
void Finalize(Unit*) override { }
void Reset(Unit*) override;
@@ -36,7 +36,7 @@ TC_GAME_API extern IdleMovementGenerator si_idleMovement;
class RotateMovementGenerator : public MovementGenerator
{
public:
- explicit RotateMovementGenerator(uint32 time, RotateDirection direction) : m_duration(time), m_maxDuration(time), m_direction(direction) { }
+ explicit RotateMovementGenerator(uint32 time, RotateDirection direction) : _duration(time), _maxDuration(time), _direction(direction) { }
void Initialize(Unit*) override;
void Finalize(Unit*) override;
@@ -45,14 +45,14 @@ class RotateMovementGenerator : public MovementGenerator
MovementGeneratorType GetMovementGeneratorType() const override { return ROTATE_MOTION_TYPE; }
private:
- uint32 m_duration, m_maxDuration;
- RotateDirection m_direction;
+ uint32 _duration, _maxDuration;
+ RotateDirection _direction;
};
class DistractMovementGenerator : public MovementGenerator
{
public:
- explicit DistractMovementGenerator(uint32 timer) : m_timer(timer) { }
+ explicit DistractMovementGenerator(uint32 timer) : _timer(timer) { }
void Initialize(Unit*) override;
void Finalize(Unit*) override;
@@ -61,14 +61,13 @@ class DistractMovementGenerator : public MovementGenerator
MovementGeneratorType GetMovementGeneratorType() const override { return DISTRACT_MOTION_TYPE; }
private:
- uint32 m_timer;
+ uint32 _timer;
};
class AssistanceDistractMovementGenerator : public DistractMovementGenerator
{
public:
- AssistanceDistractMovementGenerator(uint32 timer) :
- DistractMovementGenerator(timer) { }
+ explicit AssistanceDistractMovementGenerator(uint32 timer) : DistractMovementGenerator(timer) { }
MovementGeneratorType GetMovementGeneratorType() const override { return ASSISTANCE_DISTRACT_MOTION_TYPE; }
void Finalize(Unit*) override;
diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp
index 3cf0711dc41..ff3a2699128 100755
--- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp
@@ -15,33 +15,42 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "PointMovementGenerator.h"
-#include "Errors.h"
-#include "Creature.h"
#include "CreatureAI.h"
-#include "World.h"
+#include "Creature.h"
+#include "CreatureGroups.h"
+#include "Player.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
-#include "Player.h"
-#include "CreatureGroups.h"
#include "ObjectAccessor.h"
+#include "World.h"
+#include "PointMovementGenerator.h"
//----- Point Movement Generator
+
template<class T>
-void PointMovementGenerator<T>::DoInitialize(T* unit)
+void PointMovementGenerator<T>::DoInitialize(T* owner)
{
- if (!unit->IsStopped())
- unit->StopMoving();
+ if (_movementId == EVENT_CHARGE_PREPATH)
+ {
+ owner->AddUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
+ return;
+ }
- unit->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ owner->AddUnitState(UNIT_STATE_ROAMING);
- if (id == EVENT_CHARGE_PREPATH)
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
+ {
+ _interrupt = true;
+ owner->StopMoving();
return;
+ }
- Movement::MoveSplineInit init(unit);
- init.MoveTo(i_x, i_y, i_z, m_generatePath);
- if (speed > 0.0f)
- init.SetVelocity(speed);
+ owner->AddUnitState(UNIT_STATE_ROAMING_MOVE);
+
+ Movement::MoveSplineInit init(owner);
+ init.MoveTo(_destination.GetPositionX(), _destination.GetPositionY(), _destination.GetPositionZ(), _generatePath);
+ if (_speed > 0.0f)
+ init.SetVelocity(_speed);
if (i_faceTarget)
init.SetFacing(i_faceTarget);
if (i_spellEffectExtra)
@@ -49,69 +58,73 @@ void PointMovementGenerator<T>::DoInitialize(T* unit)
init.Launch();
// Call for creature group update
- if (Creature* creature = unit->ToCreature())
+ if (Creature* creature = owner->ToCreature())
if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature)
- creature->GetFormation()->LeaderMoveTo(i_x, i_y, i_z);
+ creature->GetFormation()->LeaderMoveTo(_destination, _movementId);
}
template<class T>
-bool PointMovementGenerator<T>::DoUpdate(T* unit, uint32 /*diff*/)
+bool PointMovementGenerator<T>::DoUpdate(T* owner, uint32 /*diff*/)
{
- if (!unit)
+ if (!owner)
return false;
- if (unit->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
+ if (_movementId == EVENT_CHARGE_PREPATH)
+ return !owner->movespline->Finalized();
+
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
{
- unit->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
+ _interrupt = true;
+ owner->StopMoving();
return true;
}
- unit->AddUnitState(UNIT_STATE_ROAMING_MOVE);
-
- if (id != EVENT_CHARGE_PREPATH && i_recalculateSpeed && !unit->movespline->Finalized())
+ if ((_interrupt && owner->movespline->Finalized()) || (_recalculateSpeed && !owner->movespline->Finalized()))
{
- i_recalculateSpeed = false;
- Movement::MoveSplineInit init(unit);
- 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);
+ _recalculateSpeed = false;
+ _interrupt = false;
+
+ owner->AddUnitState(UNIT_STATE_ROAMING_MOVE);
+
+ Movement::MoveSplineInit init(owner);
+ init.MoveTo(_destination.GetPositionX(), _destination.GetPositionY(), _destination.GetPositionZ(), _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();
// Call for creature group update
- if (Creature* creature = unit->ToCreature())
+ if (Creature* creature = owner->ToCreature())
if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature)
- creature->GetFormation()->LeaderMoveTo(i_x, i_y, i_z);
+ creature->GetFormation()->LeaderMoveTo(_destination, _movementId);
}
- return !unit->movespline->Finalized();
+ return !owner->movespline->Finalized();
}
template<class T>
-void PointMovementGenerator<T>::DoFinalize(T* unit)
+void PointMovementGenerator<T>::DoFinalize(T* owner)
{
- if (unit->HasUnitState(UNIT_STATE_CHARGING))
- unit->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
+ owner->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
- if (unit->movespline->Finalized())
- MovementInform(unit);
+ if (owner->movespline->Finalized())
+ MovementInform(owner);
}
template<class T>
-void PointMovementGenerator<T>::DoReset(T* unit)
+void PointMovementGenerator<T>::DoReset(T* owner)
{
- if (!unit->IsStopped())
- unit->StopMoving();
-
- unit->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ owner->StopMoving();
+ DoInitialize(owner);
}
template<class T>
-void PointMovementGenerator<T>::MovementInform(T* /*unit*/) { }
+void PointMovementGenerator<T>::MovementInform(T*) { }
-template <> void PointMovementGenerator<Creature>::MovementInform(Creature* unit)
+template <>
+void PointMovementGenerator<Creature>::MovementInform(Creature* owner)
{
- if (unit->AI())
- unit->AI()->MovementInform(POINT_MOTION_TYPE, id);
+ if (owner->AI())
+ owner->AI()->MovementInform(POINT_MOTION_TYPE, _movementId);
}
template void PointMovementGenerator<Player>::DoInitialize(Player*);
@@ -123,34 +136,36 @@ 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)
+//---- AssistanceMovementGenerator
+
+void AssistanceMovementGenerator::Finalize(Unit* owner)
+{
+ owner->ClearUnitState(UNIT_STATE_ROAMING);
+ owner->StopMoving();
+ owner->ToCreature()->SetNoCallAssistance(false);
+ owner->ToCreature()->CallAssistance();
+ if (owner->IsAlive())
+ owner->GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY));
+}
+
+//---- EffectMovementGenerator
+
+bool EffectMovementGenerator::Update(Unit* owner, uint32 /*diff*/)
{
- unit->ToCreature()->SetNoCallAssistance(false);
- unit->ToCreature()->CallAssistance();
- if (unit->IsAlive())
- unit->GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY));
+ return !owner->movespline->Finalized();
}
-bool EffectMovementGenerator::Update(Unit* unit, uint32)
+void EffectMovementGenerator::Finalize(Unit* owner)
{
- return !unit->movespline->Finalized();
+ MovementInform(owner);
}
-void EffectMovementGenerator::Finalize(Unit* unit)
+void EffectMovementGenerator::MovementInform(Unit* owner)
{
if (_arrivalSpellId)
- unit->CastSpell(ObjectAccessor::GetUnit(*unit, _arrivalSpellTargetGuid), _arrivalSpellId, true);
-
- if (unit->GetTypeId() != TYPEID_UNIT)
- return;
-
- // 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);
- }
+ owner->CastSpell(ObjectAccessor::GetUnit(*owner, _arrivalSpellTargetGuid), _arrivalSpellId, true);
- if (unit->ToCreature()->AI())
- unit->ToCreature()->AI()->MovementInform(EFFECT_MOTION_TYPE, _id);
+ if (Creature* creature = owner->ToCreature())
+ if (creature->AI())
+ creature->AI()->MovementInform(EFFECT_MOTION_TYPE, _pointId);
}
diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h
index 7b5451daa9e..18f552cc1cd 100644
--- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h
@@ -19,7 +19,6 @@
#define TRINITY_POINTMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
-#include "FollowerReference.h"
class Creature;
namespace Movement
@@ -31,56 +30,54 @@ template<class T>
class PointMovementGenerator : public MovementGeneratorMedium< T, PointMovementGenerator<T> >
{
public:
- PointMovementGenerator(uint32 _id, float _x, float _y, float _z, bool _generatePath, float _speed = 0.0f, Unit const* faceTarget = nullptr,
- Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr) : id(_id),
- i_x(_x), i_y(_y), i_z(_z), speed(_speed), i_faceTarget(faceTarget), i_spellEffectExtra(spellEffectExtraData),
- m_generatePath(_generatePath), i_recalculateSpeed(false) { }
+explicit PointMovementGenerator(uint32 id, float x, float y, float z, bool generatePath, float speed = 0.0f, Unit const* faceTarget = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr) : _movementId(id), _destination(x, y, z), _speed(speed), i_faceTarget(faceTarget), i_spellEffectExtra(spellEffectExtraData), _generatePath(generatePath), _recalculateSpeed(false), _interrupt(false) { }
+
+ MovementGeneratorType GetMovementGeneratorType() const override { return POINT_MOTION_TYPE; }
void DoInitialize(T*);
void DoFinalize(T*);
void DoReset(T*);
bool DoUpdate(T*, uint32);
- void MovementInform(T*);
-
- void unitSpeedChanged() override { i_recalculateSpeed = true; }
-
- MovementGeneratorType GetMovementGeneratorType() const override { return POINT_MOTION_TYPE; }
+ void UnitSpeedChanged() override { _recalculateSpeed = 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;
+ void MovementInform(T*);
+
+ uint32 _movementId;
+ Position _destination;
+ float _speed;
Unit const* i_faceTarget;
Movement::SpellEffectExtraData const* i_spellEffectExtra;
- bool m_generatePath;
- bool i_recalculateSpeed;
+ bool _generatePath;
+ bool _recalculateSpeed;
+ bool _interrupt;
};
class AssistanceMovementGenerator : public PointMovementGenerator<Creature>
{
public:
- AssistanceMovementGenerator(float _x, float _y, float _z) :
- PointMovementGenerator<Creature>(0, _x, _y, _z, true) { }
+ explicit AssistanceMovementGenerator(float _x, float _y, float _z) : PointMovementGenerator<Creature>(0, _x, _y, _z, true) { }
MovementGeneratorType GetMovementGeneratorType() const override { return ASSISTANCE_MOTION_TYPE; }
void Finalize(Unit*) override;
};
-// Does almost nothing - just doesn't allows previous movegen interrupt current effect.
class EffectMovementGenerator : public MovementGenerator
{
public:
- EffectMovementGenerator(uint32 id, uint32 arrivalSpellId = 0, ObjectGuid const& arrivalSpellTargetGuid = ObjectGuid::Empty)
- : _id(id), _arrivalSpellId(arrivalSpellId), _arrivalSpellTargetGuid(arrivalSpellTargetGuid) { }
+ explicit EffectMovementGenerator(uint32 id, uint32 arrivalSpellId = 0, ObjectGuid const& arrivalSpellTargetGuid = ObjectGuid::Empty) : _pointId(id), _arrivalSpellId(arrivalSpellId), _arrivalSpellTargetGuid(arrivalSpellTargetGuid) { }
+
void Initialize(Unit*) override { }
void Finalize(Unit*) override;
void Reset(Unit*) override { }
bool Update(Unit*, uint32) override;
MovementGeneratorType GetMovementGeneratorType() const override { return EFFECT_MOTION_TYPE; }
+
private:
- uint32 _id;
+ void MovementInform(Unit*);
+
+ uint32 _pointId;
uint32 _arrivalSpellId;
ObjectGuid _arrivalSpellTargetGuid;
};
diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
index 473e63447ed..7b0025d644f 100644
--- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
@@ -16,165 +16,133 @@
*/
#include "Creature.h"
-#include "RandomMovementGenerator.h"
-#include "Map.h"
-#include "Util.h"
#include "CreatureGroups.h"
+#include "Map.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
+#include "PathGenerator.h"
#include "Random.h"
+#include "RandomMovementGenerator.h"
-#define RUNNING_CHANCE_RANDOMMV 20 //will be "1 / RUNNING_CHANCE_RANDOMMV"
+template<class T>
+RandomMovementGenerator<T>::~RandomMovementGenerator() { }
template<>
-void RandomMovementGenerator<Creature>::_setRandomLocation(Creature* creature)
+RandomMovementGenerator<Creature>::~RandomMovementGenerator()
{
- if (creature->IsMovementPreventedByCasting())
- {
- creature->CastStop();
+ delete _path;
+}
+
+template<class T>
+void RandomMovementGenerator<T>::DoInitialize(T*) { }
+
+template<>
+void RandomMovementGenerator<Creature>::DoInitialize(Creature* owner)
+{
+ if (!owner || !owner->IsAlive())
return;
- }
- float respX, respY, respZ, respO, destX, destY, destZ, travelDistZ;
- creature->GetHomePosition(respX, respY, respZ, respO);
- Map const* map = creature->GetMap();
+ owner->AddUnitState(UNIT_STATE_ROAMING);
+ owner->GetPosition(_reference.m_positionX, _reference.m_positionY, _reference.m_positionZ);
+ owner->StopMoving();
+
+ if (!_wanderDistance)
+ _wanderDistance = owner->GetRespawnRadius();
- // 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();
+ _timer.Reset(0);
+}
- const float angle = float(rand_norm()) * static_cast<float>(M_PI*2.0f);
- const float range = float(rand_norm()) * wander_distance;
- const float distanceX = range * std::cos(angle);
- const float distanceY = range * std::sin(angle);
+template<class T>
+void RandomMovementGenerator<T>::DoFinalize(T*) { }
- destX = respX + distanceX;
- destY = respY + distanceY;
+template<>
+void RandomMovementGenerator<Creature>::DoFinalize(Creature* owner)
+{
+ owner->ClearUnitState(UNIT_STATE_ROAMING);
+ owner->StopMoving();
+ owner->SetWalk(false);
+}
- // prevent invalid coordinates generation
- Trinity::NormalizeMapCoord(destX);
- Trinity::NormalizeMapCoord(destY);
+template<class T>
+void RandomMovementGenerator<T>::DoReset(T*) { }
- travelDistZ = range; // sin^2+cos^2=1, so travelDistZ=range^2; no need for sqrt below
+template<>
+void RandomMovementGenerator<Creature>::DoReset(Creature* owner)
+{
+ DoInitialize(owner);
+}
- if (is_air_ok) // 3D system above ground and above water (flying mode)
- {
- // Limit height change
- const float distanceZ = float(rand_norm()) * travelDistZ/2.0f;
- destZ = respZ + distanceZ;
- float levelZ = map->GetWaterOrGroundLevel(creature->GetPhaseShift(), destX, destY, destZ-2.5f);
-
- // Problem here, we must fly above the ground and water, not under. Let's try on next tick
- if (levelZ >= destZ)
- return;
- }
- //else if (is_water_ok) // 3D system under water and above ground (swimming mode)
- else // 2D only
- {
- // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE)
- travelDistZ = travelDistZ >= 10.0f ? 10.0f : travelDistZ;
-
- // 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->GetPhaseShift(), destX, destY, respZ+travelDistZ-2.0f, false);
-
- if (std::fabs(destZ - respZ) > travelDistZ) // Map check
- {
- // Vmap Horizontal or above
- destZ = map->GetHeight(creature->GetPhaseShift(), destX, destY, respZ - 2.0f, true);
-
- if (std::fabs(destZ - respZ) > travelDistZ)
- {
- // Vmap Higher
- destZ = map->GetHeight(creature->GetPhaseShift(), 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 (std::fabs(destZ - respZ) > travelDistZ)
- return;
- }
- }
- }
+template<class T>
+void RandomMovementGenerator<T>::SetRandomLocation(T*) { }
- if (is_air_ok)
- i_nextMoveTime.Reset(0);
- else
+template<>
+void RandomMovementGenerator<Creature>::SetRandomLocation(Creature* owner)
+{
+ if (!owner)
+ return;
+
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
{
- if (roll_chance_i(50))
- i_nextMoveTime.Reset(urand(5000, 10000));
- else
- i_nextMoveTime.Reset(urand(50, 400));
+ _interrupt = true;
+ owner->StopMoving();
+ return;
}
- creature->AddUnitState(UNIT_STATE_ROAMING_MOVE);
+ owner->AddUnitState(UNIT_STATE_ROAMING_MOVE);
- Movement::MoveSplineInit init(creature);
- init.MoveTo(destX, destY, destZ);
- init.SetWalk(true);
- init.Launch();
+ Position position(_reference);
+ float distance = frand(0.f, 1.f) * _wanderDistance;
+ float angle = frand(0.f, 1.f) * float(M_PI) * 2.f;
+ owner->MovePositionToFirstCollision(position, distance, angle);
- //Call for creature group update
- if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature)
- creature->GetFormation()->LeaderMoveTo(destX, destY, destZ);
-}
+ uint32 resetTimer = roll_chance_i(50) ? urand(5000, 10000) : urand(1000, 2000);
-template<>
-void RandomMovementGenerator<Creature>::DoInitialize(Creature* creature)
-{
- if (!creature->IsAlive())
+ if (!_path)
+ _path = new PathGenerator(owner);
+
+ _path->SetPathLengthLimit(30.0f);
+ bool result = _path->CalculatePath(position.GetPositionX(), position.GetPositionY(), position.GetPositionZ());
+ if (!result || (_path->GetPathType() & PATHFIND_NOPATH))
+ {
+ _timer.Reset(100);
return;
+ }
- if (!wander_distance)
- wander_distance = creature->GetRespawnRadius();
+ Movement::MoveSplineInit init(owner);
+ init.MovebyPath(_path->GetPath());
+ init.SetWalk(true);
+ int32 traveltime = init.Launch();
+ _timer.Reset(traveltime + resetTimer);
- creature->AddUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
- _setRandomLocation(creature);
+ // Call for creature group update
+ if (owner->GetFormation() && owner->GetFormation()->getLeader() == owner)
+ owner->GetFormation()->LeaderMoveTo(position);
}
-template<>
-void RandomMovementGenerator<Creature>::DoReset(Creature* creature)
+template<class T>
+bool RandomMovementGenerator<T>::DoUpdate(T*, uint32)
{
- DoInitialize(creature);
+ return false;
}
template<>
-void RandomMovementGenerator<Creature>::DoFinalize(Creature* creature)
+bool RandomMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff)
{
- creature->ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
- creature->SetWalk(false);
-}
-
-template<>
-bool RandomMovementGenerator<Creature>::DoUpdate(Creature* creature, const uint32 diff)
-{
- if (!creature || !creature->IsAlive())
+ if (!owner || !owner->IsAlive())
return false;
- if (creature->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
{
- i_nextMoveTime.Reset(0); // Expire the timer
- creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
+ _interrupt = true;
+ owner->StopMoving();
return true;
}
+ else
+ _interrupt = false;
- if (creature->movespline->Finalized())
- {
- i_nextMoveTime.Update(diff);
- if (i_nextMoveTime.Passed())
- _setRandomLocation(creature);
- }
- return true;
-}
-
-template<>
-bool RandomMovementGenerator<Creature>::GetResetPos(Creature* creature, float& x, float& y, float& z)
-{
- float radius;
- creature->GetRespawnPosition(x, y, z, NULL, &radius);
-
- // use current if in range
- if (creature->IsWithinDist2d(x, y, radius))
- creature->GetPosition(x, y, z);
+ _timer.Update(diff);
+ if (!_interrupt && _timer.Passed() && owner->movespline->Finalized())
+ SetRandomLocation(owner);
return true;
}
diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
index 080c594ea01..a615bec49bc 100644
--- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
@@ -19,23 +19,30 @@
#define TRINITY_RANDOMMOTIONGENERATOR_H
#include "MovementGenerator.h"
+#include "Timer.h"
template<class T>
class RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovementGenerator<T> >
{
public:
- RandomMovementGenerator(float spawn_dist = 0.0f) : i_nextMoveTime(0), wander_distance(spawn_dist) { }
+ explicit RandomMovementGenerator(float distance = 0.0f) : _path(nullptr), _timer(0), _reference(0.f, 0.f, 0.f), _wanderDistance(distance), _interrupt(false) { }
+ ~RandomMovementGenerator();
+
+ MovementGeneratorType GetMovementGeneratorType() const override { return RANDOM_MOTION_TYPE; }
- 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() const override { return RANDOM_MOTION_TYPE; }
+ bool DoUpdate(T*, uint32);
+
private:
- TimeTrackerSmall i_nextMoveTime;
+ void SetRandomLocation(T*);
- float wander_distance;
+ PathGenerator* _path;
+ TimeTracker _timer;
+ Position _reference;
+ float _wanderDistance;
+ bool _interrupt;
};
+
#endif
diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
index 54cc97ab418..5c8eb721e18 100755
--- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
@@ -15,226 +15,210 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "ByteBuffer.h"
-#include "TargetedMovementGenerator.h"
-#include "Errors.h"
-#include "Creature.h"
#include "CreatureAI.h"
-#include "World.h"
-#include "MoveSplineInit.h"
-#include "MoveSpline.h"
+#include "Creature.h"
#include "Player.h"
#include "VehicleDefines.h"
+#include "MoveSplineInit.h"
+#include "MoveSpline.h"
+#include "PathGenerator.h"
+#include "World.h"
+#include "TargetedMovementGenerator.h"
template<class T, typename D>
-void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T* owner, bool updateDestination)
+TargetedMovementGenerator<T, D>::~TargetedMovementGenerator()
{
- if (!i_target.isValid() || !i_target->IsInWorld())
- return;
+ delete _path;
+}
+
+template<class T, typename D>
+bool TargetedMovementGenerator<T, D>::DoUpdate(T* owner, uint32 diff)
+{
+ if (!IsTargetValid() || !GetTarget()->IsInWorld())
+ return false;
+
+ if (!owner || !owner->IsAlive())
+ return false;
+
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting() || HasLostTarget(owner))
+ {
+ _interrupt = true;
+ owner->StopMoving();
+ return true;
+ }
+
+ if (_interrupt || _recalculateTravel)
+ {
+ _interrupt = false;
+ SetTargetLocation(owner, true);
+ return true;
+ }
+
+ bool targetMoved = false;
+ _timer.Update(diff);
+ if (!_interrupt && _timer.Passed())
+ {
+ _timer.Reset(100);
+
+ float distance = owner->GetCombatReach() + sWorld->getRate(RATE_TARGET_POS_RECALCULATION_RANGE);
+ if (owner->IsPet() && (owner->GetCharmerOrOwnerGUID() == GetTarget()->GetGUID()))
+ distance = 1.f; // pet following owner
+
+ G3D::Vector3 destination = owner->movespline->FinalDestination();
+ if (owner->movespline->onTransport)
+ if (TransportBase* transport = owner->GetDirectTransport())
+ transport->CalculatePassengerPosition(destination.x, destination.y, destination.z);
+
+ // First check distance
+ if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->CanFly())
+ targetMoved = !GetTarget()->IsWithinDist3d(destination.x, destination.y, destination.z, distance);
+ else
+ targetMoved = !GetTarget()->IsWithinDist2d(destination.x, destination.y, distance);
+
+ // then, if the target is in range, check also Line of Sight.
+ if (!targetMoved)
+ targetMoved = !GetTarget()->IsWithinLOSInMap(owner);
+ }
+
+ if (targetMoved)
+ SetTargetLocation(owner, true);
+ else if (_speedChanged)
+ SetTargetLocation(owner, false);
+
+ if (!_targetReached && owner->movespline->Finalized())
+ {
+ MovementInform(owner);
+ if (_angle == 0.f && !owner->HasInArc(0.01f, GetTarget()))
+ owner->SetInFront(GetTarget());
+
+ if (!_targetReached)
+ {
+ _targetReached = true;
+ ReachTarget(owner);
+ }
+ }
- if (owner->HasUnitState(UNIT_STATE_NOT_MOVE))
+ return true;
+}
+
+template<class T, typename D>
+void TargetedMovementGenerator<T, D>::SetTargetLocation(T* owner, bool updateDestination)
+{
+ if (!IsTargetValid() || !GetTarget()->IsInWorld())
return;
- if (owner->IsMovementPreventedByCasting())
+ if (!owner || !owner->IsAlive())
return;
- if (owner->GetTypeId() == TYPEID_UNIT && !i_target->isInAccessiblePlaceFor(owner->ToCreature()))
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting() || HasLostTarget(owner))
{
- owner->ToCreature()->SetCannotReachTarget(true);
+ _interrupt = true;
+ owner->StopMoving();
return;
}
- if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsFocusing(nullptr, true))
+ if (owner->GetTypeId() == TYPEID_UNIT && !GetTarget()->isInAccessiblePlaceFor(owner->ToCreature()))
+ {
+ owner->ToCreature()->SetCannotReachTarget(true);
return;
+ }
float x, y, z;
-
- if (updateDestination || !i_path)
+ if (updateDestination || !_path)
{
- if (!i_offset)
+ if (!_offset)
{
- if (i_target->IsWithinDistInMap(owner, CONTACT_DISTANCE))
+ if (GetTarget()->IsWithinDistInMap(owner, CONTACT_DISTANCE))
return;
- // to nearest contact position
- i_target->GetContactPoint(owner, x, y, z);
+ GetTarget()->GetContactPoint(owner, x, y, z);
}
else
{
- float dist;
- float size;
-
- // Pets need special handling.
- // We need to subtract GetCombatReach() 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 = 1.0f; //i_target->GetCombatReach();
- size = 1.0f; //i_target->GetCombatReach() - i_target->GetCombatReach();
- }
- else
+ float distance = _offset + 1.0f;
+ float size = owner->GetCombatReach();
+
+ if (owner->IsPet() && GetTarget()->GetTypeId() == TYPEID_PLAYER)
{
- dist = i_offset + 1.0f;
- size = owner->GetCombatReach();
+ distance = 1.0f;
+ size = 1.0f;
}
- if (i_target->IsWithinDistInMap(owner, dist))
+ if (GetTarget()->IsWithinDistInMap(owner, distance))
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);
+ GetTarget()->GetClosePoint(x, y, z, size, _offset, _angle);
}
}
else
{
// the destination has not changed, we just need to refresh the path (usually speed change)
- G3D::Vector3 end = i_path->GetEndPosition();
+ G3D::Vector3 end = _path->GetEndPosition();
x = end.x;
y = end.y;
z = end.z;
}
- if (!i_path)
- i_path = new PathGenerator(owner);
+ if (!_path)
+ _path = new PathGenerator(owner);
// 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));
+ bool forceDest = (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsPet() && owner->HasUnitState(UNIT_STATE_FOLLOW));
- bool result = i_path->CalculatePath(x, y, z, forceDest);
- if (!result || (i_path->GetPathType() & PATHFIND_NOPATH))
+ bool result = _path->CalculatePath(x, y, z, forceDest);
+ if (!result || (_path->GetPathType() & PATHFIND_NOPATH))
{
// can't reach target
- i_recalculateTravel = true;
+ _recalculateTravel = true;
if (owner->GetTypeId() == TYPEID_UNIT)
owner->ToCreature()->SetCannotReachTarget(true);
return;
}
- D::_addUnitStateMove(owner);
- i_targetReached = false;
- i_recalculateTravel = false;
- owner->AddUnitState(UNIT_STATE_CHASE);
+ _targetReached = false;
+ _recalculateTravel = false;
+ _speedChanged = false;
+
+ AddUnitStateMove(owner);
+
if (owner->GetTypeId() == TYPEID_UNIT)
owner->ToCreature()->SetCannotReachTarget(false);
Movement::MoveSplineInit init(owner);
- init.MovebyPath(i_path->GetPath());
- init.SetWalk(((D*)this)->EnableWalking());
+ init.MovebyPath(_path->GetPath());
+ init.SetWalk(EnableWalking());
// Using the same condition for facing target as the one that is used for SetInFront on movement end
// - applies to ChaseMovementGenerator mostly
- if (i_angle == 0.f)
- init.SetFacing(i_target.getTarget());
+ if (_angle == 0.f)
+ init.SetFacing(GetTarget());
init.Launch();
}
template<class T, typename D>
-bool TargetedMovementGeneratorMedium<T, D>::DoUpdate(T* owner, uint32 time_diff)
+bool TargetedMovementGenerator<T, D>::IsReachable() const
{
- if (!i_target.isValid() || !i_target->IsInWorld())
- return false;
-
- if (!owner || !owner->IsAlive())
- return false;
-
- 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->IsMovementPreventedByCasting())
- {
- if (!owner->IsStopped())
- owner->StopMoving();
- return true;
- }
-
- // prevent crash after creature killed pet
- if (static_cast<D*>(this)->_lostTarget(owner))
- {
- D::_clearUnitStateMove(owner);
- return true;
- }
-
- bool targetMoved = false;
- i_recheckDistance.Update(time_diff);
- if (i_recheckDistance.Passed())
- {
- i_recheckDistance.Reset(100);
-
- //More distance let have better performance, less distance let have more sensitive reaction at target move.
- float allowed_dist = 0.0f;
-
- if (owner->IsPet() && (owner->GetCharmerOrOwnerGUID() == i_target->GetGUID()))
- allowed_dist = 1.0f; // pet following owner
- else
- allowed_dist = owner->GetCombatReach() + sWorld->getRate(RATE_TARGET_POS_RECALCULATION_RANGE);
-
- G3D::Vector3 dest = owner->movespline->FinalDestination();
- if (owner->movespline->onTransport)
- if (TransportBase* transport = owner->GetDirectTransport())
- transport->CalculatePassengerPosition(dest.x, dest.y, dest.z);
-
- // First check distance
- if (owner->GetTypeId() == TYPEID_UNIT && (owner->ToCreature()->CanFly() || owner->ToCreature()->CanSwim()))
- targetMoved = !i_target->IsWithinDist3d(dest.x, dest.y, dest.z, allowed_dist);
- else
- targetMoved = !i_target->IsWithinDist2d(dest.x, dest.y, allowed_dist);
-
- // then, if the target is in range, check also Line of Sight.
- if (!targetMoved)
- targetMoved = !i_target->IsWithinLOSInMap(owner);
- }
-
- 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_targetReached)
- {
- i_targetReached = true;
- static_cast<D*>(this)->_reachTarget(owner);
- }
- }
-
- return true;
+ return (_path) ? (_path->GetPathType() & PATHFIND_NORMAL) : true;
}
-//-----------------------------------------------//
+//---- ChaseMovementGenerator
+
template<class T>
-void ChaseMovementGenerator<T>::_reachTarget(T* owner)
-{
- _clearUnitStateMove(owner);
- if (owner->IsWithinMeleeRange(this->i_target.getTarget()))
- owner->Attack(this->i_target.getTarget(), true);
- if (owner->GetTypeId() == TYPEID_UNIT)
- owner->ToCreature()->SetCannotReachTarget(false);
-}
+void ChaseMovementGenerator<T>::DoInitialize(T*) { }
template<>
void ChaseMovementGenerator<Player>::DoInitialize(Player* owner)
{
- owner->AddUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE);
- _setTargetLocation(owner, true);
+ owner->AddUnitState(UNIT_STATE_CHASE);
+ SetTargetLocation(owner, true);
}
template<>
void ChaseMovementGenerator<Creature>::DoInitialize(Creature* owner)
{
owner->SetWalk(false);
- owner->AddUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE);
- _setTargetLocation(owner, true);
+ owner->AddUnitState(UNIT_STATE_CHASE);
+ SetTargetLocation(owner, true);
}
template<class T>
@@ -250,41 +234,60 @@ void ChaseMovementGenerator<T>::DoReset(T* owner)
}
template<class T>
-void ChaseMovementGenerator<T>::MovementInform(T* /*unit*/) { }
+void ChaseMovementGenerator<T>::ClearUnitStateMove(T* owner)
+{
+ owner->ClearUnitState(UNIT_STATE_CHASE_MOVE);
+}
-template<>
-void ChaseMovementGenerator<Creature>::MovementInform(Creature* unit)
+template<class T>
+void ChaseMovementGenerator<T>::AddUnitStateMove(T* owner)
{
- // 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()->GetGUID().GetCounter());
+ owner->AddUnitState(UNIT_STATE_CHASE_MOVE);
}
-//-----------------------------------------------//
-template<>
-bool FollowMovementGenerator<Creature>::EnableWalking() const
+template<class T>
+bool ChaseMovementGenerator<T>::HasLostTarget(T* owner) const
{
- return i_target.isValid() && i_target->IsWalking();
+ return owner->GetVictim() != TargetedMovementGeneratorBase::GetTarget();
}
-template<>
-bool FollowMovementGenerator<Player>::EnableWalking() const
+template<class T>
+void ChaseMovementGenerator<T>::ReachTarget(T* owner)
{
- return false;
+ ClearUnitStateMove(owner);
+
+ if (owner->IsWithinMeleeRange(TargetedMovementGeneratorBase::GetTarget()))
+ owner->Attack(TargetedMovementGeneratorBase::GetTarget(), true);
+
+ if (owner->GetTypeId() == TYPEID_UNIT)
+ owner->ToCreature()->SetCannotReachTarget(false);
}
+template<class T>
+void ChaseMovementGenerator<T>::MovementInform(T*) { }
+
template<>
-void FollowMovementGenerator<Player>::_updateSpeed(Player* /*owner*/)
+void ChaseMovementGenerator<Creature>::MovementInform(Creature* owner)
{
- // nothing to do for Player
+ // Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
+ if (owner->AI())
+ owner->AI()->MovementInform(CHASE_MOTION_TYPE, GetTarget()->GetGUID().GetCounter());
}
+//---- FollowMovementGenerator
+
+template<class T>
+void FollowMovementGenerator<T>::UpdateSpeed(T*) { }
+
+template<>
+void FollowMovementGenerator<Player>::UpdateSpeed(Player* /*owner*/) { }
+
template<>
-void FollowMovementGenerator<Creature>::_updateSpeed(Creature* owner)
+void FollowMovementGenerator<Creature>::UpdateSpeed(Creature* owner)
{
- // pet only sync speed with owner
- /// 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())
+ // Pet only sync speed with owner
+ // Make sure we are not in the process of a map change (IsInWorld)
+ if (!owner->IsPet() || !owner->IsInWorld() || !IsTargetValid() || GetTarget()->GetGUID() != owner->GetOwnerGUID())
return;
owner->UpdateSpeed(MOVE_RUN);
@@ -292,27 +295,19 @@ void FollowMovementGenerator<Creature>::_updateSpeed(Creature* owner)
owner->UpdateSpeed(MOVE_SWIM);
}
-template<>
-void FollowMovementGenerator<Player>::DoInitialize(Player* owner)
-{
- owner->AddUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE);
- _updateSpeed(owner);
- _setTargetLocation(owner, true);
-}
-
-template<>
-void FollowMovementGenerator<Creature>::DoInitialize(Creature* owner)
+template<class T>
+void FollowMovementGenerator<T>::DoInitialize(T* owner)
{
- owner->AddUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE);
- _updateSpeed(owner);
- _setTargetLocation(owner, true);
+ owner->AddUnitState(UNIT_STATE_FOLLOW);
+ UpdateSpeed(owner);
+ TargetedMovementGenerator<T, FollowMovementGenerator<T>>::SetTargetLocation(owner, true);
}
template<class T>
void FollowMovementGenerator<T>::DoFinalize(T* owner)
{
owner->ClearUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE);
- _updateSpeed(owner);
+ UpdateSpeed(owner);
}
template<class T>
@@ -322,36 +317,85 @@ void FollowMovementGenerator<T>::DoReset(T* owner)
}
template<class T>
-void FollowMovementGenerator<T>::MovementInform(T* /*unit*/) { }
+void FollowMovementGenerator<T>::ClearUnitStateMove(T* owner)
+{
+ owner->ClearUnitState(UNIT_STATE_FOLLOW_MOVE);
+}
+
+template<class T>
+void FollowMovementGenerator<T>::AddUnitStateMove(T* owner)
+{
+ owner->AddUnitState(UNIT_STATE_FOLLOW_MOVE);
+}
+
+template<class T>
+void FollowMovementGenerator<T>::ReachTarget(T* owner)
+{
+ ClearUnitStateMove(owner);
+}
+
+template<>
+bool FollowMovementGenerator<Creature>::EnableWalking() const
+{
+ return IsTargetValid() && GetTarget()->IsWalking();
+}
+
+template<>
+bool FollowMovementGenerator<Player>::EnableWalking() const
+{
+ return false;
+}
+
+template<class T>
+void FollowMovementGenerator<T>::MovementInform(T*) { }
template<>
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()->GetGUID().GetCounter());
+ unit->AI()->MovementInform(FOLLOW_MOTION_TYPE, GetTarget()->GetGUID().GetCounter());
}
//-----------------------------------------------//
-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 TargetedMovementGenerator<Player, ChaseMovementGenerator<Player> >::~TargetedMovementGenerator();
+template TargetedMovementGenerator<Player, FollowMovementGenerator<Player> >::~TargetedMovementGenerator();
+template TargetedMovementGenerator<Creature, ChaseMovementGenerator<Creature> >::~TargetedMovementGenerator();
+template TargetedMovementGenerator<Creature, FollowMovementGenerator<Creature> >::~TargetedMovementGenerator();
+template bool TargetedMovementGenerator<Player, ChaseMovementGenerator<Player> >::DoUpdate(Player*, uint32);
+template bool TargetedMovementGenerator<Player, FollowMovementGenerator<Player> >::DoUpdate(Player*, uint32);
+template bool TargetedMovementGenerator<Creature, ChaseMovementGenerator<Creature> >::DoUpdate(Creature*, uint32);
+template bool TargetedMovementGenerator<Creature, FollowMovementGenerator<Creature> >::DoUpdate(Creature*, uint32);
+template void TargetedMovementGenerator<Player, ChaseMovementGenerator<Player> >::SetTargetLocation(Player*, bool);
+template void TargetedMovementGenerator<Player, FollowMovementGenerator<Player> >::SetTargetLocation(Player*, bool);
+template void TargetedMovementGenerator<Creature, ChaseMovementGenerator<Creature> >::SetTargetLocation(Creature*, bool);
+template void TargetedMovementGenerator<Creature, FollowMovementGenerator<Creature> >::SetTargetLocation(Creature*, bool);
+
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>::ClearUnitStateMove(Player*);
+template void ChaseMovementGenerator<Creature>::ClearUnitStateMove(Creature*);
+template void ChaseMovementGenerator<Player>::AddUnitStateMove(Player*);
+template void ChaseMovementGenerator<Creature>::AddUnitStateMove(Creature*);
+template bool ChaseMovementGenerator<Player>::HasLostTarget(Player*) const;
+template bool ChaseMovementGenerator<Creature>::HasLostTarget(Creature*) const;
+template void ChaseMovementGenerator<Player>::ReachTarget(Player*);
+template void ChaseMovementGenerator<Creature>::ReachTarget(Creature*);
template void ChaseMovementGenerator<Player>::MovementInform(Player*);
+template void FollowMovementGenerator<Player>::DoInitialize(Player*);
+template void FollowMovementGenerator<Creature>::DoInitialize(Creature*);
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>::ClearUnitStateMove(Player*);
+template void FollowMovementGenerator<Creature>::ClearUnitStateMove(Creature*);
+template void FollowMovementGenerator<Player>::AddUnitStateMove(Player*);
+template void FollowMovementGenerator<Creature>::AddUnitStateMove(Creature*);
+template void FollowMovementGenerator<Player>::ReachTarget(Player*);
+template void FollowMovementGenerator<Creature>::ReachTarget(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 79a1c7952db..9f4e3712b5c 100755
--- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h
@@ -21,95 +21,94 @@
#include "MovementGenerator.h"
#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)
+ {
+ _target.link(target, this);
+ }
+
+ bool IsTargetValid() const { return _target.isValid(); }
+ Unit* GetTarget() const { return _target.getTarget(); }
void stopFollowing() { }
- protected:
- FollowerReference i_target;
+
+ private:
+ FollowerReference _target;
};
template<class T, typename D>
-class TargetedMovementGeneratorMedium : public MovementGeneratorMedium< T, D >, public TargetedMovementGeneratorBase
+class TargetedMovementGenerator : public MovementGeneratorMedium< T, D >, public TargetedMovementGeneratorBase
{
- protected:
- 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() { delete i_path; }
-
public:
+ explicit TargetedMovementGenerator(Unit* target, float offset, float angle) : TargetedMovementGeneratorBase(target), _path(nullptr), _timer(0), _offset(offset), _angle(angle), _recalculateTravel(false), _speedChanged(false), _targetReached(false), _interrupt(false) { }
+ ~TargetedMovementGenerator();
+
bool DoUpdate(T*, uint32);
- Unit* GetTarget() const { return i_target.getTarget(); }
-
- void unitSpeedChanged() override { i_recalculateTravel = true; }
- bool IsReachable() const { return (i_path) ? (i_path->GetPathType() & PATHFIND_NORMAL) : true; }
- protected:
- void _setTargetLocation(T* owner, bool updateDestination);
-
- PathGenerator* i_path;
- TimeTrackerSmall i_recheckDistance;
- float i_offset;
- float i_angle;
- bool i_recalculateTravel : 1;
- bool i_targetReached : 1;
+
+ void UnitSpeedChanged() override { _speedChanged = true; }
+
+ virtual void ClearUnitStateMove(T*) { }
+ virtual void AddUnitStateMove(T*) { }
+ virtual bool HasLostTarget(T*) const { return false; }
+ virtual void ReachTarget(T*) { }
+ virtual bool EnableWalking() const { return false; }
+ virtual void MovementInform(T*) { }
+
+ bool IsReachable() const;
+ void SetTargetLocation(T* owner, bool updateDestination);
+
+ private:
+ PathGenerator* _path;
+ TimeTrackerSmall _timer;
+ float _offset;
+ float _angle;
+ bool _recalculateTravel;
+ bool _speedChanged;
+ bool _targetReached;
+ bool _interrupt;
};
template<class T>
-class ChaseMovementGenerator : public TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >
+class ChaseMovementGenerator : public TargetedMovementGenerator<T, ChaseMovementGenerator<T> >
{
public:
- ChaseMovementGenerator(Unit* target)
- : TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target) { }
- ChaseMovementGenerator(Unit* target, float offset, float angle)
- : TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target, offset, angle) { }
- ~ChaseMovementGenerator() { }
+ explicit ChaseMovementGenerator(Unit* target, float offset, float angle) : TargetedMovementGenerator<T, ChaseMovementGenerator<T> >(target, offset, angle) { }
MovementGeneratorType GetMovementGeneratorType() const override { return CHASE_MOTION_TYPE; }
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); }
- bool EnableWalking() const { return false;}
- bool _lostTarget(T* u) const { return u->GetVictim() != this->GetTarget(); }
- void _reachTarget(T*);
+ void ClearUnitStateMove(T*) override;
+ void AddUnitStateMove(T*) override;
+ bool HasLostTarget(T*) const override;
+ void ReachTarget(T*) override;
+ void MovementInform(T*) override;
};
template<class T>
-class FollowMovementGenerator : public TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >
+class FollowMovementGenerator : public TargetedMovementGenerator<T, FollowMovementGenerator<T> >
{
public:
- FollowMovementGenerator(Unit* target)
- : TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >(target){ }
- FollowMovementGenerator(Unit* target, float offset, float angle)
- : TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >(target, offset, angle) { }
- ~FollowMovementGenerator() { }
+ explicit FollowMovementGenerator(Unit* target, float offset, float angle) : TargetedMovementGenerator<T, FollowMovementGenerator<T> >(target, offset, angle) { }
MovementGeneratorType GetMovementGeneratorType() const override { return FOLLOW_MOTION_TYPE; }
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); }
- bool EnableWalking() const;
- bool _lostTarget(T*) const { return false; }
- void _reachTarget(T*) { }
+ void ClearUnitStateMove(T*) override;
+ void AddUnitStateMove(T*) override;
+ bool HasLostTarget(T*) const override { return false; }
+ void ReachTarget(T*) override;
+ bool EnableWalking() const override;
+ void MovementInform(T*) override;
private:
- void _updateSpeed(T* owner);
+ void UpdateSpeed(T* owner);
};
#endif
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index 9f07641d74d..0a01d7f3a96 100644
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -139,7 +139,7 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
creature->AddUnitState(UNIT_STATE_ROAMING_MOVE);
- Movement::Location formationDest(node->x, node->y, node->z, 0.0f);
+ Position formationDest(node->x, node->y, node->z, (node->orientation && node->delay) ? node->orientation : 0.0f);
Movement::MoveSplineInit init(creature);
//! If creature is on transport, we assume waypoints set in DB are already transport offsets
@@ -147,7 +147,11 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
{
init.DisableTransportPathTransformations();
if (TransportBase* trans = creature->GetDirectTransport())
- trans->CalculatePassengerPosition(formationDest.x, formationDest.y, formationDest.z, &formationDest.orientation);
+ {
+ float orientation = formationDest.GetOrientation();
+ trans->CalculatePassengerPosition(formationDest.m_positionX, formationDest.m_positionY, formationDest.m_positionZ, &orientation);
+ formationDest.SetOrientation(orientation);
+ }
}
//! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call
@@ -176,12 +180,9 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
init.Launch();
- //Call for creature group update
+ // Call for creature group update
if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature)
- {
- creature->SetWalk(node->move_type != WAYPOINT_MOVE_TYPE_RUN);
- creature->GetFormation()->LeaderMoveTo(formationDest.x, formationDest.y, formationDest.z);
- }
+ creature->GetFormation()->LeaderMoveTo(formationDest, node->id, node->move_type, (node->orientation && node->delay) ? true : false);
return true;
}
diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h
index 2023a4de8e8..da9d80dad63 100644
--- a/src/server/game/Quests/QuestDef.h
+++ b/src/server/game/Quests/QuestDef.h
@@ -224,7 +224,8 @@ enum QuestSpecialFlags
QUEST_SPECIAL_FLAGS_SPEAKTO = 0x100, // Internal flag computed only
QUEST_SPECIAL_FLAGS_KILL = 0x200, // Internal flag computed only
QUEST_SPECIAL_FLAGS_TIMED = 0x400, // Internal flag computed only
- QUEST_SPECIAL_FLAGS_PLAYER_KILL = 0x800 // Internal flag computed only
+ QUEST_SPECIAL_FLAGS_PLAYER_KILL = 0x800, // Internal flag computed only
+ QUEST_SPECIAL_FLAGS_COMPLETED_AT_START = 0x1000 // Internal flag computed only
};
enum QuestObjectiveType
@@ -497,7 +498,6 @@ class TC_GAME_API Quest
void BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player* player) const;
std::vector<uint32> DependentPreviousQuests;
- std::vector<uint32> PrevChainQuests;
WorldPacket QueryData[TOTAL_LOCALES];
private:
diff --git a/src/server/game/Reputation/ReputationMgr.cpp b/src/server/game/Reputation/ReputationMgr.cpp
index 1c362984ecc..b017947d56c 100644
--- a/src/server/game/Reputation/ReputationMgr.cpp
+++ b/src/server/game/Reputation/ReputationMgr.cpp
@@ -267,7 +267,7 @@ void ReputationMgr::Initialize()
}
}
-bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental, bool noSpillover)
+bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental, bool spillOverOnly, bool noSpillover)
{
sScriptMgr->OnPlayerReputationChange(_player, factionEntry->ID, standing, incremental);
bool res = false;
@@ -334,7 +334,10 @@ bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standi
FactionStateList::iterator faction = _factions.find(factionEntry->ReputationIndex);
if (faction != _factions.end())
{
- res = SetOneFactionReputation(factionEntry, standing, incremental);
+ // if we update spillover only, do not update main reputation (rank exceeds creature reward rate)
+ if (!spillOverOnly)
+ res = SetOneFactionReputation(factionEntry, standing, incremental);
+
// only this faction gets reported to client, even if it has no own visible standing
SendState(&faction->second);
}
diff --git a/src/server/game/Reputation/ReputationMgr.h b/src/server/game/Reputation/ReputationMgr.h
index 3ad0958107c..ffc9ad826b5 100644
--- a/src/server/game/Reputation/ReputationMgr.h
+++ b/src/server/game/Reputation/ReputationMgr.h
@@ -118,11 +118,11 @@ class TC_GAME_API ReputationMgr
public: // modifiers
bool SetReputation(FactionEntry const* factionEntry, int32 standing)
{
- return SetReputation(factionEntry, standing, false, false);
+ return SetReputation(factionEntry, standing, false, false, false);
}
- bool ModifyReputation(FactionEntry const* factionEntry, int32 standing, bool noSpillover = false)
+ bool ModifyReputation(FactionEntry const* factionEntry, int32 standing, bool spillOverOnly = false, bool noSpillover = false)
{
- return SetReputation(factionEntry, standing, true, noSpillover);
+ return SetReputation(factionEntry, standing, true, spillOverOnly, noSpillover);
}
void SetVisible(FactionTemplateEntry const* factionTemplateEntry);
@@ -144,7 +144,7 @@ class TC_GAME_API ReputationMgr
private: // internal helper functions
void Initialize();
uint32 GetDefaultStateFlags(FactionEntry const* factionEntry) const;
- bool SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental, bool noSpillover);
+ bool SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental, bool spillOverOnly, bool noSpillover);
void SetVisible(FactionState* faction);
void SetAtWar(FactionState* faction, bool atWar) const;
void SetInactive(FactionState* faction, bool inactive) const;
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index e9596c4fdd3..fea767fa9a5 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -1637,15 +1637,6 @@ InstanceScript* ScriptMgr::CreateInstanceData(InstanceMap* map)
return tmpscript->GetInstanceScript(map);
}
-bool ScriptMgr::OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, Item* target)
-{
- ASSERT(caster);
- ASSERT(target);
-
- GET_SCRIPT_RET(ItemScript, target->GetScriptId(), tmpscript, false);
- return tmpscript->OnDummyEffect(caster, spellId, effIndex, target);
-}
-
bool ScriptMgr::OnQuestAccept(Player* player, Item* item, Quest const* quest)
{
ASSERT(player);
@@ -1695,15 +1686,6 @@ bool ScriptMgr::OnCastItemCombatSpell(Player* player, Unit* victim, SpellInfo co
return tmpscript->OnCastItemCombatSpell(player, victim, spellInfo, item);
}
-bool ScriptMgr::OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, Creature* target)
-{
- ASSERT(caster);
- ASSERT(target);
-
- GET_SCRIPT_RET(CreatureScript, target->GetScriptId(), tmpscript, false);
- return tmpscript->OnDummyEffect(caster, spellId, effIndex, target);
-}
-
bool ScriptMgr::OnGossipHello(Player* player, Creature* creature)
{
ASSERT(player);
@@ -1920,15 +1902,6 @@ void ScriptMgr::OnGameObjectUpdate(GameObject* go, uint32 diff)
tmpscript->OnUpdate(go, diff);
}
-bool ScriptMgr::OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, GameObject* target)
-{
- ASSERT(caster);
- ASSERT(target);
-
- GET_SCRIPT_RET(GameObjectScript, target->GetScriptId(), tmpscript, false);
- return tmpscript->OnDummyEffect(caster, spellId, effIndex, target);
-}
-
bool ScriptMgr::OnAreaTrigger(Player* player, AreaTriggerEntry const* trigger, bool entered)
{
ASSERT(player);
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index 53465b1dca2..518cc5f4a70 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -374,9 +374,6 @@ class TC_GAME_API ItemScript : public ScriptObject
public:
- // Called when a dummy spell effect is triggered on the item.
- virtual bool OnDummyEffect(Unit* /*caster*/, uint32 /*spellId*/, SpellEffIndex /*effIndex*/, Item* /*target*/) { return false; }
-
// Called when a player accepts a quest from the item.
virtual bool OnQuestAccept(Player* /*player*/, Item* /*item*/, Quest const* /*quest*/) { return false; }
@@ -424,9 +421,6 @@ class TC_GAME_API CreatureScript : public UnitScript, public UpdatableScript<Cre
public:
- // Called when a dummy spell effect is triggered on the creature.
- virtual bool OnDummyEffect(Unit* /*caster*/, uint32 /*spellId*/, SpellEffIndex /*effIndex*/, Creature* /*target*/) { return false; }
-
// Called when a player opens a gossip dialog with the creature.
virtual bool OnGossipHello(Player* /*player*/, Creature* /*creature*/) { return false; }
@@ -463,9 +457,6 @@ class TC_GAME_API GameObjectScript : public ScriptObject, public UpdatableScript
public:
- // Called when a dummy spell effect is triggered on the gameobject.
- virtual bool OnDummyEffect(Unit* /*caster*/, uint32 /*spellId*/, SpellEffIndex /*effIndex*/, GameObject* /*target*/) { return false; }
-
// Called when a player opens a gossip dialog with the gameobject.
virtual bool OnGossipHello(Player* /*player*/, GameObject* /*go*/) { return false; }
@@ -1026,7 +1017,6 @@ class TC_GAME_API ScriptMgr
public: /* ItemScript */
- bool OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, Item* target);
bool OnQuestAccept(Player* player, Item* item, Quest const* quest);
bool OnItemUse(Player* player, Item* item, SpellCastTargets const& targets, ObjectGuid castId);
bool OnItemExpire(Player* player, ItemTemplate const* proto);
@@ -1035,7 +1025,6 @@ class TC_GAME_API ScriptMgr
public: /* CreatureScript */
- bool OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, Creature* target);
bool OnGossipHello(Player* player, Creature* creature);
bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action);
bool OnGossipSelectCode(Player* player, Creature* creature, uint32 sender, uint32 action, const char* code);
@@ -1049,7 +1038,6 @@ class TC_GAME_API ScriptMgr
public: /* GameObjectScript */
- bool OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, GameObject* target);
bool OnGossipHello(Player* player, GameObject* go);
bool OnGossipSelect(Player* player, GameObject* go, uint32 sender, uint32 action);
bool OnGossipSelectCode(Player* player, GameObject* go, uint32 sender, uint32 action, const char* code);
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 566ecfd9df8..9281d012f55 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -4072,6 +4072,34 @@ void AuraEffect::HandleModCastingSpeed(AuraApplication const* aurApp, uint8 mode
Unit* target = aurApp->GetTarget();
+ // Do not apply such auras in normal way
+ if (GetAmount() >= 1000)
+ {
+ if (apply)
+ target->SetInstantCast(true);
+ else
+ {
+ // only SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK can have this high amount
+ // it's some rare case that you have 2 auras like that, but just in case ;)
+
+ bool remove = true;
+ Unit::AuraEffectList const& castingSpeedNotStack = target->GetAuraEffectsByType(SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK);
+ for (AuraEffect const* aurEff : castingSpeedNotStack)
+ {
+ if (aurEff != this && aurEff->GetAmount() >= 1000)
+ {
+ remove = false;
+ break;
+ }
+ }
+
+ if (remove)
+ target->SetInstantCast(false);
+ }
+
+ return;
+ }
+
target->ApplyCastTimePercentMod((float)GetAmount(), apply);
}
@@ -4457,15 +4485,15 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
Unit* caster = GetCaster();
- if (mode & AURA_EFFECT_HANDLE_REAL)
+ // pet auras
+ if (target->GetTypeId() == TYPEID_PLAYER && (mode & AURA_EFFECT_HANDLE_REAL))
{
- // pet auras
if (PetAura const* petSpell = sSpellMgr->GetPetAura(GetId(), m_effIndex))
{
if (apply)
- target->AddPetAura(petSpell);
+ target->ToPlayer()->AddPetAura(petSpell);
else
- target->RemovePetAura(petSpell);
+ target->ToPlayer()->RemovePetAura(petSpell);
}
}
@@ -4900,7 +4928,7 @@ void AuraEffect::HandleAuraModFaction(AuraApplication const* aurApp, uint8 mode,
if (apply)
{
- target->setFaction(GetMiscValue());
+ target->SetFaction(GetMiscValue());
if (target->GetTypeId() == TYPEID_PLAYER)
target->RemoveUnitFlag(UNIT_FLAG_PVP_ATTACKABLE);
}
@@ -5501,12 +5529,7 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster)
}
}
else
- {
- Creature* c = target->ToCreature();
- if (!c || !caster || !sScriptMgr->OnDummyEffect(caster, GetId(), SpellEffIndex(GetEffIndex()), target->ToCreature()) ||
- !c->AI()->sOnDummyEffect(caster, GetId(), SpellEffIndex(GetEffIndex())))
- TC_LOG_DEBUG("spells", "AuraEffect::HandlePeriodicTriggerSpellAuraTick: Spell %u has non-existent spell %u in EffectTriggered[%d] and is therefor not triggered.", GetId(), triggerSpellId, GetEffIndex());
- }
+ TC_LOG_DEBUG("spells", "AuraEffect::HandlePeriodicTriggerSpellAuraTick: Spell %u has non-existent spell %u in EffectTriggered[%d] and is therefor not triggered.", GetId(), triggerSpellId, GetEffIndex());
}
void AuraEffect::HandlePeriodicTriggerSpellWithValueAuraTick(Unit* target, Unit* caster) const
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index a03788cdda5..85388dc5821 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -2626,11 +2626,24 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask)
}
// Now Reduce spell duration using data received at spell hit
+ // check whatever effects we're going to apply, diminishing returns only apply to negative aura effects
+ bool positive = true;
+ if (m_originalCaster == unit || !m_originalCaster->IsFriendlyTo(unit))
+ {
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if ((effectMask & (1 << i)) && !m_spellInfo->IsPositiveEffect(i))
+ {
+ positive = false;
+ break;
+ }
+ }
+ }
+
int32 duration = m_spellAura->GetMaxDuration();
- float diminishMod = unit->ApplyDiminishingToDuration(m_spellInfo, duration, m_originalCaster, diminishLevel);
// unit is immune to aura if it was diminished to 0 duration
- if (diminishMod == 0.0f)
+ if (!positive && !unit->ApplyDiminishingToDuration(m_spellInfo, duration, m_originalCaster, diminishLevel))
{
m_spellAura->Remove();
bool found = false;
@@ -2642,11 +2655,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask)
}
else
{
- ((UnitAura*)m_spellAura)->SetDiminishGroup(diminishGroup);
-
- bool positive = m_spellAura->GetSpellInfo()->IsPositive();
- if (AuraApplication* aurApp = m_spellAura->GetApplicationOfTarget(m_originalCaster->GetGUID()))
- positive = aurApp->IsPositive();
+ static_cast<UnitAura*>(m_spellAura)->SetDiminishGroup(diminishGroup);
duration = m_originalCaster->ModSpellDuration(m_spellInfo, unit, duration, positive, effectMask);
@@ -2944,15 +2953,6 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
else
m_casttime = m_spellInfo->CalcCastTime(m_caster->getLevel(), this);
- if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)) // _UNIT actually means creature. for some reason.
- if (!(m_spellInfo->IsNextMeleeSwingSpell() || IsAutoRepeat() || (_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING)))
- {
- if (m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
- m_caster->ToCreature()->FocusTarget(this, m_targets.GetObjectTarget());
- else if (m_spellInfo->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST))
- m_caster->ToCreature()->FocusTarget(this, nullptr);
- }
-
// don't allow channeled spells / spells with cast time to be cast while moving
// exception are only channeled spells that have no casttime and SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING
// (even if they are interrupted on moving, spells with almost immediate effect get to have their effect processed before movement interrupter kicks in)
@@ -2969,6 +2969,18 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
}
}
+ // focus if not controlled creature
+ if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
+ {
+ if (!(m_spellInfo->IsNextMeleeSwingSpell() || IsAutoRepeat() || (_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING)))
+ {
+ if (m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
+ m_caster->ToCreature()->FocusTarget(this, m_targets.GetObjectTarget());
+ else if (m_spellInfo->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST))
+ m_caster->ToCreature()->FocusTarget(this, nullptr);
+ }
+ }
+
// set timer base at cast time
ReSetTimer();
@@ -3116,11 +3128,12 @@ void Spell::_cast(bool skipCheck)
m_caster->SetInFront(m_targets.GetObjectTarget());
// Should this be done for original caster?
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ Player* modOwner = m_caster->GetSpellModOwner();
+ if (modOwner)
{
// Set spell which will drop charges for triggered cast spells
// if not successfully cast, will be remove in finish(false)
- m_caster->ToPlayer()->SetSpellModTakingSpell(this, true);
+ modOwner->SetSpellModTakingSpell(this, true);
}
CallScriptBeforeCastHandlers();
@@ -3135,8 +3148,8 @@ void Spell::_cast(bool skipCheck)
SendCastResult(castResult, &param1, &param2);
SendInterrupted(0);
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->SetSpellModTakingSpell(this, false);
+ if (modOwner)
+ modOwner->SetSpellModTakingSpell(this, false);
finish(false);
SetExecutedCurrently(false);
@@ -3147,9 +3160,9 @@ void Spell::_cast(bool skipCheck)
// if trade not complete then remember it in trade data
if (m_targets.GetTargetMask() & TARGET_FLAG_TRADE_ITEM)
{
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (modOwner)
{
- if (TradeData* my_trade = m_caster->ToPlayer()->GetTradeData())
+ if (TradeData* my_trade = modOwner->GetTradeData())
{
if (!my_trade->IsInAcceptProcess())
{
@@ -3158,7 +3171,7 @@ void Spell::_cast(bool skipCheck)
SendCastResult(SPELL_FAILED_DONT_REPORT);
SendInterrupted(0);
- m_caster->ToPlayer()->SetSpellModTakingSpell(this, false);
+ modOwner->SetSpellModTakingSpell(this, false);
finish(false);
SetExecutedCurrently(false);
@@ -3275,12 +3288,12 @@ void Spell::_cast(bool skipCheck)
m_caster->CastSpell(m_targets.GetUnitTarget() ? m_targets.GetUnitTarget() : m_caster, *i, true);
}
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (modOwner)
{
- m_caster->ToPlayer()->SetSpellModTakingSpell(this, false);
+ modOwner->SetSpellModTakingSpell(this, false);
//Clear spell cooldowns after every spell is cast if .cheat cooldown is enabled.
- if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_COOLDOWN))
+ if (modOwner->GetCommandStatus(CHEAT_COOLDOWN))
{
m_caster->GetSpellHistory()->ResetCooldown(m_spellInfo->Id, true);
m_caster->GetSpellHistory()->RestoreCharge(m_spellInfo->ChargeCategoryId);
@@ -3289,9 +3302,6 @@ void Spell::_cast(bool skipCheck)
SetExecutedCurrently(false);
- if (Creature* creatureCaster = m_caster->ToCreature())
- creatureCaster->ReleaseFocus(this);
-
if (!m_originalCaster)
return;
@@ -3411,8 +3421,9 @@ uint64 Spell::handle_delayed(uint64 t_offset)
if (single_missile && !t_offset)
return m_delayMoment;
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->SetSpellModTakingSpell(this, true);
+ Player* modOwner = m_caster->GetSpellModOwner();
+ if (modOwner)
+ modOwner->SetSpellModTakingSpell(this, true);
PrepareTargetProcessing();
@@ -3451,8 +3462,8 @@ uint64 Spell::handle_delayed(uint64 t_offset)
FinishTargetProcessing();
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->SetSpellModTakingSpell(this, false);
+ if (modOwner)
+ modOwner->SetSpellModTakingSpell(this, false);
// All targets passed - need finish phase
if (next_time == 0)
@@ -4449,8 +4460,16 @@ void Spell::SendChannelStart(uint32 duration)
m_timer = duration;
for (TargetInfo const& target : m_UniqueTargetInfo)
+ {
m_caster->AddChannelObject(target.targetGUID);
+ if (m_UniqueTargetInfo.size() == 1 && m_UniqueGOTargetInfo.empty())
+ if(target.targetGUID != m_caster->GetGUID())
+ if (Creature* creatureCaster = m_caster->ToCreature())
+ if (!creatureCaster->IsFocusing(this))
+ creatureCaster->FocusTarget(this, ObjectAccessor::GetWorldObject(*creatureCaster, target.targetGUID));
+ }
+
for (GOTargetInfo const& target : m_UniqueGOTargetInfo)
m_caster->AddChannelObject(target.targetGUID);
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 56a050eea65..53e9c98b0db 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -607,24 +607,18 @@ void Spell::EffectDummy(SpellEffIndex effIndex)
}
// pet auras
- if (PetAura const* petSpell = sSpellMgr->GetPetAura(m_spellInfo->Id, effIndex))
+ if (m_caster->GetTypeId() == TYPEID_PLAYER)
{
- m_caster->AddPetAura(petSpell);
- return;
+ if (PetAura const* petSpell = sSpellMgr->GetPetAura(m_spellInfo->Id, effIndex))
+ {
+ m_caster->ToPlayer()->AddPetAura(petSpell);
+ return;
+ }
}
// normal DB scripted effect
TC_LOG_DEBUG("spells", "Spell ScriptStart spellid %u in EffectDummy(%u)", m_spellInfo->Id, effIndex);
m_caster->GetMap()->ScriptsStart(sSpellScripts, uint32(m_spellInfo->Id | (effIndex << 24)), m_caster, unitTarget);
-
- // Script based implementation. Must be used only for not good for implementation in core spell effects
- // So called only for not proccessed cases
- if (gameObjTarget)
- sScriptMgr->OnDummyEffect(m_caster, m_spellInfo->Id, effIndex, gameObjTarget);
- else if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT)
- sScriptMgr->OnDummyEffect(m_caster, m_spellInfo->Id, effIndex, unitTarget->ToCreature());
- else if (itemTarget)
- sScriptMgr->OnDummyEffect(m_caster, m_spellInfo->Id, effIndex, itemTarget);
}
void Spell::EffectTriggerSpell(SpellEffIndex /*effIndex*/)
@@ -2031,7 +2025,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
if (properties->Control == SUMMON_CATEGORY_ALLY)
{
summon->SetOwnerGUID(m_originalCaster->GetGUID());
- summon->setFaction(m_originalCaster->getFaction());
+ summon->SetFaction(m_originalCaster->GetFaction());
summon->SetCreatedBySpell(m_spellInfo->Id);
}
@@ -2072,9 +2066,9 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
uint32 faction = properties->Faction;
if (!faction)
- faction = m_originalCaster->getFaction();
+ faction = m_originalCaster->GetFaction();
- summon->setFaction(faction);
+ summon->SetFaction(faction);
break;
}
@@ -2232,11 +2226,11 @@ void Spell::EffectDistract(SpellEffIndex /*effIndex*/)
if (unitTarget->HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING))
return;
- unitTarget->SetFacingTo(unitTarget->GetAngle(destTarget));
- unitTarget->ClearUnitState(UNIT_STATE_MOVING);
-
if (unitTarget->GetTypeId() == TYPEID_UNIT)
unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS);
+
+ unitTarget->StopMoving();
+ unitTarget->SetFacingTo(unitTarget->GetAngle(destTarget));
}
void Spell::EffectPickPocket(SpellEffIndex /*effIndex*/)
@@ -3604,7 +3598,7 @@ void Spell::EffectDuel(SpellEffIndex effIndex)
PhasingHandler::InheritPhaseShift(go, m_caster);
- go->SetFaction(m_caster->getFaction());
+ go->SetFaction(m_caster->GetFaction());
go->SetLevel(m_caster->getLevel()+1);
int32 duration = m_spellInfo->CalcDuration(m_caster);
go->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
@@ -4688,7 +4682,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex)
{
case GAMEOBJECT_TYPE_FISHINGNODE:
{
- go->SetFaction(m_caster->getFaction());
+ go->SetFaction(m_caster->GetFaction());
ObjectGuid bobberGuid = go->GetGUID();
// client requires fishing bobber guid in channel object slot 0 to be usable
m_caster->SetChannelObject(0, bobberGuid);
@@ -5206,7 +5200,7 @@ void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const*
((Guardian*)summon)->InitStatsForLevel(level);
if (properties && properties->Control == SUMMON_CATEGORY_ALLY)
- summon->setFaction(caster->getFaction());
+ summon->SetFaction(caster->GetFaction());
if (summon->HasUnitTypeMask(UNIT_MASK_MINION) && m_targets.HasDst())
((Minion*)summon)->SetFollowAngle(m_caster->GetAngle(summon));
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 12eb37b6861..b9f26ed4e08 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -510,14 +510,16 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster /*= nullptr*/, int32 const*
if (Scaling.ResourceCoefficient)
comboDamage = Scaling.ResourceCoefficient * value;
}
- else
+ else if (GetScalingExpectedStat() == ExpectedStatType::None)
{
- if (GetScalingExpectedStat() == ExpectedStatType::None)
+ if (caster && basePointsPerLevel != 0.0f)
{
- int32 level = caster ? int32(caster->getLevel()) : 0;
+ int32 level = int32(caster->getLevel());
if (level > int32(_spellInfo->MaxLevel) && _spellInfo->MaxLevel > 0)
level = int32(_spellInfo->MaxLevel);
- level -= int32(_spellInfo->BaseLevel);
+
+ // if base level is greater than spell level, reduce by base level (eg. pilgrims foods)
+ level -= int32(std::max(_spellInfo->BaseLevel, _spellInfo->SpellLevel));
if (level < 0)
level = 0;
value += level * basePointsPerLevel;
@@ -1673,7 +1675,7 @@ bool SpellInfo::IsChanneled() const
bool SpellInfo::IsMoveAllowedChannel() const
{
- return IsChanneled() && HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING);
+ return IsChanneled() && (HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING) || (!(ChannelInterruptFlags[0] & (AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING))));
}
bool SpellInfo::NeedsComboPoints() const
@@ -3382,11 +3384,14 @@ void SpellInfo::_LoadImmunityInfo()
{
switch (Id)
{
+ case 42292: // PvP trinket
+ case 59752: // Every Man for Himself
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED);
+ break;
case 34471: // The Beast Within
case 19574: // Bestial Wrath
- case 42292: // PvP trinket
case 46227: // Medallion of Immunity
- case 59752: // Every Man for Himself
case 53490: // Bullheaded
case 65547: // PvP Trinket
case 134946: // Supremacy of the Alliance
@@ -4507,6 +4512,7 @@ bool SpellInfo::_IsPositiveEffect(uint32 effIndex, bool deep) const
case SPELL_AURA_MOD_STALKED:
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
case SPELL_AURA_PREVENT_RESURRECTION:
+ case SPELL_AURA_EMPATHY:
return false;
case SPELL_AURA_PERIODIC_DAMAGE: // used in positive spells also.
// part of negative spell if cast at self (prevent cancel)
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 1dcc18773e1..eb2621954cf 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -335,32 +335,34 @@ void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>&
}
}
-bool SpellMgr::AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, int32 amount, std::map<SpellGroup, int32>& groups) const
+bool SpellMgr::AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, uint32 auraType, int32 amount, std::map<SpellGroup, int32>& groups) const
{
uint32 spellId = spellInfo->GetFirstRankSpell()->Id;
- SpellSpellGroupMapBounds spellGroup = GetSpellSpellGroupMapBounds(spellId);
+ auto spellGroupBounds = GetSpellSpellGroupMapBounds(spellId);
// Find group with SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT if it belongs to one
- for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second; ++itr)
+ for (auto itr = spellGroupBounds.first; itr != spellGroupBounds.second; ++itr)
{
SpellGroup group = itr->second;
- SpellGroupStackMap::const_iterator found = mSpellGroupStack.find(group);
- if (found != mSpellGroupStack.end())
+ auto found = mSpellSameEffectStack.find(group);
+ if (found != mSpellSameEffectStack.end())
{
- if (found->second == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
+ // check auraTypes
+ if (!found->second.count(auraType))
+ continue;
+
+ // Put the highest amount in the map
+ auto groupItr = groups.find(group);
+ if (groupItr == groups.end())
+ groups.emplace(group, amount);
+ else
{
- // Put the highest amount in the map
- if (groups.find(group) == groups.end())
- groups[group] = amount;
- else
- {
- int32 curr_amount = groups[group];
- // Take absolute value because this also counts for the highest negative aura
- if (abs(curr_amount) < abs(amount))
- groups[group] = amount;
- }
- // return because a spell should be in only one SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group
- return true;
+ int32 curr_amount = groups[group];
+ // Take absolute value because this also counts for the highest negative aura
+ if (std::abs(curr_amount) < std::abs(amount))
+ groupItr->second = amount;
}
+ // return because a spell should be in only one SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group per auraType
+ return true;
}
}
// Not in a SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group, so return false
@@ -374,8 +376,6 @@ SpellGroupStackRule SpellMgr::CheckSpellGroupStackRules(SpellInfo const* spellIn
uint32 spellid_1 = spellInfo1->GetFirstRankSpell()->Id;
uint32 spellid_2 = spellInfo2->GetFirstRankSpell()->Id;
- if (spellid_1 == spellid_2)
- return SPELL_GROUP_STACK_RULE_DEFAULT;
// find SpellGroups which are common for both spells
SpellSpellGroupMapBounds spellGroup1 = GetSpellSpellGroupMapBounds(spellid_1);
@@ -1181,19 +1181,19 @@ void SpellMgr::LoadSpellGroups()
}
int32 spell_id = fields[1].GetInt32();
- groups.insert(std::set<uint32>::value_type(group_id));
- mSpellGroupSpell.insert(SpellGroupSpellMap::value_type((SpellGroup)group_id, spell_id));
+ groups.insert(group_id);
+ mSpellGroupSpell.emplace(SpellGroup(group_id), spell_id);
} while (result->NextRow());
- for (SpellGroupSpellMap::iterator itr = mSpellGroupSpell.begin(); itr!= mSpellGroupSpell.end();)
+ for (auto itr = mSpellGroupSpell.begin(); itr!= mSpellGroupSpell.end();)
{
if (itr->second < 0)
{
if (groups.find(abs(itr->second)) == groups.end())
{
TC_LOG_ERROR("sql.sql", "SpellGroup id %u listed in `spell_group` does not exist", abs(itr->second));
- mSpellGroupSpell.erase(itr++);
+ itr = mSpellGroupSpell.erase(itr);
}
else
++itr;
@@ -1201,31 +1201,30 @@ void SpellMgr::LoadSpellGroups()
else
{
SpellInfo const* spellInfo = GetSpellInfo(itr->second);
-
if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_group` does not exist", itr->second);
- mSpellGroupSpell.erase(itr++);
+ itr = mSpellGroupSpell.erase(itr);
}
else if (spellInfo->GetRank() > 1)
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_group` is not the first rank of the spell.", itr->second);
- mSpellGroupSpell.erase(itr++);
+ itr = mSpellGroupSpell.erase(itr);
}
else
++itr;
}
}
- for (std::set<uint32>::iterator groupItr = groups.begin(); groupItr != groups.end(); ++groupItr)
+ for (auto groupItr = groups.begin(); groupItr != groups.end(); ++groupItr)
{
std::set<uint32> spells;
GetSetOfSpellsInSpellGroup(SpellGroup(*groupItr), spells);
- for (std::set<uint32>::iterator spellItr = spells.begin(); spellItr != spells.end(); ++spellItr)
+ for (auto spellItr = spells.begin(); spellItr != spells.end(); ++spellItr)
{
++count;
- mSpellSpellGroup.insert(SpellSpellGroupMap::value_type(*spellItr, SpellGroup(*groupItr)));
+ mSpellSpellGroup.emplace(*spellItr, SpellGroup(*groupItr));
}
}
@@ -1237,6 +1236,9 @@ void SpellMgr::LoadSpellGroupStackRules()
uint32 oldMSTime = getMSTime();
mSpellGroupStack.clear(); // need for reload case
+ mSpellSameEffectStack.clear();
+
+ std::vector<uint32> sameEffectGroups;
// 0 1
QueryResult result = WorldDatabase.Query("SELECT group_id, stack_rule FROM spell_group_stack_rules");
@@ -1259,20 +1261,126 @@ void SpellMgr::LoadSpellGroupStackRules()
continue;
}
- SpellGroupSpellMapBounds spellGroup = GetSpellGroupSpellMapBounds((SpellGroup)group_id);
-
- if (spellGroup.first == spellGroup.second)
+ auto bounds = GetSpellGroupSpellMapBounds((SpellGroup)group_id);
+ if (bounds.first == bounds.second)
{
TC_LOG_ERROR("sql.sql", "SpellGroup id %u listed in `spell_group_stack_rules` does not exist.", group_id);
continue;
}
- mSpellGroupStack[(SpellGroup)group_id] = (SpellGroupStackRule)stack_rule;
+ mSpellGroupStack.emplace(SpellGroup(group_id), SpellGroupStackRule(stack_rule));
+
+ // different container for same effect stack rules, need to check effect types
+ if (stack_rule == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
+ sameEffectGroups.push_back(group_id);
++count;
} while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded %u spell group stack rules in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+
+ count = 0;
+ oldMSTime = getMSTime();
+ TC_LOG_INFO("server.loading", ">> Parsing SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules...");
+
+ for (uint32 group_id : sameEffectGroups)
+ {
+ std::set<uint32> spellIds;
+ GetSetOfSpellsInSpellGroup(SpellGroup(group_id), spellIds);
+
+ std::unordered_set<uint32> auraTypes;
+
+ // we have to 'guess' what effect this group corresponds to
+ {
+ std::unordered_multiset<uint32 /*auraName*/> frequencyContainer;
+
+ // only waylay for the moment (shared group)
+ std::vector<std::vector<uint32 /*auraName*/>> const SubGroups =
+ {
+ { SPELL_AURA_MOD_MELEE_HASTE, SPELL_AURA_MOD_MELEE_RANGED_HASTE, SPELL_AURA_MOD_RANGED_HASTE }
+ };
+
+ for (uint32 spellId : spellIds)
+ {
+ SpellInfo const* spellInfo = AssertSpellInfo(spellId);
+ for (SpellEffectInfo const* effectInfo : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ {
+ if (!effectInfo->IsAura())
+ continue;
+
+ int32 auraName = static_cast<int32>(effectInfo->ApplyAuraName);
+ for (std::vector<uint32> const& subGroup : SubGroups)
+ {
+ if (std::find(subGroup.begin(), subGroup.end(), auraName) != subGroup.end())
+ {
+ // count as first aura
+ auraName = subGroup.front();
+ break;
+ }
+ }
+
+ frequencyContainer.insert(auraName);
+ }
+ }
+
+ uint32 auraType = 0;
+ size_t auraTypeCount = 0;
+ for (uint32 auraName : frequencyContainer)
+ {
+ size_t currentCount = frequencyContainer.count(auraName);
+ if (currentCount > auraTypeCount)
+ {
+ auraType = auraName;
+ auraTypeCount = currentCount;
+ }
+ }
+
+ for (std::vector<uint32> const& subGroup : SubGroups)
+ {
+ if (auraType == subGroup.front())
+ {
+ auraTypes.insert(subGroup.begin(), subGroup.end());
+ break;
+ }
+ }
+
+ if (auraTypes.empty())
+ auraTypes.insert(auraType);
+ }
+
+ // re-check spells against guessed group
+ for (uint32 spellId : spellIds)
+ {
+ SpellInfo const* spellInfo = AssertSpellInfo(spellId);
+
+ bool found = false;
+ while (spellInfo)
+ {
+ for (uint32 auraType : auraTypes)
+ {
+ if (spellInfo->HasAura(DIFFICULTY_NONE, AuraType(auraType)))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ break;
+
+ spellInfo = spellInfo->GetNextRankSpell();
+ }
+
+ // not found either, log error
+ if (!found)
+ TC_LOG_ERROR("sql.sql", "SpellId %u listed in `spell_group` with stack rule 3 does not share aura assigned for group %u", spellId, group_id);
+ }
+
+ mSpellSameEffectStack[SpellGroup(group_id)] = auraTypes;
+ ++count;
+ }
+
+ TC_LOG_INFO("server.loading", ">> Parsed %u SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void SpellMgr::LoadSpellProcs()
@@ -3342,6 +3450,13 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Speed = 0.0f; // This spell's summon happens instantly
});
+ // Chilled to the Bone
+ ApplySpellFix({ 70106 }, [](SpellInfo* spellInfo)
+ {
+ spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS;
+ spellInfo->AttributesEx6 |= SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS;
+ });
+
// Ice Lock
ApplySpellFix({ 71614 }, [](SpellInfo* spellInfo)
{
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index 6bf843cfff1..c121f1ec8f1 100644
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -31,6 +31,7 @@
#include <set>
#include <vector>
#include <unordered_map>
+#include <unordered_set>
class SpellInfo;
class Player;
@@ -309,14 +310,26 @@ enum SpellGroup
SPELL_GROUP_CORE_RANGE_MAX = 5
};
+namespace std
+{
+ template<>
+ struct hash<SpellGroup>
+ {
+ size_t operator()(SpellGroup const& group) const
+ {
+ return hash<uint32>()(uint32(group));
+ }
+ };
+}
+
#define SPELL_GROUP_DB_RANGE_MIN 1000
// spell_id, group_id
-typedef std::multimap<uint32, SpellGroup > SpellSpellGroupMap;
+typedef std::unordered_multimap<uint32, SpellGroup> SpellSpellGroupMap;
typedef std::pair<SpellSpellGroupMap::const_iterator, SpellSpellGroupMap::const_iterator> SpellSpellGroupMapBounds;
// group_id, spell_id
-typedef std::multimap<SpellGroup, int32> SpellGroupSpellMap;
+typedef std::unordered_multimap<SpellGroup, int32> SpellGroupSpellMap;
typedef std::pair<SpellGroupSpellMap::const_iterator, SpellGroupSpellMap::const_iterator> SpellGroupSpellMapBounds;
enum SpellGroupStackRule
@@ -329,7 +342,9 @@ enum SpellGroupStackRule
SPELL_GROUP_STACK_RULE_MAX
};
-typedef std::map<SpellGroup, SpellGroupStackRule> SpellGroupStackMap;
+typedef std::unordered_map<SpellGroup, SpellGroupStackRule> SpellGroupStackMap;
+
+typedef std::unordered_map<SpellGroup, std::unordered_set<uint32 /*auraName*/>> SameEffectStackMap;
struct SpellThreatEntry
{
@@ -655,7 +670,7 @@ class TC_GAME_API SpellMgr
void GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells, std::set<SpellGroup>& usedGroups) const;
// Spell Group Stack Rules table
- bool AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, int32 amount, std::map<SpellGroup, int32>& groups) const;
+ bool AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, uint32 auraType, int32 amount, std::map<SpellGroup, int32>& groups) const;
SpellGroupStackRule CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const;
SpellGroupStackRule GetSpellGroupStackRule(SpellGroup groupid) const;
@@ -750,6 +765,7 @@ class TC_GAME_API SpellMgr
SpellSpellGroupMap mSpellSpellGroup;
SpellGroupSpellMap mSpellGroupSpell;
SpellGroupStackMap mSpellGroupStack;
+ SameEffectStackMap mSpellSameEffectStack;
SpellProcMap mSpellProcMap;
SpellThreatMap mSpellThreatMap;
SpellPetAuraMap mSpellPetAuraMap;
diff --git a/src/server/game/Time/UpdateTime.cpp b/src/server/game/Time/UpdateTime.cpp
index ffd985c2caf..6f3f5d6ff83 100644
--- a/src/server/game/Time/UpdateTime.cpp
+++ b/src/server/game/Time/UpdateTime.cpp
@@ -31,6 +31,7 @@ UpdateTime::UpdateTime()
_maxUpdateTime = 0;
_maxUpdateTimeOfLastTable = 0;
_maxUpdateTimeOfCurrentTable = 0;
+ _recordedTime = 0;
_updateTimeDataTable = { };
}
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index e1e71ce01e2..a94e06034ba 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -60,6 +60,7 @@
#include "IPLocation.h"
#include "Language.h"
#include "LFGMgr.h"
+#include "LootItemStorage.h"
#include "LootMgr.h"
#include "M2Stores.h"
#include "MapManager.h"
@@ -2073,6 +2074,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Calendar data...");
sCalendarMgr->LoadFromDB();
+ TC_LOG_INFO("server.loading", "Loading Item loot...");
+ sLootItemStorage->LoadStorageFromDB();
+
TC_LOG_INFO("server.loading", "Initialize query data...");
sObjectMgr->InitializeQueriesData(QUERY_DATA_ALL);