aboutsummaryrefslogtreecommitdiff
path: root/src/server/game
diff options
context:
space:
mode:
authorSpp <spp@jorge.gr>2012-01-31 11:49:53 +0100
committerSpp <spp@jorge.gr>2012-01-31 11:49:53 +0100
commit37b66384f3d905fb8de506aae48237900a1b6065 (patch)
treef6c36187e06f76704d7a661179857916b18b6469 /src/server/game
parentfdbb3e52bcbaa236a26bd2bf8293a5deccb34a01 (diff)
parentd4670a558dd40fc03c9b143dcffa763c834ab966 (diff)
Merge branch 'master' into 4.x
Conflicts: src/server/authserver/Server/AuthSocket.cpp src/server/game/Entities/Object/Object.cpp src/server/game/Entities/Player/Player.cpp src/server/game/Entities/Unit/Unit.cpp src/server/game/Handlers/AuctionHouseHandler.cpp src/server/game/Handlers/CharacterHandler.cpp src/server/game/Handlers/MovementHandler.cpp src/server/game/Miscellaneous/SharedDefines.h src/server/game/Spells/Spell.cpp src/server/game/Spells/SpellEffects.cpp
Diffstat (limited to 'src/server/game')
-rw-r--r--src/server/game/AI/CoreAI/GameObjectAI.h1
-rwxr-xr-xsrc/server/game/AI/CoreAI/GuardAI.cpp4
-rwxr-xr-xsrc/server/game/AI/CoreAI/PetAI.cpp9
-rwxr-xr-xsrc/server/game/AI/EventAI/CreatureEventAI.cpp5
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.cpp5
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp4
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedGossip.h2
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp28
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.h1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp289
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp4
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h24
-rwxr-xr-xsrc/server/game/Battlegrounds/Battleground.cpp18
-rwxr-xr-xsrc/server/game/Battlegrounds/Battleground.h4
-rwxr-xr-xsrc/server/game/Battlegrounds/Zones/BattlegroundAB.cpp3
-rwxr-xr-xsrc/server/game/Battlegrounds/Zones/BattlegroundAB.h2
-rwxr-xr-xsrc/server/game/Battlegrounds/Zones/BattlegroundAV.cpp3
-rwxr-xr-xsrc/server/game/Battlegrounds/Zones/BattlegroundAV.h2
-rwxr-xr-xsrc/server/game/Battlegrounds/Zones/BattlegroundEY.cpp4
-rwxr-xr-xsrc/server/game/Battlegrounds/Zones/BattlegroundEY.h2
-rw-r--r--src/server/game/CMakeLists.txt8
-rwxr-xr-xsrc/server/game/Chat/Commands/Level2.cpp19
-rwxr-xr-xsrc/server/game/Chat/Commands/Level3.cpp61
-rwxr-xr-xsrc/server/game/Conditions/ConditionMgr.cpp206
-rwxr-xr-xsrc/server/game/Conditions/ConditionMgr.h28
-rwxr-xr-xsrc/server/game/DungeonFinding/LFGMgr.cpp117
-rwxr-xr-xsrc/server/game/DungeonFinding/LFGMgr.h8
-rwxr-xr-xsrc/server/game/Entities/Creature/Creature.cpp74
-rwxr-xr-xsrc/server/game/Entities/Creature/Creature.h4
-rwxr-xr-xsrc/server/game/Entities/Creature/CreatureGroups.cpp6
-rwxr-xr-xsrc/server/game/Entities/GameObject/GameObject.cpp14
-rwxr-xr-xsrc/server/game/Entities/GameObject/GameObject.h5
-rwxr-xr-xsrc/server/game/Entities/Object/Object.cpp130
-rwxr-xr-xsrc/server/game/Entities/Object/Object.h3
-rwxr-xr-xsrc/server/game/Entities/Player/Player.cpp191
-rwxr-xr-xsrc/server/game/Entities/Player/Player.h11
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp289
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h126
-rwxr-xr-xsrc/server/game/Globals/ObjectMgr.cpp2
-rwxr-xr-xsrc/server/game/Groups/Group.cpp128
-rwxr-xr-xsrc/server/game/Groups/Group.h3
-rw-r--r--src/server/game/Groups/GroupMgr.cpp8
-rwxr-xr-xsrc/server/game/Groups/GroupReference.cpp4
-rwxr-xr-xsrc/server/game/Handlers/AddonHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/AddonHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/AddonHandler.h (renamed from src/server/game/Server/Protocol/Handlers/AddonHandler.h)0
-rwxr-xr-xsrc/server/game/Handlers/ArenaTeamHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/ArenaTeamHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/AuctionHouseHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/AuthHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/AuthHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/BattleGroundHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/CalendarHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/CalendarHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/ChannelHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp)0
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp)18
-rwxr-xr-xsrc/server/game/Handlers/ChatHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/ChatHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/CombatHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/CombatHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/DuelHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/DuelHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/GroupHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/GroupHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/GuildHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/GuildHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/ItemHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/ItemHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/LFGHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/LFGHandler.cpp)3
-rwxr-xr-xsrc/server/game/Handlers/LootHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/LootHandler.cpp)2
-rwxr-xr-xsrc/server/game/Handlers/MailHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/MailHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/MiscHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/MiscHandler.cpp)8
-rwxr-xr-xsrc/server/game/Handlers/MovementHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/MovementHandler.cpp)13
-rwxr-xr-xsrc/server/game/Handlers/NPCHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/NPCHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/NPCHandler.h (renamed from src/server/game/Server/Protocol/Handlers/NPCHandler.h)0
-rwxr-xr-xsrc/server/game/Handlers/PetHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/PetHandler.cpp)1
-rwxr-xr-xsrc/server/game/Handlers/PetitionsHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/QueryHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/QueryHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/QuestHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/QuestHandler.cpp)0
-rw-r--r--src/server/game/Handlers/ReferAFriendHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/ReferAFriendHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/SkillHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/SkillHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/SpellHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/SpellHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/TaxiHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp)1
-rwxr-xr-xsrc/server/game/Handlers/TicketHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/TicketHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/TradeHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/TradeHandler.cpp)0
-rw-r--r--src/server/game/Handlers/VehicleHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/VehicleHandler.cpp)0
-rwxr-xr-xsrc/server/game/Handlers/VoiceChatHandler.cpp (renamed from src/server/game/Server/Protocol/Handlers/VoiceChatHandler.cpp)0
-rwxr-xr-xsrc/server/game/Instances/InstanceSaveMgr.cpp4
-rwxr-xr-xsrc/server/game/Instances/InstanceScript.cpp18
-rwxr-xr-xsrc/server/game/Maps/Map.cpp18
-rwxr-xr-xsrc/server/game/Maps/Map.h2
-rwxr-xr-xsrc/server/game/Maps/MapManager.cpp1
-rwxr-xr-xsrc/server/game/Miscellaneous/Language.h12
-rwxr-xr-xsrc/server/game/Movement/DestinationHolder.cpp20
-rwxr-xr-xsrc/server/game/Movement/DestinationHolder.h65
-rwxr-xr-xsrc/server/game/Movement/DestinationHolderImp.h215
-rwxr-xr-xsrc/server/game/Movement/MotionMaster.cpp168
-rwxr-xr-xsrc/server/game/Movement/MotionMaster.h17
-rwxr-xr-xsrc/server/game/Movement/MovementGenerator.cpp1
-rwxr-xr-xsrc/server/game/Movement/MovementGenerator.h2
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp125
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h13
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp123
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h7
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp57
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/HomeMovementGenerator.h12
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp105
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/PointMovementGenerator.h30
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp188
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/RandomMovementGenerator.h12
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp370
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h91
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp417
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h90
-rw-r--r--src/server/game/Movement/Spline/MoveSpline.cpp316
-rw-r--r--src/server/game/Movement/Spline/MoveSpline.h127
-rw-r--r--src/server/game/Movement/Spline/MoveSplineFlag.h143
-rw-r--r--src/server/game/Movement/Spline/MoveSplineInit.cpp118
-rw-r--r--src/server/game/Movement/Spline/MoveSplineInit.h170
-rw-r--r--src/server/game/Movement/Spline/MoveSplineInitArgs.h67
-rw-r--r--src/server/game/Movement/Spline/MovementPacketBuilder.cpp188
-rw-r--r--src/server/game/Movement/Spline/MovementPacketBuilder.h37
-rw-r--r--src/server/game/Movement/Spline/MovementTypedefs.h81
-rw-r--r--src/server/game/Movement/Spline/MovementUtil.cpp208
-rw-r--r--src/server/game/Movement/Spline/Spline.cpp307
-rw-r--r--src/server/game/Movement/Spline/Spline.h212
-rw-r--r--src/server/game/Movement/Spline/SplineImpl.h97
-rwxr-xr-xsrc/server/game/Movement/Traveller.h152
-rwxr-xr-xsrc/server/game/Quests/QuestDef.h2
-rwxr-xr-xsrc/server/game/Scripting/MapScripts.cpp10
-rwxr-xr-xsrc/server/game/Scripting/ScriptLoader.cpp2
-rwxr-xr-xsrc/server/game/Server/WorldSession.cpp2
-rwxr-xr-xsrc/server/game/Server/WorldSession.h1
-rwxr-xr-xsrc/server/game/Spells/Auras/SpellAuraEffects.cpp6
-rwxr-xr-xsrc/server/game/Spells/Auras/SpellAuras.cpp14
-rwxr-xr-xsrc/server/game/Spells/Auras/SpellAuras.h3
-rwxr-xr-xsrc/server/game/Spells/Spell.cpp7
-rwxr-xr-xsrc/server/game/Spells/SpellEffects.cpp53
-rwxr-xr-xsrc/server/game/Spells/SpellMgr.cpp19
130 files changed, 4187 insertions, 2244 deletions
diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h
index 0b91b6e8ddb..b9d385ba675 100644
--- a/src/server/game/AI/CoreAI/GameObjectAI.h
+++ b/src/server/game/AI/CoreAI/GameObjectAI.h
@@ -50,6 +50,7 @@ class GameObjectAI
virtual void Destroyed(Player* /*player*/, uint32 /*eventId*/) {}
virtual void SetData(uint32 /*id*/, uint32 /*value*/) {}
virtual void OnGameEvent(bool /*start*/, uint16 /*eventId*/) {}
+ virtual void OnStateChanged(uint32 /*state*/, Unit* /*unit*/) { }
};
class NullGameObjectAI : public GameObjectAI
diff --git a/src/server/game/AI/CoreAI/GuardAI.cpp b/src/server/game/AI/CoreAI/GuardAI.cpp
index 54061274408..b78fec7c142 100755
--- a/src/server/game/AI/CoreAI/GuardAI.cpp
+++ b/src/server/game/AI/CoreAI/GuardAI.cpp
@@ -115,8 +115,8 @@ void GuardAI::EnterEvadeMode()
me->CombatStop(true);
i_state = STATE_NORMAL;
- // Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
- if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
+ // Remove ChaseMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
+ if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
me->GetMotionMaster()->MoveTargetedHome();
}
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp
index 60151e4865a..015e20415b1 100755
--- a/src/server/game/AI/CoreAI/PetAI.cpp
+++ b/src/server/game/AI/CoreAI/PetAI.cpp
@@ -417,10 +417,9 @@ void PetAI::MovementInform(uint32 moveType, uint32 data)
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveIdle();
}
+ break;
}
- break;
-
- case TARGETED_MOTION_TYPE:
+ case FOLLOW_MOTION_TYPE:
{
// If data is owner's GUIDLow then we've reached follow point,
// otherwise we're probably chasing a creature
@@ -430,11 +429,9 @@ void PetAI::MovementInform(uint32 moveType, uint32 data)
me->GetCharmInfo()->SetIsReturning(false);
me->GetCharmInfo()->SetIsFollowing(true);
me->GetCharmInfo()->SetIsCommandAttack(false);
- me->AddUnitState(UNIT_STAT_FOLLOW);
}
+ break;
}
- break;
-
default:
break;
}
diff --git a/src/server/game/AI/EventAI/CreatureEventAI.cpp b/src/server/game/AI/EventAI/CreatureEventAI.cpp
index 4029f5e8180..9703757ca7a 100755
--- a/src/server/game/AI/EventAI/CreatureEventAI.cpp
+++ b/src/server/game/AI/EventAI/CreatureEventAI.cpp
@@ -475,7 +475,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
//Melee current victim if flag not set
if (!(action.cast.castFlags & CAST_NO_MELEE_IF_OOM))
{
- if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
+ if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
{
m_AttackDistance = 0.0f;
m_AttackAngle = 0.0f;
@@ -483,7 +483,6 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
me->GetMotionMaster()->MoveChase(me->getVictim(), m_AttackDistance, m_AttackAngle);
}
}
-
}
else
{
@@ -595,7 +594,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
me->ClearUnitState(UNIT_STAT_MELEE_ATTACKING);
me->SendMeleeAttackStop(victim);
}
- if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
+ if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
me->GetMotionMaster()->MoveIdle();
}
}
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
index e9a9c1fdcf2..ff432abcc82 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+/* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
*
* Thanks to the original authors: ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
@@ -298,7 +298,8 @@ void ScriptedAI::DoModifyThreatPercent(Unit* unit, int32 pct)
void ScriptedAI::DoTeleportTo(float x, float y, float z, uint32 time)
{
me->Relocate(x, y, z);
- me->SendMonsterMove(x, y, z, time);
+ float speed = me->GetDistance(x, y, z) / ((float)time * 0.001f);
+ me->MonsterMoveWithSpeed(x, y, z, speed);
}
void ScriptedAI::DoTeleportTo(const float position[4])
diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
index 1e0b212dd45..53747d0c799 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
@@ -167,7 +167,7 @@ void FollowerAI::EnterEvadeMode()
{
sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI left combat, returning to CombatStartPosition.");
- if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
+ if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
{
float fPosX, fPosY, fPosZ;
me->GetPosition(fPosX, fPosY, fPosZ);
@@ -176,7 +176,7 @@ void FollowerAI::EnterEvadeMode()
}
else
{
- if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
+ if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
me->GetMotionMaster()->MoveTargetedHome();
}
diff --git a/src/server/game/AI/ScriptedAI/ScriptedGossip.h b/src/server/game/AI/ScriptedAI/ScriptedGossip.h
index 5d376be888e..34300ff406c 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedGossip.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedGossip.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+/* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
*
* Thanks to the original authors: ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index b5fdf38a4b6..d4b2a9746be 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -46,7 +46,7 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c)
// spawn in run mode
me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
- mRun = true;
+ mRun = false;
me->GetPosition(&mLastOOCPos);
@@ -89,7 +89,7 @@ void SmartAI::UpdateDespawn(const uint32 diff)
void SmartAI::Reset()
{
if (!HasEscortState(SMART_ESCORT_ESCORTING))//dont mess up escort movement after combat
- SetRun(true);
+ SetRun(mRun);
GetScript()->OnReset();
}
@@ -433,24 +433,13 @@ void SmartAI::MovementInform(uint32 MovementType, uint32 Data)
void SmartAI::RemoveAuras()
{
+ // Only loop throught the applied auras, because here is where all auras on the current unit are stored
Unit::AuraApplicationMap appliedAuras = me->GetAppliedAuras();
- for (Unit::AuraApplicationMap::iterator iter = appliedAuras.begin(); iter != appliedAuras.end();)
+ for (Unit::AuraApplicationMap::iterator iter = appliedAuras.begin(); iter != appliedAuras.end(); ++iter)
{
Aura const* aura = iter->second->GetBase();
- if (!aura->GetSpellInfo()->HasAura(SPELL_AURA_CONTROL_VEHICLE) && !(iter->second->GetTarget() == me && aura->GetCaster() == me))
- me->_UnapplyAura(iter, AURA_REMOVE_BY_DEFAULT);
- else
- ++iter;
- }
-
- Unit::AuraMap ownedAuras = me->GetOwnedAuras();
- for (Unit::AuraMap::iterator iter = ownedAuras.begin(); iter != ownedAuras.end();)
- {
- Aura* aura = iter->second;
- if (!aura->GetSpellInfo()->HasAura(SPELL_AURA_CONTROL_VEHICLE))
- me->RemoveOwnedAura(iter, AURA_REMOVE_BY_DEFAULT);
- else
- ++iter;
+ if (!aura->GetSpellInfo()->IsPassive() && !aura->GetSpellInfo()->HasAura(SPELL_AURA_CONTROL_VEHICLE) && aura->GetCaster() != me)
+ me->RemoveAurasDueToSpell(aura->GetId());
}
}
@@ -948,6 +937,11 @@ void SmartGameObjectAI::OnGameEvent(bool start, uint16 eventId)
GetScript()->ProcessEventsFor(start ? SMART_EVENT_GAME_EVENT_START : SMART_EVENT_GAME_EVENT_END, NULL, eventId);
}
+void SmartGameObjectAI::OnStateChanged(uint32 state, Unit* unit)
+{
+ GetScript()->ProcessEventsFor(SMART_EVENT_GO_STATE_CHANGED, unit, state);
+}
+
class SmartTrigger : public AreaTriggerScript
{
public:
diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h
index b33bfebf912..0576612a155 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.h
+++ b/src/server/game/AI/SmartScripts/SmartAI.h
@@ -253,6 +253,7 @@ public:
void SetData(uint32 id, uint32 value);
void SetScript9(SmartScriptHolder& e, uint32 entry, Unit* invoker);
void OnGameEvent(bool start, uint16 eventId);
+ void OnStateChanged(uint32 state, Unit* unit);
protected:
GameObject* const go;
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index a2e70e9cbf2..3c0bdfcade7 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -51,7 +51,6 @@ SmartScript::SmartScript()
mTemplate = SMARTAI_TEMPLATE_BASIC;
meOrigGUID = 0;
goOrigGUID = 0;
- mResumeActionList = true;
mLastInvoker = 0;
}
@@ -78,22 +77,6 @@ void SmartScript::OnReset()
void SmartScript::ProcessEventsFor(SMART_EVENT e, Unit* unit, uint32 var0, uint32 var1, bool bvar, const SpellInfo* spell, GameObject* gob)
{
- if (e == SMART_EVENT_AGGRO)
- {
- if (!mResumeActionList)
- mTimedActionList.clear();//clear action list if it is not resumable
- else
- {
- for (SmartAIEventList::iterator itr = mTimedActionList.begin(); itr != mTimedActionList.end(); ++itr)
- {
- if (itr->enableTimed)
- {
- InitTimer((*itr));//re-init the currently enabled timer, so it restarts the timer when resumed
- break;
- }
- }
- }
- }
for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i)
{
SMART_EVENT eventType = SMART_EVENT((*i).GetEventType());
@@ -101,7 +84,20 @@ void SmartScript::ProcessEventsFor(SMART_EVENT e, Unit* unit, uint32 var0, uint3
continue;
if (eventType == e/* && (!(*i).event.event_phase_mask || IsInPhase((*i).event.event_phase_mask)) && !((*i).event.event_flags & SMART_EVENT_FLAG_NOT_REPEATABLE && (*i).runOnce)*/)
- ProcessEvent(*i, unit, var0, var1, bvar, spell, gob);
+ {
+ bool meets = true;
+ if (unit)
+ {
+ if (Player* player = unit->ToPlayer())
+ {
+ ConditionList conds = sConditionMgr->GetConditionsForSmartEvent((*i).entryOrGuid, (*i).event_id, (*i).source_type);
+ meets = sConditionMgr->IsPlayerMeetToConditions(player, conds);
+ }
+ }
+
+ if (meets)
+ ProcessEvent(*i, unit, var0, var1, bvar, spell, gob);
+ }
}
}
@@ -119,15 +115,6 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (unit)
mLastInvoker = unit->GetGUID();
- if (e.link && e.link != e.event_id)
- {
- SmartScriptHolder linked = FindLinkedEvent(e.link);
- if (linked.GetActionType() && linked.GetEventType() == SMART_EVENT_LINK)
- ProcessEvent(linked, unit, var0, var1, bvar, spell, gob);
- else
- sLog->outErrorDb("SmartScript::ProcessAction: Entry %d SourceType %u, Event %u, Link Event %u not found or invalid, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link);
- }
-
if (Unit* tempInvoker = GetLastInvoker())
sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: Invoker: %s (guidlow: %u)", tempInvoker->GetName(), tempInvoker->GetGUIDLow());
@@ -136,7 +123,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_TALK:
{
if (!me)
- return;
+ break;
ObjectList* targets = GetTargets(e, unit);
Creature* talker = me;
@@ -274,7 +261,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -317,7 +304,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -336,7 +323,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -357,7 +344,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_SET_REACT_STATE:
{
if (!me)
- return;
+ break;
me->SetReactState(ReactStates(e.action.react.state));
sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SET_REACT_STATE: Creature guidLow %u set reactstate %u",
@@ -368,7 +355,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
uint32 emotes[SMART_ACTION_PARAM_COUNT];
emotes[0] = e.action.randomEmote.emote1;
@@ -405,7 +392,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_THREAT_ALL_PCT:
{
if (!me)
- return;
+ break;
std::list<HostileReference*> const& threatList = me->getThreatManager().getThreatList();
for (std::list<HostileReference*>::const_iterator i = threatList.begin(); i != threatList.end(); ++i)
@@ -422,11 +409,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_THREAT_SINGLE_PCT:
{
if (!me)
- return;
+ break;
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -445,7 +432,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -463,11 +450,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_SEND_CASTCREATUREORGO:
{
if (!GetBaseObject())
- return;
+ break;
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -485,11 +472,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_CAST:
{
if (!me)
- return;
+ break;
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -511,11 +498,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
Unit* tempLastInvoker = GetLastInvoker();
if (!tempLastInvoker)
- return;
+ break;
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -537,7 +524,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -556,7 +543,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -564,7 +551,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
// Activate
(*itr)->ToGameObject()->SetLootState(GO_READY);
- (*itr)->ToGameObject()->UseDoorOrButton();
+ (*itr)->ToGameObject()->UseDoorOrButton(0, false, unit);
sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_ACTIVATE_GOBJECT. Gameobject %u (entry: %u) activated",
(*itr)->GetGUIDLow(), (*itr)->GetEntry());
}
@@ -577,7 +564,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -596,7 +583,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -615,7 +602,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -634,7 +621,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -652,7 +639,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_AUTO_ATTACK:
{
if (!IsSmart())
- return;
+ break;
CAST_AI(SmartAI, me->AI())->SetAutoAttack(e.action.autoAttack.attack ? true : false);
sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_AUTO_ATTACK: Creature: %u bool on = %u",
@@ -662,7 +649,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_ALLOW_COMBAT_MOVEMENT:
{
if (!IsSmart())
- return;
+ break;
bool move = e.action.combatMove.move ? true : false;
CAST_AI(SmartAI, me->AI())->SetCombatMove(move);
@@ -673,7 +660,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_SET_EVENT_PHASE:
{
if (!GetBaseObject())
- return;
+ break;
SetPhase(e.action.setEventPhase.phase);
sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SET_EVENT_PHASE: Creature %u set event phase %u",
@@ -683,7 +670,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_INC_EVENT_PHASE:
{
if (!GetBaseObject())
- return;
+ break;
IncPhase(e.action.incEventPhase.inc);
DecPhase(e.action.incEventPhase.dec);
@@ -694,7 +681,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_EVADE:
{
if (!me)
- return;
+ break;
me->AI()->EnterEvadeMode();
sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_EVADE: Creature %u EnterEvadeMode", me->GetGUIDLow());
@@ -703,7 +690,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_FLEE_FOR_ASSIST:
{
if (!me)
- return;
+ break;
me->DoFleeToGetAssistance();
if (e.action.flee.withEmote)
@@ -724,11 +711,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_CALL_CASTEDCREATUREORGO:
{
if (!GetBaseObject())
- return;
+ break;
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -747,7 +734,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -765,11 +752,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_FOLLOW:
{
if (!IsSmart())
- return;
+ break;
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -788,7 +775,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_RANDOM_PHASE:
{
if (!GetBaseObject())
- return;
+ break;
uint32 phases[SMART_ACTION_PARAM_COUNT];
phases[0] = e.action.randomPhase.phase1;
@@ -817,7 +804,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_RANDOM_PHASE_RANGE:
{
if (!GetBaseObject())
- return;
+ break;
uint32 phase = urand(e.action.randomPhaseRange.phaseMin, e.action.randomPhaseRange.phaseMax);
SetPhase(phase);
@@ -837,7 +824,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -866,13 +853,13 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
obj = unit;
if (!obj)
- return;
+ break;
InstanceScript* instance = obj->GetInstanceScript();
if (!instance)
{
sLog->outErrorDb("SmartScript: Event %u attempt to set instance data without instance script. EntryOrGuid %d", e.GetEventType(), e.entryOrGuid);
- return;
+ break;
}
instance->SetData(e.action.setInstanceData.field, e.action.setInstanceData.data);
@@ -887,18 +874,18 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
obj = unit;
if (!obj)
- return;
+ break;
InstanceScript* instance = obj->GetInstanceScript();
if (!instance)
{
sLog->outErrorDb("SmartScript: Event %u attempt to set instance data without instance script. EntryOrGuid %d", e.GetEventType(), e.entryOrGuid);
- return;
+ break;
}
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
instance->SetData64(e.action.setInstanceData64.field, targets->front()->GetGUID());
sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA64: Field: %u, data: "UI64FMTD,
@@ -910,7 +897,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_UPDATE_TEMPLATE:
{
if (!me || me->GetEntry() == e.action.updateTemplate.creature)
- return;
+ break;
me->UpdateEntry(e.action.updateTemplate.creature, e.action.updateTemplate.team ? HORDE : ALLIANCE);
sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_UPDATE_TEMPLATE: Creature %u, Template: %u, Team: %u",
@@ -957,7 +944,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_FORCE_DESPAWN:
{
if (!IsSmart())
- return;
+ break;
CAST_AI(SmartAI, me->AI())->SetDespawnTime(e.action.forceDespawn.delay + 1);//next tick
CAST_AI(SmartAI, me->AI())->StartDespawn();
@@ -973,7 +960,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -1003,7 +990,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL:
{
if (!me)
- return;
+ break;
if (e.action.invincHP.percent)
mInvinceabilityHpLevel = me->CountPctFromMaxHealth(e.action.invincHP.percent);
@@ -1015,7 +1002,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -1031,7 +1018,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_MOVE_FORWARD:
{
if (!me)
- return;
+ break;
float x, y, z;
me->GetClosePoint(x, y, z, me->GetObjectSize() / 3, (float)e.action.moveRandom.distance);
@@ -1053,11 +1040,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_ATTACK_START:
{
if (!me)
- return;
+ break;
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -1092,7 +1079,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
if (e.GetTargetType() != SMART_TARGET_POSITION)
- return;
+ break;
if (Creature* summon = GetBaseObject()->SummonCreature(e.action.summonCreature.creature, e.target.x, e.target.y, e.target.z, e.target.o, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration))
if (unit && e.action.summonCreature.attackInvoker)
@@ -1102,7 +1089,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_SUMMON_GO:
{
if (!GetBaseObject())
- return;
+ break;
float x, y, z, o;
ObjectList* targets = GetTargets(e, unit);
@@ -1121,7 +1108,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
if (e.GetTargetType() != SMART_TARGET_POSITION)
- return;
+ break;
GetBaseObject()->SummonGameObject(e.action.summonGO.entry, e.target.x, e.target.y, e.target.z, e.target.o, 0, 0, 0, 0, e.action.summonGO.despawnTime);
break;
@@ -1130,7 +1117,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -1152,7 +1139,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -1169,7 +1156,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -1199,7 +1186,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -1215,7 +1202,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_SET_FLY:
{
if (!IsSmart())
- return;
+ break;
CAST_AI(SmartAI, me->AI())->SetFly(e.action.setFly.fly ? true : false);
break;
@@ -1223,7 +1210,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_SET_RUN:
{
if (!IsSmart())
- return;
+ break;
CAST_AI(SmartAI, me->AI())->SetRun(e.action.setRun.run ? true : false);
break;
@@ -1231,7 +1218,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_SET_SWIM:
{
if (!IsSmart())
- return;
+ break;
CAST_AI(SmartAI, me->AI())->SetSwim(e.action.setSwim.swim ? true : false);
break;
@@ -1239,7 +1226,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_WP_START:
{
if (!IsSmart())
- return;
+ break;
bool run = e.action.wpStart.run ? true : false;
uint32 entry = e.action.wpStart.pathID;
@@ -1258,7 +1245,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_WP_PAUSE:
{
if (!IsSmart())
- return;
+ break;
uint32 delay = e.action.wpPause.delay;
CAST_AI(SmartAI, me->AI())->PausePath(delay, e.GetEventType() == SMART_EVENT_WAYPOINT_REACHED ? false : true);
@@ -1267,7 +1254,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_WP_STOP:
{
if (!IsSmart())
- return;
+ break;
uint32 DespawnTime = e.action.wpStop.despawnTime;
uint32 quest = e.action.wpStop.quest;
@@ -1278,7 +1265,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_WP_RESUME:
{
if (!IsSmart())
- return;
+ break;
CAST_AI(SmartAI, me->AI())->ResumePath();
break;
@@ -1286,15 +1273,15 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_SET_ORIENTATION:
{
if (!me)
- return;
+ break;
ObjectList* targets = GetTargets(e, unit);
if (e.GetTargetType() == SMART_TARGET_SELF)
- me->SetFacing(me->GetHomePosition().GetOrientation(), NULL);
+ me->SetFacingTo(me->GetHomePosition().GetOrientation());
else if (e.GetTargetType() == SMART_TARGET_POSITION)
- me->SetFacing(e.target.o, NULL);
+ me->SetFacingTo(e.target.o);
else if (targets && !targets->empty())
- me->SetFacing(0, (*targets->begin()));
+ me->SetFacingToObject(*targets->begin());
delete targets;
break;
@@ -1303,7 +1290,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -1319,7 +1306,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_MOVE_TO_POS:
{
if (!IsSmart())
- return;
+ break;
WorldObject* target = NULL;
@@ -1331,7 +1318,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
target = targets->front();
}
@@ -1346,7 +1333,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -1363,7 +1350,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
if (IsPlayer(*itr))
@@ -1376,7 +1363,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -1453,7 +1440,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -1493,7 +1480,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (e.GetTargetType() == SMART_TARGET_NONE)
{
sLog->outErrorDb("SmartScript: Entry %d SourceType %u Event %u Action %u is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
- return;
+ break;
}
ObjectList* targets = GetTargets(e, unit);
@@ -1521,7 +1508,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
if (IsUnit(*itr))
@@ -1534,7 +1521,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
if (IsUnit(*itr))
@@ -1547,7 +1534,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
if (IsUnit(*itr))
@@ -1560,13 +1547,13 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* casters = GetTargets(CreateEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, 0, 0, SMART_ACTION_NONE, 0, 0, 0, 0, 0, 0, (SMARTAI_TARGETS)e.action.cast.targetType, e.action.cast.targetParam1, e.action.cast.targetParam2, e.action.cast.targetParam3, 0), unit);
if (!casters)
- return;
+ break;
ObjectList* targets = GetTargets(e, unit);
if (!targets)
{
delete casters; // casters already validated, delete now
- return;
+ break;
}
for (ObjectList::const_iterator itr = casters->begin(); itr != casters->end(); ++itr)
@@ -1610,7 +1597,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (e.GetTargetType() == SMART_TARGET_NONE)
{
sLog->outErrorDb("SmartScript: Entry %d SourceType %u Event %u Action %u is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
- return;
+ break;
}
ObjectList* targets = GetTargets(e, unit);
@@ -1640,7 +1627,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (e.GetTargetType() == SMART_TARGET_NONE)
{
sLog->outErrorDb("SmartScript: Entry %d SourceType %u Event %u Action %u is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
- return;
+ break;
}
ObjectList* targets = GetTargets(e, unit);
@@ -1668,7 +1655,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
if (IsPlayer(*itr))
@@ -1681,7 +1668,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
@@ -1701,7 +1688,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
if (IsUnit(*itr))
(*itr)->ToUnit()->SetByteFlag(UNIT_FIELD_BYTES_1, 0, e.action.setunitByte.byte1);
@@ -1713,7 +1700,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
if (IsUnit(*itr))
@@ -1726,7 +1713,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
if (IsUnit(*itr))
@@ -1739,7 +1726,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
if (IsGameObject(*itr))
@@ -1752,7 +1739,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
if (IsUnit(*itr))
@@ -1765,7 +1752,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
if (IsUnit(*itr))
@@ -1778,7 +1765,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
if (IsUnit(*itr))
@@ -1790,24 +1777,65 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_JUMP_TO_POS:
{
if (!me)
- return;
+ break;
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz);
// TODO: Resume path when reached jump location
break;
}
+ case SMART_ACTION_GO_SET_LOOT_STATE:
+ {
+ ObjectList* targets = GetTargets(e, unit);
+
+ if (!targets)
+ break;
+
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ if (IsGameObject(*itr))
+ (*itr)->ToGameObject()->SetLootState((LootState)e.action.setGoLootState.state);
+
+ delete targets;
+ break;
+ }
+ case SMART_ACTION_SEND_TARGET_TO_TARGET:
+ {
+ ObjectList* targets = GetTargets(e, unit);
+ if (!targets)
+ break;
+
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ {
+ if (IsCreature(*itr))
+ {
+ if (SmartAI* ai = CAST_AI(SmartAI, (*itr)->ToCreature()->AI()))
+ ai->GetScript()->StoreTargetList(GetTargetList(e.action.sendTargetToTarget.id), e.action.sendTargetToTarget.id);
+ else
+ sLog->outErrorDb("SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartAI, skipping");
+ }
+ else if (IsGameObject(*itr))
+ {
+ if (SmartGameObjectAI* ai = CAST_AI(SmartGameObjectAI, (*itr)->ToGameObject()->AI()))
+ ai->GetScript()->StoreTargetList(GetTargetList(e.action.sendTargetToTarget.id), e.action.sendTargetToTarget.id);
+ else
+ sLog->outErrorDb("SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartGameObjectAI, skipping");
+ }
+ }
+
+ delete targets;
+ break;
+ }
case SMART_ACTION_SEND_GOSSIP_MENU:
{
if (!GetBaseObject())
- return;
+ break;
sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SEND_GOSSIP_MENU: gossipMenuId %d, gossipNpcTextId %d",
e.action.sendGossipMenu.gossipMenuId, e.action.sendGossipMenu.gossipNpcTextId);
ObjectList* targets = GetTargets(e, unit);
if (!targets)
- return;
+ break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
if (Player* player = (*itr)->ToPlayer())
@@ -1827,6 +1855,15 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
sLog->outErrorDb("SmartScript::ProcessAction: Unhandled Action type %u", e.GetActionType());
break;
}
+
+ if (e.link && e.link != e.event_id)
+ {
+ SmartScriptHolder linked = FindLinkedEvent(e.link);
+ if (linked.GetActionType() && linked.GetEventType() == SMART_EVENT_LINK)
+ ProcessEvent(linked, unit, var0, var1, bvar, spell, gob);
+ else
+ sLog->outErrorDb("SmartScript::ProcessAction: Entry %d SourceType %u, Event %u, Link Event %u not found or invalid, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link);
+ }
}
void SmartScript::InstallTemplate(SmartScriptHolder const& e)
@@ -2619,6 +2656,13 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
ProcessAction(e, NULL, var0);
break;
}
+ case SMART_EVENT_GO_STATE_CHANGED:
+ {
+ if (e.event.goStateChanged.state != var0)
+ return;
+ ProcessAction(e, unit, var0, var1);
+ break;
+ }
default:
sLog->outErrorDb("SmartScript::ProcessEvent: Unhandled Event type %u", e.GetEventType());
break;
@@ -3017,7 +3061,6 @@ void SmartScript::SetScript9(SmartScriptHolder& e, uint32 entry)
i->event.type = SMART_EVENT_UPDATE_IC;
else if (e.action.timedActionList.timerType > 1)
i->event.type = SMART_EVENT_UPDATE;
- mResumeActionList = e.action.timedActionList.dontResume ? false : true;
InitTimer((*i));
}
}
diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h
index 0193ac2bfb6..f55d91ed52f 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.h
+++ b/src/server/game/AI/SmartScripts/SmartScript.h
@@ -228,7 +228,6 @@ class SmartScript
SmartAIEventList mEvents;
SmartAIEventList mInstallEvents;
SmartAIEventList mTimedActionList;
- bool mResumeActionList;
Creature* me;
uint64 meOrigGUID;
GameObject* go;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 63595b2439f..9a23d9e1390 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -282,6 +282,7 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e)
case SMART_TARGET_HOSTILE_RANDOM:
case SMART_TARGET_HOSTILE_RANDOM_NOT_TOP:
case SMART_TARGET_ACTION_INVOKER:
+ case SMART_TARGET_INVOKER_PARTY:
case SMART_TARGET_POSITION:
case SMART_TARGET_NONE:
case SMART_TARGET_ACTION_INVOKER_VEHICLE:
@@ -478,6 +479,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
return false;
break;
}
+ case SMART_EVENT_GO_STATE_CHANGED:
case SMART_EVENT_TIMED_EVENT_TRIGGERED:
case SMART_EVENT_INSTANCE_PLAYER_ENTER:
case SMART_EVENT_TRANSPORT_RELOCATE:
@@ -800,6 +802,8 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_REMOVE_DYNAMIC_FLAG:
case SMART_ACTION_JUMP_TO_POS:
case SMART_ACTION_SEND_GOSSIP_MENU:
+ case SMART_ACTION_GO_SET_LOOT_STATE:
+ case SMART_ACTION_SEND_TARGET_TO_TARGET:
break;
default:
sLog->outErrorDb("SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index f56cf478bf8..123275ccc55 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -155,8 +155,9 @@ enum SMART_EVENT
SMART_EVENT_IS_BEHIND_TARGET = 67, //1 // cooldownMin, CooldownMax
SMART_EVENT_GAME_EVENT_START = 68, //1 // game_event.Entry
SMART_EVENT_GAME_EVENT_END = 69, //1 // game_event.Entry
+ SMART_EVENT_GO_STATE_CHANGED = 70, // go state
- SMART_EVENT_END = 70,
+ SMART_EVENT_END = 71,
};
struct SmartEvent
@@ -348,6 +349,11 @@ struct SmartEvent
struct
{
+ uint32 state;
+ } goStateChanged;
+
+ struct
+ {
uint32 param1;
uint32 param2;
uint32 param3;
@@ -467,8 +473,10 @@ enum SMART_ACTION
SMART_ACTION_REMOVE_DYNAMIC_FLAG = 96, // Flags
SMART_ACTION_JUMP_TO_POS = 97, // speedXY, speedZ, targetX, targetY, targetZ
SMART_ACTION_SEND_GOSSIP_MENU = 98, // menuId, optionId
+ SMART_ACTION_GO_SET_LOOT_STATE = 99, // state
+ SMART_ACTION_SEND_TARGET_TO_TARGET = 100, // id
- SMART_ACTION_END = 99,
+ SMART_ACTION_END = 101,
};
struct SmartAction
@@ -825,7 +833,6 @@ struct SmartAction
struct
{
uint32 id;
- uint32 dontResume;
uint32 timerType;
} timedActionList;
@@ -875,6 +882,16 @@ struct SmartAction
struct
{
+ uint32 state;
+ } setGoLootState;
+
+ struct
+ {
+ uint32 id;
+ } sendTargetToTarget;
+
+ struct
+ {
uint32 param1;
uint32 param2;
uint32 param3;
@@ -1139,6 +1156,7 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] =
{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 },
+ {SMART_EVENT_GO_STATE_CHANGED, SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
};
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp
index 78fad4bfe02..159a986367c 100755
--- a/src/server/game/Battlegrounds/Battleground.cpp
+++ b/src/server/game/Battlegrounds/Battleground.cpp
@@ -771,6 +771,7 @@ void Battleground::EndBattleground(uint32 winner)
}
}
+ uint8 aliveWinners = GetAlivePlayersCountByTeam(winner);
for (BattlegroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
uint32 team = itr->second.Team;
@@ -796,6 +797,10 @@ void Battleground::EndBattleground(uint32 winner)
if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
+ // Last standing - Rated 5v5 arena & be solely alive player
+ if (team == winner && isArena() && isRated() && GetArenaType() == ARENA_TYPE_5v5 && aliveWinners == 1 && player->isAlive())
+ player->CastSpell(player, SPELL_THE_LAST_STANDING, true);
+
if (!player->isAlive())
{
player->ResurrectPlayer(1.0f);
@@ -898,19 +903,6 @@ uint32 Battleground::GetBonusHonorFromKill(uint32 kills) const
return Trinity::Honor::hk_honor_at_level(maxLevel, float(kills));
}
-uint32 Battleground::GetBattlemasterEntry() const
-{
- switch (GetTypeID(true))
- {
- case BATTLEGROUND_AV: return 15972;
- case BATTLEGROUND_WS: return 14623;
- case BATTLEGROUND_AB: return 14879;
- case BATTLEGROUND_EY: return 22516;
- case BATTLEGROUND_NA: return 20200;
- default: return 0;
- }
-}
-
void Battleground::BlockMovement(Player* player)
{
player->SetClientControl(player, 0); // movement disabled NOTE: the effect will be automatically removed by client when the player is teleported from the battleground, so no need to send with uint8(1) in RemovePlayerAtLeave()
diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h
index fcfc0c48cb4..6eb64a2caba 100755
--- a/src/server/game/Battlegrounds/Battleground.h
+++ b/src/server/game/Battlegrounds/Battleground.h
@@ -98,7 +98,8 @@ enum BattlegroundSpells
SPELL_RECENTLY_DROPPED_FLAG = 42792, // Recently Dropped Flag
SPELL_AURA_PLAYER_INACTIVE = 43681, // Inactive
SPELL_HONORABLE_DEFENDER_25Y = 68652, // +50% honor when standing at a capture point that you control, 25yards radius (added in 3.2)
- SPELL_HONORABLE_DEFENDER_60Y = 66157 // +50% honor when standing at a capture point that you control, 60yards radius (added in 3.2), probably for 40+ player battlegrounds
+ SPELL_HONORABLE_DEFENDER_60Y = 66157, // +50% honor when standing at a capture point that you control, 60yards radius (added in 3.2), probably for 40+ player battlegrounds
+ SPELL_THE_LAST_STANDING = 26549, // Arena achievement related
};
enum BattlegroundTimeIntervals
@@ -360,7 +361,6 @@ class Battleground
uint8 GetArenaType() const { return m_ArenaType; }
uint8 GetWinner() const { return m_Winner; }
uint32 GetScriptId() const { return ScriptId; }
- uint32 GetBattlemasterEntry() const;
uint32 GetBonusHonorFromKill(uint32 kills) const;
bool IsRandom() const { return m_IsRandom; }
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
index d64b2a9913d..5e529768c04 100755
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
@@ -202,6 +202,9 @@ void BattlegroundAB::StartingEventOpenDoors()
}
DoorOpen(BG_AB_OBJECT_GATE_A);
DoorOpen(BG_AB_OBJECT_GATE_H);
+
+ // Achievement: Let's Get This Done
+ StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, AB_EVENT_START_BATTLE);
}
void BattlegroundAB::AddPlayer(Player* player)
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h
index 38c8f4a21d4..c86076f0250 100755
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h
@@ -181,6 +181,8 @@ enum BG_AB_Objectives
#define BG_AB_NotABBGWeekendReputationTicks 200
#define BG_AB_ABBGWeekendReputationTicks 150
+#define AB_EVENT_START_BATTLE 9158 // Achievement: Let's Get This Done
+
// x, y, z, o
const float BG_AB_NodePositions[BG_AB_DYNAMIC_NODES_COUNT][4] = {
{1166.785f, 1200.132f, -56.70859f, 0.9075713f}, // stables
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
index 01f62bfcf35..f2e8c2bf0af 100755
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
@@ -420,6 +420,9 @@ void BattlegroundAV::StartingEventOpenDoors()
DoorOpen(BG_AV_OBJECT_DOOR_H);
DoorOpen(BG_AV_OBJECT_DOOR_A);
+
+ // Achievement: The Alterac Blitz
+ StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, AV_EVENT_START_BATTLE);
}
void BattlegroundAV::AddPlayer(Player* player)
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h
index e2902f8fd2d..82e231c63fa 100755
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h
@@ -50,6 +50,8 @@ class Battleground;
#define BG_AV_KILL_SURVIVING_CAPTAIN 2
#define BG_AV_REP_SURVIVING_CAPTAIN 125
+#define AV_EVENT_START_BATTLE 9166 // Achievement: The Alterac Blitz
+
enum BG_AV_Sounds
{ //TODO: get out if there comes a sound when neutral team captures mine
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
index 4595a061e1a..cbc3ec85055 100755
--- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
@@ -120,6 +120,9 @@ void BattlegroundEY::StartingEventOpenDoors()
uint8 buff = urand(0, 2);
SpawnBGObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REAVER + buff + i * 3, RESPAWN_IMMEDIATELY);
}
+
+ // Achievement: Flurry
+ StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EY_EVENT_START_BATTLE);
}
void BattlegroundEY::AddPoints(uint32 Team, uint32 Points)
@@ -193,7 +196,6 @@ void BattlegroundEY::CheckSomeoneLeftPoint()
//move not existed player to "free space" - this will cause many error showing in log, but it is a very important bug
m_PlayersNearPoint[EY_POINTS_MAX].push_back(m_PlayersNearPoint[i][j]);
m_PlayersNearPoint[i].erase(m_PlayersNearPoint[i].begin() + j);
- ++j;
continue;
}
if (!player->CanCaptureTowerPoint() || !player->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS))
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h
index 5f89e0d7021..baa9ca30cff 100755
--- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h
@@ -220,6 +220,8 @@ enum EYBattlegroundObjectTypes
#define BG_EY_NotEYWeekendHonorTicks 330
#define BG_EY_EYWeekendHonorTicks 200
+#define EY_EVENT_START_BATTLE 13180 // Achievement: Flurry
+
enum BG_EY_Score
{
BG_EY_WARNING_NEAR_VICTORY_SCORE = 1400,
diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt
index 117a8f680ee..745e5962eb6 100644
--- a/src/server/game/CMakeLists.txt
+++ b/src/server/game/CMakeLists.txt
@@ -30,6 +30,7 @@ file(GLOB_RECURSE sources_Globals Globals/*.cpp Globals/*.h)
file(GLOB_RECURSE sources_Grids Grids/*.cpp Grids/*.h)
file(GLOB_RECURSE sources_Groups Groups/*.cpp Groups/*.h)
file(GLOB_RECURSE sources_Guilds Guilds/*.cpp Guilds/*.h)
+file(GLOB_RECURSE sources_Handlers Handlers/*.cpp Server/*.h)
file(GLOB_RECURSE sources_Instances Instances/*.cpp Instances/*.h)
file(GLOB_RECURSE sources_Loot Loot/*.cpp Loot/*.h)
file(GLOB_RECURSE sources_Mails Mails/*.cpp Mails/*.h)
@@ -79,6 +80,7 @@ set(game_STAT_SRCS
${sources_Grids}
${sources_Groups}
${sources_Guilds}
+ ${sources_Handlers}
${sources_Instances}
${sources_Loot}
${sources_Mails}
@@ -102,6 +104,7 @@ set(game_STAT_SRCS
include_directories(
${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/mersennetwister
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/dep/zlib
@@ -114,12 +117,10 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/server/shared/Database
${CMAKE_SOURCE_DIR}/src/server/shared/DataStores
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
- ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/CountedReference
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic
${CMAKE_SOURCE_DIR}/src/server/shared/Logging
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
- ${CMAKE_SOURCE_DIR}/src/server/shared/Policies
${CMAKE_SOURCE_DIR}/src/server/shared/Threading
${CMAKE_SOURCE_DIR}/src/server/shared/Utilities
${CMAKE_CURRENT_SOURCE_DIR}
@@ -164,12 +165,14 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/Grids
${CMAKE_CURRENT_SOURCE_DIR}/Groups
${CMAKE_CURRENT_SOURCE_DIR}/Guilds
+ ${CMAKE_CURRENT_SOURCE_DIR}/Handlers
${CMAKE_CURRENT_SOURCE_DIR}/Instances
${CMAKE_CURRENT_SOURCE_DIR}/Loot
${CMAKE_CURRENT_SOURCE_DIR}/Mails
${CMAKE_CURRENT_SOURCE_DIR}/Maps
${CMAKE_CURRENT_SOURCE_DIR}/Miscellaneous
${CMAKE_CURRENT_SOURCE_DIR}/Movement
+ ${CMAKE_CURRENT_SOURCE_DIR}/Movement/Spline
${CMAKE_CURRENT_SOURCE_DIR}/Movement/MovementGenerators
${CMAKE_CURRENT_SOURCE_DIR}/Movement/Waypoints
${CMAKE_CURRENT_SOURCE_DIR}/OutdoorPvP
@@ -179,7 +182,6 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/Reputation
${CMAKE_CURRENT_SOURCE_DIR}/Scripting
${CMAKE_CURRENT_SOURCE_DIR}/Server/Protocol
- ${CMAKE_CURRENT_SOURCE_DIR}/Server/Protocol/Handlers
${CMAKE_CURRENT_SOURCE_DIR}/Server
${CMAKE_CURRENT_SOURCE_DIR}/Skills
${CMAKE_CURRENT_SOURCE_DIR}/Spells
diff --git a/src/server/game/Chat/Commands/Level2.cpp b/src/server/game/Chat/Commands/Level2.cpp
index ef91d39e6cb..b0c0bbf6890 100755
--- a/src/server/game/Chat/Commands/Level2.cpp
+++ b/src/server/game/Chat/Commands/Level2.cpp
@@ -332,8 +332,8 @@ bool ChatHandler::HandlePInfoCommand(const char* args)
QueryResult result = LoginDatabase.PQuery("SELECT a.username, aa.gmlevel, a.email, a.last_ip, a.last_login, a.mutetime "
"FROM account a "
"LEFT JOIN account_access aa "
- "ON (a.id = aa.id) "
- "WHERE a.id = '%u'", accId);
+ "ON (a.id = aa.id AND (aa.RealmID = -1 OR aa.RealmID = %u)) "
+ "WHERE a.id = '%u'", realmID, accId);
if (result)
{
Field* fields = result->Fetch();
@@ -714,19 +714,20 @@ bool ChatHandler::HandleLookupPlayerIpCommand(const char* args)
char* limit_str;
Player *chr = getSelectedPlayer();
- if (chr == NULL)
+ if (!*args)
{
- if (!*args)
+ // NULL only if used from console
+ if (!chr || chr == GetSession()->GetPlayer())
return false;
- ip = strtok ((char*)args, " ");
- limit_str = strtok (NULL, " ");
- limit = limit_str ? atoi (limit_str) : -1;
+ ip = chr->GetSession()->GetRemoteAddress();
+ limit = -1;
}
else
{
- ip = chr->GetSession()->GetRemoteAddress();
- limit = -1;
+ ip = strtok ((char*)args, " ");
+ limit_str = strtok (NULL, " ");
+ limit = limit_str ? atoi (limit_str) : -1;
}
LoginDatabase.EscapeString(ip);
diff --git a/src/server/game/Chat/Commands/Level3.cpp b/src/server/game/Chat/Commands/Level3.cpp
index df35a8ed906..1cb07fca4a8 100755
--- a/src/server/game/Chat/Commands/Level3.cpp
+++ b/src/server/game/Chat/Commands/Level3.cpp
@@ -3690,6 +3690,9 @@ bool ChatHandler::HandleMovegensCommand(const char* /*args*/)
PSendSysMessage(LANG_MOVEGENS_LIST, (unit->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), unit->GetGUIDLow());
MotionMaster* mm = unit->GetMotionMaster();
+ float x,y,z;
+ mm->GetDestination(x,y,z);
+
for (uint8 i = 0; i < MAX_MOTION_SLOT; ++i)
{
MovementGenerator* mg = mm->GetMotionSlot(i);
@@ -3705,48 +3708,55 @@ bool ChatHandler::HandleMovegensCommand(const char* /*args*/)
case WAYPOINT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_WAYPOINT); break;
case ANIMAL_RANDOM_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_ANIMAL_RANDOM); break;
case CONFUSED_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_CONFUSED); break;
- case TARGETED_MOTION_TYPE:
+ case CHASE_MOTION_TYPE:
{
+ Unit* target = NULL;
if (unit->GetTypeId() == TYPEID_PLAYER)
- {
- TargetedMovementGenerator<Player> const* mgen = static_cast<TargetedMovementGenerator<Player> const*>(mg);
- Unit* target = mgen->GetTarget();
- if (target)
- PSendSysMessage(LANG_MOVEGENS_TARGETED_PLAYER, target->GetName(), target->GetGUIDLow());
- else
- SendSysMessage(LANG_MOVEGENS_TARGETED_NULL);
- }
+ target = static_cast<ChaseMovementGenerator<Player> const*>(mg)->GetTarget();
else
- {
- TargetedMovementGenerator<Creature> const* mgen = static_cast<TargetedMovementGenerator<Creature> const*>(mg);
- Unit* target = mgen->GetTarget();
- if (target)
- PSendSysMessage(LANG_MOVEGENS_TARGETED_CREATURE, target->GetName(), target->GetGUIDLow());
- else
- SendSysMessage(LANG_MOVEGENS_TARGETED_NULL);
- }
+ target = static_cast<ChaseMovementGenerator<Creature> const*>(mg)->GetTarget();
+
+ if (!target)
+ SendSysMessage(LANG_MOVEGENS_CHASE_NULL);
+ else if (target->GetTypeId() == TYPEID_PLAYER)
+ PSendSysMessage(LANG_MOVEGENS_CHASE_PLAYER, target->GetName(), target->GetGUIDLow());
+ else
+ PSendSysMessage(LANG_MOVEGENS_CHASE_CREATURE, target->GetName(), target->GetGUIDLow());
break;
}
+ case FOLLOW_MOTION_TYPE:
+ {
+ Unit* target = NULL;
+ if (unit->GetTypeId() == TYPEID_PLAYER)
+ target = static_cast<FollowMovementGenerator<Player> const*>(mg)->GetTarget();
+ else
+ target = static_cast<FollowMovementGenerator<Creature> const*>(mg)->GetTarget();
+
+ if (!target)
+ SendSysMessage(LANG_MOVEGENS_FOLLOW_NULL);
+ else if (target->GetTypeId() == TYPEID_PLAYER)
+ PSendSysMessage(LANG_MOVEGENS_FOLLOW_PLAYER, target->GetName(), target->GetGUIDLow());
+ else
+ PSendSysMessage(LANG_MOVEGENS_FOLLOW_CREATURE, target->GetName(), target->GetGUIDLow());
+ break;
+ }
case HOME_MOTION_TYPE:
+ {
if (unit->GetTypeId() == TYPEID_UNIT)
- {
- float x, y, z;
- mg->GetDestination(x, y, z);
PSendSysMessage(LANG_MOVEGENS_HOME_CREATURE, x, y, z);
- }
else
SendSysMessage(LANG_MOVEGENS_HOME_PLAYER);
break;
+ }
case FLIGHT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FLIGHT); break;
case POINT_MOTION_TYPE:
{
- float x, y, z;
- mg->GetDestination(x, y, z);
PSendSysMessage(LANG_MOVEGENS_POINT, x, y, z);
break;
}
case FLEEING_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FEAR); break;
case DISTRACT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_DISTRACT); break;
+ case EFFECT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_EFFECT); break;
default:
PSendSysMessage(LANG_MOVEGENS_UNKNOWN, mg->GetMovementGeneratorType());
break;
@@ -4038,19 +4048,14 @@ bool ChatHandler::HandleComeToMeCommand(const char *args)
if (!newFlagStr)
return false;
- uint32 newFlags = (uint32)strtoul(newFlagStr, NULL, 0);
-
Creature* caster = getSelectedCreature();
if (!caster)
{
- m_session->GetPlayer()->SetUnitMovementFlags(newFlags);
SendSysMessage(LANG_SELECT_CREATURE);
SetSentErrorMessage(true);
return false;
}
- caster->SetUnitMovementFlags(newFlags);
-
Player* player = m_session->GetPlayer();
caster->GetMotionMaster()->MovePoint(0, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index 0bcd1a7864b..a745c5a2f13 100755
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -63,7 +63,7 @@ bool Condition::Meets(Player* player, Unit* invoker)
case CONDITION_REPUTATION_RANK:
{
if (FactionEntry const* faction = sFactionStore.LookupEntry(mConditionValue1))
- condMeets = uint32(player->GetReputationMgr().GetRank(faction)) == mConditionValue2;
+ condMeets = (mConditionValue2 & (1 << player->GetReputationMgr().GetRank(faction)));
break;
}
case CONDITION_ACHIEVEMENT:
@@ -73,10 +73,10 @@ bool Condition::Meets(Player* player, Unit* invoker)
condMeets = player->GetTeam() == mConditionValue1;
break;
case CONDITION_CLASS:
- condMeets = player->getClass() == mConditionValue1;
+ condMeets = player->getClassMask() & mConditionValue1;
break;
case CONDITION_RACE:
- condMeets = player->getRace() == mConditionValue1;
+ condMeets = player->getRaceMask() & mConditionValue1;
break;
case CONDITION_SKILL:
condMeets = player->HasSkill(mConditionValue1) && player->GetBaseSkillValue(mConditionValue1) >= mConditionValue2;
@@ -243,33 +243,33 @@ ConditionMgr::~ConditionMgr()
ConditionList ConditionMgr::GetConditionReferences(uint32 refId)
{
ConditionList conditions;
- ConditionReferenceMap::const_iterator ref = m_ConditionReferenceMap.find(refId);
- if (ref != m_ConditionReferenceMap.end())
+ ConditionReferenceContainer::const_iterator ref = ConditionReferenceStore.find(refId);
+ if (ref != ConditionReferenceStore.end())
conditions = (*ref).second;
return conditions;
}
bool ConditionMgr::IsPlayerMeetToConditionList(Player* player, ConditionList const& conditions, Unit* invoker /*= NULL*/)
{
- std::map<uint32, bool> ElseGroupMap;
+ std::map<uint32, bool> ElseGroupStore;
for (ConditionList::const_iterator i = conditions.begin(); i != conditions.end(); ++i)
{
sLog->outDebug(LOG_FILTER_CONDITIONSYS, "ConditionMgr::IsPlayerMeetToConditionList condType: %u val1: %u", (*i)->mConditionType, (*i)->mConditionValue1);
if ((*i)->isLoaded())
{
- std::map<uint32, bool>::const_iterator itr = ElseGroupMap.find((*i)->mElseGroup);
- if (itr == ElseGroupMap.end())
- ElseGroupMap[(*i)->mElseGroup] = true;
+ std::map<uint32, bool>::const_iterator itr = ElseGroupStore.find((*i)->mElseGroup);
+ if (itr == ElseGroupStore.end())
+ ElseGroupStore[(*i)->mElseGroup] = true;
else if (!(*itr).second)
continue;
if ((*i)->mReferenceId)//handle reference
{
- ConditionReferenceMap::const_iterator ref = m_ConditionReferenceMap.find((*i)->mReferenceId);
- if (ref != m_ConditionReferenceMap.end())
+ ConditionReferenceContainer::const_iterator ref = ConditionReferenceStore.find((*i)->mReferenceId);
+ if (ref != ConditionReferenceStore.end())
{
if (!IsPlayerMeetToConditionList(player, (*ref).second, invoker))
- ElseGroupMap[(*i)->mElseGroup] = false;
+ ElseGroupStore[(*i)->mElseGroup] = false;
}
else
{
@@ -281,11 +281,11 @@ bool ConditionMgr::IsPlayerMeetToConditionList(Player* player, ConditionList con
else //handle normal condition
{
if (!(*i)->Meets(player, invoker))
- ElseGroupMap[(*i)->mElseGroup] = false;
+ ElseGroupStore[(*i)->mElseGroup] = false;
}
}
}
- for (std::map<uint32, bool>::const_iterator i = ElseGroupMap.begin(); i != ElseGroupMap.end(); ++i)
+ for (std::map<uint32, bool>::const_iterator i = ElseGroupStore.begin(); i != ElseGroupStore.end(); ++i)
if (i->second)
return true;
@@ -309,19 +309,19 @@ bool ConditionMgr::IsPlayerMeetToConditions(Player* player, ConditionList const&
return result;
}
-ConditionList ConditionMgr::GetConditionsForNotGroupedEntry(ConditionSourceType sType, uint32 uEntry)
+ConditionList ConditionMgr::GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry)
{
ConditionList spellCond;
- if (sType > CONDITION_SOURCE_TYPE_NONE && sType < CONDITION_SOURCE_TYPE_MAX)
+ if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX)
{
- ConditionMap::const_iterator itr = m_ConditionMap.find(sType);
- if (itr != m_ConditionMap.end())
+ ConditionContainer::const_iterator itr = ConditionStore.find(sourceType);
+ if (itr != ConditionStore.end())
{
- ConditionTypeMap::const_iterator i = (*itr).second.find(uEntry);
+ ConditionTypeContainer::const_iterator i = (*itr).second.find(entry);
if (i != (*itr).second.end())
{
spellCond = (*i).second;
- sLog->outDebug(LOG_FILTER_CONDITIONSYS, "GetConditionsForNotGroupedEntry: found conditions for type %u and entry %u", uint32(sType), uEntry);
+ sLog->outDebug(LOG_FILTER_CONDITIONSYS, "GetConditionsForNotGroupedEntry: found conditions for type %u and entry %u", uint32(sourceType), entry);
}
}
}
@@ -331,10 +331,10 @@ ConditionList ConditionMgr::GetConditionsForNotGroupedEntry(ConditionSourceType
ConditionList ConditionMgr::GetConditionsForVehicleSpell(uint32 creatureID, uint32 spellID)
{
ConditionList cond;
- VehicleSpellConditionMap::const_iterator itr = m_VehicleSpellConditions.find(creatureID);
- if (itr != m_VehicleSpellConditions.end())
+ VehicleSpellConditionContainer::const_iterator itr = VehicleSpellConditionStore.find(creatureID);
+ if (itr != VehicleSpellConditionStore.end())
{
- ConditionTypeMap::const_iterator i = (*itr).second.find(spellID);
+ ConditionTypeContainer::const_iterator i = (*itr).second.find(spellID);
if (i != (*itr).second.end())
{
cond = (*i).second;
@@ -344,6 +344,22 @@ ConditionList ConditionMgr::GetConditionsForVehicleSpell(uint32 creatureID, uint
return cond;
}
+ConditionList ConditionMgr::GetConditionsForSmartEvent(uint32 entry, uint32 eventId, uint32 sourceType)
+{
+ ConditionList cond;
+ SmartEventConditionContainer::const_iterator itr = SmartEventConditionStore.find(std::make_pair(entry, sourceType));
+ if (itr != SmartEventConditionStore.end())
+ {
+ ConditionTypeContainer::const_iterator i = (*itr).second.find(eventId + 1);
+ if (i != (*itr).second.end())
+ {
+ cond = (*i).second;
+ sLog->outDebug(LOG_FILTER_CONDITIONSYS, "GetConditionsForSmartEvent: found conditions for Smart Event entry %u event_id %u", entry, eventId);
+ }
+ }
+ return cond;
+}
+
void ConditionMgr::LoadConditions(bool isReload)
{
uint32 oldMSTime = getMSTime();
@@ -374,7 +390,7 @@ void ConditionMgr::LoadConditions(bool isReload)
sObjectMgr->LoadGossipMenuItems();
}
- QueryResult result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, ElseGroup, ConditionTypeOrReference, "
+ QueryResult result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, SourceId, ElseGroup, ConditionTypeOrReference, "
" ConditionValue1, ConditionValue2, ConditionValue3, ErrorTextId, ScriptName FROM conditions");
if (!result)
@@ -395,13 +411,14 @@ void ConditionMgr::LoadConditions(bool isReload)
int32 iSourceTypeOrReferenceId = fields[0].GetInt32();
cond->mSourceGroup = fields[1].GetUInt32();
cond->mSourceEntry = fields[2].GetUInt32();
- cond->mElseGroup = fields[3].GetUInt32();
- int32 iConditionTypeOrReference = fields[4].GetInt32();
- cond->mConditionValue1 = fields[5].GetUInt32();
- cond->mConditionValue2 = fields[6].GetUInt32();
- cond->mConditionValue3 = fields[7].GetUInt32();
- cond->ErrorTextd = fields[8].GetUInt32();
- cond->mScriptId = sObjectMgr->GetScriptId(fields[9].GetCString());
+ cond->mSourceId = fields[3].GetUInt32();
+ cond->mElseGroup = fields[4].GetUInt32();
+ int32 iConditionTypeOrReference = fields[5].GetInt32();
+ cond->mConditionValue1 = fields[6].GetUInt32();
+ cond->mConditionValue2 = fields[7].GetUInt32();
+ cond->mConditionValue3 = fields[8].GetUInt32();
+ cond->ErrorTextd = fields[9].GetUInt32();
+ cond->mScriptId = sObjectMgr->GetScriptId(fields[10].GetCString());
if (iConditionTypeOrReference >= 0)
cond->mConditionType = ConditionType(iConditionTypeOrReference);
@@ -440,12 +457,12 @@ void ConditionMgr::LoadConditions(bool isReload)
if (iSourceTypeOrReferenceId < 0)//it is a reference template
{
uint32 uRefId = abs(iSourceTypeOrReferenceId);
- if (m_ConditionReferenceMap.find(uRefId) == m_ConditionReferenceMap.end())//make sure we have a list for our conditions, based on reference id
+ if (ConditionReferenceStore.find(uRefId) == ConditionReferenceStore.end())//make sure we have a list for our conditions, based on reference id
{
ConditionList mCondList;
- m_ConditionReferenceMap[uRefId] = mCondList;
+ ConditionReferenceStore[uRefId] = mCondList;
}
- m_ConditionReferenceMap[uRefId].push_back(cond);//add to reference storage
+ ConditionReferenceStore[uRefId].push_back(cond);//add to reference storage
count++;
continue;
}//end of reference templates
@@ -468,83 +485,102 @@ void ConditionMgr::LoadConditions(bool isReload)
}
else if (cond->mSourceGroup)
{
- bool bIsDone = false;
+ bool valid = false;
//handle grouped conditions
switch (cond->mSourceType)
{
case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE:
- bIsDone = addToLootTemplate(cond, LootTemplates_Creature.GetLootForConditionFill(cond->mSourceGroup));
+ valid = addToLootTemplate(cond, LootTemplates_Creature.GetLootForConditionFill(cond->mSourceGroup));
break;
case CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE:
- bIsDone = addToLootTemplate(cond, LootTemplates_Disenchant.GetLootForConditionFill(cond->mSourceGroup));
+ valid = addToLootTemplate(cond, LootTemplates_Disenchant.GetLootForConditionFill(cond->mSourceGroup));
break;
case CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE:
- bIsDone = addToLootTemplate(cond, LootTemplates_Fishing.GetLootForConditionFill(cond->mSourceGroup));
+ valid = addToLootTemplate(cond, LootTemplates_Fishing.GetLootForConditionFill(cond->mSourceGroup));
break;
case CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE:
- bIsDone = addToLootTemplate(cond, LootTemplates_Gameobject.GetLootForConditionFill(cond->mSourceGroup));
+ valid = addToLootTemplate(cond, LootTemplates_Gameobject.GetLootForConditionFill(cond->mSourceGroup));
break;
case CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE:
- bIsDone = addToLootTemplate(cond, LootTemplates_Item.GetLootForConditionFill(cond->mSourceGroup));
+ valid = addToLootTemplate(cond, LootTemplates_Item.GetLootForConditionFill(cond->mSourceGroup));
break;
case CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE:
- bIsDone = addToLootTemplate(cond, LootTemplates_Mail.GetLootForConditionFill(cond->mSourceGroup));
+ valid = addToLootTemplate(cond, LootTemplates_Mail.GetLootForConditionFill(cond->mSourceGroup));
break;
case CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE:
- bIsDone = addToLootTemplate(cond, LootTemplates_Milling.GetLootForConditionFill(cond->mSourceGroup));
+ valid = addToLootTemplate(cond, LootTemplates_Milling.GetLootForConditionFill(cond->mSourceGroup));
break;
case CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE:
- bIsDone = addToLootTemplate(cond, LootTemplates_Pickpocketing.GetLootForConditionFill(cond->mSourceGroup));
+ valid = addToLootTemplate(cond, LootTemplates_Pickpocketing.GetLootForConditionFill(cond->mSourceGroup));
break;
case CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE:
- bIsDone = addToLootTemplate(cond, LootTemplates_Prospecting.GetLootForConditionFill(cond->mSourceGroup));
+ valid = addToLootTemplate(cond, LootTemplates_Prospecting.GetLootForConditionFill(cond->mSourceGroup));
break;
case CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE:
- bIsDone = addToLootTemplate(cond, LootTemplates_Reference.GetLootForConditionFill(cond->mSourceGroup));
+ valid = addToLootTemplate(cond, LootTemplates_Reference.GetLootForConditionFill(cond->mSourceGroup));
break;
case CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE:
- bIsDone = addToLootTemplate(cond, LootTemplates_Skinning.GetLootForConditionFill(cond->mSourceGroup));
+ valid = addToLootTemplate(cond, LootTemplates_Skinning.GetLootForConditionFill(cond->mSourceGroup));
break;
case CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE:
- bIsDone = addToLootTemplate(cond, LootTemplates_Spell.GetLootForConditionFill(cond->mSourceGroup));
+ valid = addToLootTemplate(cond, LootTemplates_Spell.GetLootForConditionFill(cond->mSourceGroup));
break;
case CONDITION_SOURCE_TYPE_GOSSIP_MENU:
- bIsDone = addToGossipMenus(cond);
+ valid = addToGossipMenus(cond);
break;
case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION:
- bIsDone = addToGossipMenuItems(cond);
+ valid = addToGossipMenuItems(cond);
break;
case CONDITION_SOURCE_TYPE_VEHICLE_SPELL:
{
//if no list for vehicle create one
- if (m_VehicleSpellConditions.find(cond->mSourceGroup) == m_VehicleSpellConditions.end())
+ if (VehicleSpellConditionStore.find(cond->mSourceGroup) == VehicleSpellConditionStore.end())
{
- ConditionTypeMap cmap;
- m_VehicleSpellConditions[cond->mSourceGroup] = cmap;
+ ConditionTypeContainer cmap;
+ VehicleSpellConditionStore[cond->mSourceGroup] = cmap;
}
//if no list for vehicle's spell create one
- if (m_VehicleSpellConditions[cond->mSourceGroup].find(cond->mSourceEntry) == m_VehicleSpellConditions[cond->mSourceGroup].end())
+ if (VehicleSpellConditionStore[cond->mSourceGroup].find(cond->mSourceEntry) == VehicleSpellConditionStore[cond->mSourceGroup].end())
{
ConditionList clist;
- m_VehicleSpellConditions[cond->mSourceGroup][cond->mSourceEntry] = clist;
+ VehicleSpellConditionStore[cond->mSourceGroup][cond->mSourceEntry] = clist;
}
- m_VehicleSpellConditions[cond->mSourceGroup][cond->mSourceEntry].push_back(cond);
- bIsDone = true;
+ VehicleSpellConditionStore[cond->mSourceGroup][cond->mSourceEntry].push_back(cond);
+ valid = true;
++count;
continue; // do not add to m_AllocatedMemory to avoid double deleting
}
+ case CONDITION_SOURCE_TYPE_SMART_EVENT:
+ {
+ // If the entry does not exist, create a new list
+ std::pair<uint32, uint32> key = std::make_pair(cond->mSourceEntry, cond->mSourceId);
+ if (SmartEventConditionStore.find(key) == SmartEventConditionStore.end())
+ {
+ ConditionTypeContainer cmap;
+ SmartEventConditionStore[key] = cmap;
+ }
+ if (SmartEventConditionStore[key].find(cond->mSourceGroup) == SmartEventConditionStore[key].end())
+ {
+ ConditionList clist;
+ SmartEventConditionStore[key][cond->mSourceGroup] = clist;
+ }
+ SmartEventConditionStore[key][cond->mSourceGroup].push_back(cond);
+ valid = true;
+ ++count;
+ continue;
+ }
default:
break;
}
- if (!bIsDone)
+ if (!valid)
{
sLog->outErrorDb("Not handled grouped condition, SourceGroup %u", cond->mSourceGroup);
delete cond;
}
else
{
- m_AllocatedMemory.push_back(cond);
+ AllocatedMemoryStore.push_back(cond);
++count;
}
continue;
@@ -552,21 +588,21 @@ void ConditionMgr::LoadConditions(bool isReload)
//handle not grouped conditions
//make sure we have a storage list for our SourceType
- if (m_ConditionMap.find(cond->mSourceType) == m_ConditionMap.end())
+ if (ConditionStore.find(cond->mSourceType) == ConditionStore.end())
{
- ConditionTypeMap mTypeMap;
- m_ConditionMap[cond->mSourceType] = mTypeMap;//add new empty list for SourceType
+ ConditionTypeContainer mTypeMap;
+ ConditionStore[cond->mSourceType] = mTypeMap;//add new empty list for SourceType
}
//make sure we have a condition list for our SourceType's entry
- if (m_ConditionMap[cond->mSourceType].find(cond->mSourceEntry) == m_ConditionMap[cond->mSourceType].end())
+ if (ConditionStore[cond->mSourceType].find(cond->mSourceEntry) == ConditionStore[cond->mSourceType].end())
{
ConditionList mCondList;
- m_ConditionMap[cond->mSourceType][cond->mSourceEntry] = mCondList;
+ ConditionStore[cond->mSourceType][cond->mSourceEntry] = mCondList;
}
//add new Condition to storage based on Type/Entry
- m_ConditionMap[cond->mSourceType][cond->mSourceEntry].push_back(cond);
+ ConditionStore[cond->mSourceType][cond->mSourceEntry].push_back(cond);
++count;
}
while (result->NextRow());
@@ -1004,6 +1040,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond)
break;
case CONDITION_SOURCE_TYPE_GOSSIP_MENU:
case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION:
+ case CONDITION_SOURCE_TYPE_SMART_EVENT:
case CONDITION_SOURCE_TYPE_NONE:
default:
break;
@@ -1180,9 +1217,9 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
}
case CONDITION_CLASS:
{
- if (cond->mConditionValue1 >= MAX_CLASSES)
+ if (!(cond->mConditionValue1 & CLASSMASK_ALL_PLAYABLE))
{
- sLog->outErrorDb("Class condition has non existing class (%u), skipped", cond->mConditionValue1);
+ sLog->outErrorDb("Class condition has non existing classmask (%u), skipped", cond->mConditionValue1 & ~CLASSMASK_ALL_PLAYABLE);
return false;
}
@@ -1192,9 +1229,9 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
}
case CONDITION_RACE:
{
- if (cond->mConditionValue1 >= MAX_RACES)
+ if (!(cond->mConditionValue1 & RACEMASK_ALL_PLAYABLE))
{
- sLog->outErrorDb("Race condition has non existing race (%u), skipped", cond->mConditionValue1);
+ sLog->outErrorDb("Race condition has non existing racemask (%u), skipped", cond->mConditionValue1 & ~RACEMASK_ALL_PLAYABLE);
return false;
}
@@ -1375,18 +1412,31 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
void ConditionMgr::Clean()
{
- for (ConditionReferenceMap::iterator itr = m_ConditionReferenceMap.begin(); itr != m_ConditionReferenceMap.end(); ++itr)
+ for (ConditionReferenceContainer::iterator itr = ConditionReferenceStore.begin(); itr != ConditionReferenceStore.end(); ++itr)
{
for (ConditionList::const_iterator it = itr->second.begin(); it != itr->second.end(); ++it)
delete *it;
itr->second.clear();
}
- m_ConditionReferenceMap.clear();
+ ConditionReferenceStore.clear();
+
+ for (ConditionContainer::iterator itr = ConditionStore.begin(); itr != ConditionStore.end(); ++itr)
+ {
+ for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
+ {
+ for (ConditionList::const_iterator i = it->second.begin(); i != it->second.end(); ++i)
+ delete *i;
+ it->second.clear();
+ }
+ itr->second.clear();
+ }
+
+ ConditionStore.clear();
- for (ConditionMap::iterator itr = m_ConditionMap.begin(); itr != m_ConditionMap.end(); ++itr)
+ for (VehicleSpellConditionContainer::iterator itr = VehicleSpellConditionStore.begin(); itr != VehicleSpellConditionStore.end(); ++itr)
{
- for (ConditionTypeMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
+ for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
{
for (ConditionList::const_iterator i = it->second.begin(); i != it->second.end(); ++i)
delete *i;
@@ -1395,11 +1445,11 @@ void ConditionMgr::Clean()
itr->second.clear();
}
- m_ConditionMap.clear();
+ VehicleSpellConditionStore.clear();
- for (VehicleSpellConditionMap::iterator itr = m_VehicleSpellConditions.begin(); itr != m_VehicleSpellConditions.end(); ++itr)
+ for (SmartEventConditionContainer::iterator itr = SmartEventConditionStore.begin(); itr != SmartEventConditionStore.end(); ++itr)
{
- for (ConditionTypeMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
+ for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
{
for (ConditionList::const_iterator i = it->second.begin(); i != it->second.end(); ++i)
delete *i;
@@ -1408,11 +1458,11 @@ void ConditionMgr::Clean()
itr->second.clear();
}
- m_VehicleSpellConditions.clear();
+ SmartEventConditionStore.clear();
// this is a BIG hack, feel free to fix it if you can figure out the ConditionMgr ;)
- for (std::list<Condition*>::const_iterator itr = m_AllocatedMemory.begin(); itr != m_AllocatedMemory.end(); ++itr)
+ for (std::list<Condition*>::const_iterator itr = AllocatedMemoryStore.begin(); itr != AllocatedMemoryStore.end(); ++itr)
delete *itr;
- m_AllocatedMemory.clear();
+ AllocatedMemoryStore.clear();
}
diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h
index 7e11a9420e7..a9bb97251da 100755
--- a/src/server/game/Conditions/ConditionMgr.h
+++ b/src/server/game/Conditions/ConditionMgr.h
@@ -96,7 +96,8 @@ enum ConditionSourceType
CONDITION_SOURCE_TYPE_QUEST_ACCEPT = 19, //DONE
CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK = 20, //DONE
CONDITION_SOURCE_TYPE_VEHICLE_SPELL = 21, //DONE
- CONDITION_SOURCE_TYPE_MAX = 22//MAX
+ CONDITION_SOURCE_TYPE_SMART_EVENT = 22, //DONE
+ CONDITION_SOURCE_TYPE_MAX = 23 //MAX
};
struct Condition
@@ -104,6 +105,7 @@ struct Condition
ConditionSourceType mSourceType; //SourceTypeOrReferenceId
uint32 mSourceGroup;
uint32 mSourceEntry;
+ uint32 mSourceId; // So far, only used in CONDITION_SOURCE_TYPE_SMART_EVENT
uint32 mElseGroup;
ConditionType mConditionType; //ConditionTypeOrReference
uint32 mConditionValue1;
@@ -133,11 +135,12 @@ struct Condition
};
typedef std::list<Condition*> ConditionList;
-typedef std::map<uint32, ConditionList> ConditionTypeMap;
-typedef std::map<ConditionSourceType, ConditionTypeMap> ConditionMap;
-typedef std::map<uint32, ConditionTypeMap> VehicleSpellConditionMap;
+typedef std::map<uint32, ConditionList> ConditionTypeContainer;
+typedef std::map<ConditionSourceType, ConditionTypeContainer> ConditionContainer;
+typedef std::map<uint32, ConditionTypeContainer> VehicleSpellConditionContainer;
+typedef std::map<std::pair<uint32, uint32 /*SAI source_type*/>, ConditionTypeContainer> SmartEventConditionContainer;
-typedef std::map<uint32, ConditionList> ConditionReferenceMap;//only used for references
+typedef std::map<uint32, ConditionList> ConditionReferenceContainer;//only used for references
class ConditionMgr
{
@@ -153,7 +156,8 @@ class ConditionMgr
ConditionList GetConditionReferences(uint32 refId);
bool IsPlayerMeetToConditions(Player* player, ConditionList const& conditions, Unit* invoker = NULL);
- ConditionList GetConditionsForNotGroupedEntry(ConditionSourceType sType, uint32 uEntry);
+ ConditionList GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry);
+ ConditionList GetConditionsForSmartEvent(uint32 entry, uint32 eventId, uint32 sourceType);
ConditionList GetConditionsForVehicleSpell(uint32 creatureID, uint32 spellID);
private:
@@ -179,15 +183,17 @@ class ConditionMgr
sourceType == CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE ||
sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU ||
sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION ||
- sourceType == CONDITION_SOURCE_TYPE_VEHICLE_SPELL);
+ sourceType == CONDITION_SOURCE_TYPE_VEHICLE_SPELL ||
+ sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT);
}
void Clean(); // free up resources
- std::list<Condition*> m_AllocatedMemory; // some garbage collection :)
+ std::list<Condition*> AllocatedMemoryStore; // some garbage collection :)
- ConditionMap m_ConditionMap;
- ConditionReferenceMap m_ConditionReferenceMap;
- VehicleSpellConditionMap m_VehicleSpellConditions;
+ ConditionContainer ConditionStore;
+ ConditionReferenceContainer ConditionReferenceStore;
+ VehicleSpellConditionContainer VehicleSpellConditionStore;
+ SmartEventConditionContainer SmartEventConditionStore;
};
#define sConditionMgr ACE_Singleton<ConditionMgr, ACE_Null_Mutex>::instance()
diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp
index e0a16d4868b..ac7343e8f23 100755
--- a/src/server/game/DungeonFinding/LFGMgr.cpp
+++ b/src/server/game/DungeonFinding/LFGMgr.cpp
@@ -72,6 +72,54 @@ LFGMgr::~LFGMgr()
delete it->second;
}
+void LFGMgr::_LoadFromDB(Field* fields, uint64 guid)
+{
+ if (!fields)
+ return;
+
+ if (!IS_GROUP(guid))
+ return;
+
+ uint32 dungeon = fields[16].GetUInt32();
+
+ uint8 state = fields[17].GetUInt8();
+
+ if (!dungeon || !state)
+ return;
+
+ SetDungeon(guid, dungeon);
+
+ switch (state)
+ {
+ case LFG_STATE_DUNGEON:
+ case LFG_STATE_FINISHED_DUNGEON:
+ SetState(guid, (LfgState)state);
+ break;
+ default:
+ break;
+ }
+}
+
+void LFGMgr::_SaveToDB(uint64 guid, uint32 db_guid)
+{
+ if (!IS_GROUP(guid))
+ return;
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_LFG_DATA);
+
+ stmt->setUInt32(0, db_guid);
+
+ CharacterDatabase.Execute(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_LFG_DATA);
+ stmt->setUInt32(0, db_guid);
+
+ stmt->setUInt32(1, GetDungeon(guid));
+ stmt->setUInt32(2, GetState(guid));
+
+ CharacterDatabase.Execute(stmt);
+}
+
/// Load rewards for completing dungeons
void LFGMgr::LoadRewards()
{
@@ -245,7 +293,8 @@ void LFGMgr::Update(uint32 diff)
UpdateProposal(m_lfgProposalId, guid, true);
}
else
- currentQueue.push_back(frontguid); // Lfg group not found, add this group to the queue.
+ if (std::find(currentQueue.begin(), currentQueue.end(), frontguid) == currentQueue.end()) //already in queue?
+ currentQueue.push_back(frontguid); // Lfg group not found, add this group to the queue.
firstNew.clear();
}
}
@@ -382,7 +431,10 @@ void LFGMgr::InitializeLockedDungeons(Player* player)
else if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player))
locktype = LFG_LOCKSTATUS_RAID_LOCKED;
else if (dungeon->difficulty > DUNGEON_DIFFICULTY_NORMAL && player->GetBoundInstance(dungeon->map, Difficulty(dungeon->difficulty)))
- locktype = LFG_LOCKSTATUS_RAID_LOCKED;
+ {
+ if (!player->GetGroup() || !player->GetGroup()->isLFGGroup() || GetDungeon(player->GetGroup()->GetGUID(), true) != dungeon->ID || GetState(player->GetGroup()->GetGUID()) != LFG_STATE_DUNGEON)
+ locktype = LFG_LOCKSTATUS_RAID_LOCKED;
+ }
else if (dungeon->minlevel > level)
locktype = LFG_LOCKSTATUS_TOO_LOW_LEVEL;
else if (dungeon->maxlevel < level)
@@ -431,7 +483,7 @@ void LFGMgr::InitializeLockedDungeons(Player* player)
void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDungeons, const std::string& comment)
{
if (!player || !player->GetSession() || selectedDungeons.empty())
- return;
+ return;
Group* grp = player->GetGroup();
uint64 guid = player->GetGUID();
@@ -808,7 +860,7 @@ bool LFGMgr::CheckCompatibility(LfgGuidList check, LfgProposal*& pProposal)
{
uint64 guid = (*it);
LfgQueueInfoMap::iterator itQueue = m_QueueInfoMap.find(guid);
- if (itQueue == m_QueueInfoMap.end())
+ if (itQueue == m_QueueInfoMap.end() || GetState(guid) != LFG_STATE_QUEUED)
{
sLog->outError("LFGMgr::CheckCompatibility: [" UI64FMTD "] is not queued but listed as queued!", (*it));
RemoveFromQueue(guid);
@@ -923,6 +975,42 @@ bool LFGMgr::CheckCompatibility(LfgGuidList check, LfgProposal*& pProposal)
if (numPlayers != MAXGROUPSIZE)
{
sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) Compatibles but not match. Players(%u)", strGuids.c_str(), numPlayers);
+ uint8 Tanks_Needed = LFG_TANKS_NEEDED;
+ uint8 Healers_Needed = LFG_HEALERS_NEEDED;
+ uint8 Dps_Needed = LFG_DPS_NEEDED;
+ for (LfgQueueInfoMap::const_iterator itQueue = pqInfoMap.begin(); itQueue != pqInfoMap.end(); ++itQueue)
+ {
+ LfgQueueInfo* queue = itQueue->second;
+ for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer)
+ {
+ uint8 roles = itPlayer->second;
+ if ((roles & ROLE_TANK) && Tanks_Needed > 0)
+ --Tanks_Needed;
+ else if ((roles & ROLE_HEALER) && Healers_Needed > 0)
+ --Healers_Needed;
+ else if ((roles & ROLE_DAMAGE) && Dps_Needed > 0)
+ --Dps_Needed;
+ }
+ }
+ for (PlayerSet::const_iterator itPlayers = players.begin(); itPlayers != players.end(); ++itPlayers)
+ {
+ for (LfgQueueInfoMap::const_iterator itQueue = pqInfoMap.begin(); itQueue != pqInfoMap.end(); ++itQueue)
+ {
+ LfgQueueInfo* queue = itQueue->second;
+ if (!queue)
+ continue;
+
+ for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer)
+ {
+ if (*itPlayers == ObjectAccessor::FindPlayer(itPlayer->first))
+ {
+ queue->tanks = Tanks_Needed;
+ queue->healers = Healers_Needed;
+ queue->dps = Dps_Needed;
+ }
+ }
+ }
+ }
return true;
}
sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) MATCH! Group formed", strGuids.c_str());
@@ -1078,6 +1166,11 @@ void LFGMgr::UpdateRoleCheck(uint64 gguid, uint64 guid /* = 0 */, uint8 roles /*
}
m_QueueInfoMap[gguid] = pqInfo;
+ if(GetState(gguid) != LFG_STATE_NONE)
+ {
+ LfgGuidList& currentQueue = m_currentQueue[team];
+ currentQueue.push_front(gguid);
+ }
AddToQueue(gguid, team);
}
@@ -1384,6 +1477,7 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept)
break;
}
}
+ m_teleport.push_back(pguid);
grp->SetLfgRoles(pguid, pProposal->players[pguid]->role);
SetState(pguid, LFG_STATE_DUNGEON);
}
@@ -1395,6 +1489,7 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept)
uint64 gguid = grp->GetGUID();
SetDungeon(gguid, dungeon->Entry());
SetState(gguid, LFG_STATE_DUNGEON);
+ _SaveToDB(gguid, grp->GetDbStoreId());
// Remove players/groups from Queue
for (LfgGuidList::const_iterator it = pProposal->queues.begin(); it != pProposal->queues.end(); ++it)
@@ -1509,7 +1604,9 @@ void LFGMgr::RemoveProposal(LfgProposalMap::iterator itProposal, LfgUpdateType t
for (LfgGuidList::const_iterator it = pProposal->queues.begin(); it != pProposal->queues.end(); ++it)
{
uint64 guid = *it;
- AddToQueue(guid, team);
+ LfgGuidList& currentQueue = m_currentQueue[team];
+ currentQueue.push_front(guid); //Add GUID for high priority
+ AddToQueue(guid, team); //We have to add each GUID in newQueue to check for a new groups
}
delete pProposal;
@@ -1921,6 +2018,16 @@ const std::string& LFGMgr::GetComment(uint64 guid)
return m_Players[guid].GetComment();
}
+bool LFGMgr::IsTeleported(uint64 pguid)
+{
+ if (std::find(m_teleport.begin(), m_teleport.end(), pguid) != m_teleport.end())
+ {
+ m_teleport.remove(pguid);
+ return true;
+ }
+ return false;
+}
+
const LfgDungeonSet& LFGMgr::GetSelectedDungeons(uint64 guid)
{
sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetSelectedDungeons: [" UI64FMTD "]", guid);
diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h
index 3e324f4b5f4..d10902b9553 100755
--- a/src/server/game/DungeonFinding/LFGMgr.h
+++ b/src/server/game/DungeonFinding/LFGMgr.h
@@ -287,6 +287,9 @@ class LFGMgr
void InitializeLockedDungeons(Player* player);
+ void _LoadFromDB(Field* fields, uint64 guid);
+ void _SaveToDB(uint64 guid, uint32 db_guid);
+
void SetComment(uint64 guid, const std::string& comment);
const LfgLockMap& GetLockedDungeons(uint64 guid);
LfgState GetState(uint64 guid);
@@ -298,7 +301,9 @@ class LFGMgr
void RemoveGroupData(uint64 guid);
uint8 GetKicksLeft(uint64 gguid);
uint8 GetVotesNeeded(uint64 gguid);
+ bool IsTeleported(uint64 pguid);
void SetRoles(uint64 guid, uint8 roles);
+ void SetSelectedDungeons(uint64 guid, const LfgDungeonSet& dungeons);
private:
@@ -306,10 +311,8 @@ class LFGMgr
const std::string& GetComment(uint64 gguid);
void RestoreState(uint64 guid);
void SetDungeon(uint64 guid, uint32 dungeon);
- void SetSelectedDungeons(uint64 guid, const LfgDungeonSet& dungeons);
void SetLockedDungeons(uint64 guid, const LfgLockMap& lock);
void DecreaseKicksLeft(uint64 guid);
- void NoExiste(uint8 lala);
// Queue
void AddToQueue(uint64 guid, uint8 queueId);
@@ -352,6 +355,7 @@ class LFGMgr
LfgGuidListMap m_currentQueue; ///< Ordered list. Used to find groups
LfgGuidListMap m_newToQueue; ///< New groups to add to queue
LfgCompatibleMap m_CompatibleMap; ///< Compatible dungeons
+ LfgGuidList m_teleport; ///< Players being teleported
// Rolecheck - Proposal - Vote Kicks
LfgRoleCheckMap m_RoleChecks; ///< Current Role checks
LfgProposalMap m_Proposals; ///< Current Proposals
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 2c6ba86ea8f..25682999f62 100755
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -48,6 +48,8 @@
#include "Vehicle.h"
#include "SpellAuraEffects.h"
#include "Group.h"
+#include "MoveSplineInit.h"
+#include "MoveSpline.h"
// apply implementation of the singletons
TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const
@@ -143,7 +145,7 @@ m_PlayerDamageReq(0), m_lootMoney(0), m_lootRecipient(0), m_lootRecipientGroup(0
m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE),
m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
-m_creatureInfo(NULL), m_creatureData(NULL), m_formation(NULL)
+m_creatureInfo(NULL), m_creatureData(NULL), m_formation(NULL), m_path_id(0)
{
m_regenTimer = CREATURE_REGEN_INTERVAL;
m_valuesCount = UNIT_END;
@@ -332,6 +334,7 @@ bool Creature::InitEntry(uint32 Entry, uint32 /*team*/, const CreatureData* data
SetSpeed(MOVE_FLIGHT, 1.0f); // using 1.0 rate
SetFloatValue(OBJECT_FIELD_SCALE_X, cinfo->scale);
+ SetLevitate(canFly());
// checked at loading
m_defaultMovementType = MovementGeneratorType(cinfo->MovementType);
@@ -435,6 +438,17 @@ void Creature::Update(uint32 diff)
m_vehicleKit->Reset();
}
+ if (IsInWater())
+ {
+ if (canSwim())
+ AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
+ }
+ else
+ {
+ if (canWalk())
+ RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
+ }
+
switch (m_deathState)
{
case JUST_ALIVED:
@@ -472,9 +486,7 @@ void Creature::Update(uint32 diff)
}
case CORPSE:
{
- m_Events.Update(diff);
- _UpdateSpells(diff);
-
+ Unit::Update(diff);
// deathstate changed on spells update, prevent problems
if (m_deathState != CORPSE)
break;
@@ -565,9 +577,6 @@ void Creature::Update(uint32 diff)
m_regenTimer = CREATURE_REGEN_INTERVAL;
break;
}
- case DEAD_FALLING:
- GetMotionMaster()->UpdateMotion(diff);
- break;
default:
break;
}
@@ -715,7 +724,7 @@ void Creature::Motion_Initialize()
i_motionMaster.Initialize();
}
else if (m_formation->isFormed())
- i_motionMaster.MoveIdle(MOTION_SLOT_IDLE); //wait the order of leader
+ i_motionMaster.MoveIdle(); //wait the order of leader
else
i_motionMaster.Initialize();
}
@@ -945,7 +954,8 @@ void Creature::AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint3
m_startMove = getMSTime();
m_moveTime = time;*/
- SendMonsterMove(x, y, z, time);
+ float speed = GetDistance(x, y, z) / ((float)time * 0.001f);
+ MonsterMoveWithSpeed(x, y, z, speed);
}
Player* Creature::GetLootRecipient() const
@@ -1507,8 +1517,8 @@ void Creature::setDeathState(DeathState s)
if (m_formation && m_formation->getLeader() == this)
m_formation->FormationReset(true);
- if ((canFly() || IsFlying()) && FallGround())
- return;
+ if ((canFly() || IsFlying()))
+ i_motionMaster.MoveFall();
Unit::setDeathState(CORPSE);
}
@@ -1520,7 +1530,7 @@ void Creature::setDeathState(DeathState s)
SetLootRecipient(NULL);
ResetPlayerDamageReq();
CreatureTemplate const* cinfo = GetCreatureInfo();
- AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
+ SetWalk(true);
if (GetCreatureInfo()->InhabitType & INHABIT_AIR)
AddUnitMovementFlag(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_FLYING);
if (GetCreatureInfo()->InhabitType & INHABIT_WATER)
@@ -1536,24 +1546,6 @@ void Creature::setDeathState(DeathState s)
}
}
-bool Creature::FallGround()
-{
- // Let's abort after we called this function one time
- if (getDeathState() == DEAD_FALLING)
- return false;
-
- float x, y, z;
- GetPosition(x, y, z);
- // use larger distance for vmap height search than in most other cases
- float ground_Z = GetMap()->GetHeight(x, y, z, true, MAX_FALL_DISTANCE);
- if (fabs(ground_Z - z) < 0.1f)
- return false;
-
- GetMotionMaster()->MoveFall(ground_Z, EVENT_FALL_GROUND);
- Unit::setDeathState(DEAD_FALLING);
- return true;
-}
-
void Creature::Respawn(bool force)
{
DestroyForNearbyPlayers();
@@ -2417,3 +2409,25 @@ bool Creature::IsDungeonBoss() const
CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(GetEntry());
return cinfo && (cinfo->flags_extra & CREATURE_FLAG_EXTRA_DUNGEON_BOSS);
}
+
+void Creature::SetWalk(bool enable)
+{
+ if (enable)
+ AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
+ else
+ RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
+ WorldPacket data(enable ? SMSG_MOVE_SPLINE_SET_WALK_MODE : SMSG_MOVE_SPLINE_SET_RUN_MODE, 9);
+ data.append(GetPackGUID());
+ SendMessageToSet(&data, true);
+}
+
+void Creature::SetLevitate(bool enable)
+{
+ if (enable)
+ AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
+ else
+ RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
+ WorldPacket data(enable ? SMSG_MOVE_SPLINE_DISABLE_GRAVITY : SMSG_MOVE_SPLINE_ENABLE_GRAVITY, 9);
+ data.append(GetPackGUID());
+ SendMessageToSet(&data, true);
+}
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 017085fec04..908f2b7e312 100755
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -522,6 +522,9 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature
void AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type);
CreatureAI* AI() const { return (CreatureAI*)i_AI; }
+ void SetWalk(bool enable);
+ void SetLevitate(bool enable);
+
uint32 GetShieldBlockValue() const //dunno mob block value
{
return (getLevel()/2 + uint32(GetStat(STAT_STRENGTH)/20));
@@ -575,7 +578,6 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature
const char* GetNameForLocaleIdx(LocaleConstant locale_idx) const;
void setDeathState(DeathState s); // override virtual Unit::setDeathState
- bool FallGround();
bool LoadFromDB(uint32 guid, Map* map) { return LoadCreatureFromDB(guid, map, false); }
bool LoadCreatureFromDB(uint32 guid, Map* map, bool addToMap = true);
diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp
index 3a63c32fc1e..f440fd497fc 100755
--- a/src/server/game/Entities/Creature/CreatureGroups.cpp
+++ b/src/server/game/Entities/Creature/CreatureGroups.cpp
@@ -203,7 +203,7 @@ void CreatureGroup::FormationReset(bool dismiss)
if (dismiss)
itr->first->GetMotionMaster()->Initialize();
else
- itr->first->GetMotionMaster()->MoveIdle(MOTION_SLOT_IDLE);
+ itr->first->GetMotionMaster()->MoveIdle();
sLog->outDebug(LOG_FILTER_UNITS, "Set %s movement for member GUID: %u", dismiss ? "default" : "idle", itr->first->GetGUIDLow());
}
}
@@ -212,10 +212,12 @@ void CreatureGroup::FormationReset(bool dismiss)
void CreatureGroup::LeaderMoveTo(float x, float y, float z)
{
+ //! 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 pathangle = atan2(m_leader->GetPositionY() - y, m_leader->GetPositionX() - x);
+ float pathangle = atan2(m_leader->GetPositionY() - y, m_leader->GetPositionX() - x);
for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
{
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 10220c7bc89..64cc1bb325c 100755
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -974,7 +974,7 @@ void GameObject::ResetDoorOrButton()
m_cooldownTime = 0;
}
-void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = false */)
+void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = false */, Unit* user /*=NULL*/)
{
if (m_lootState != GO_READY)
return;
@@ -983,7 +983,7 @@ void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = f
time_to_restore = GetGOInfo()->GetAutoCloseTime();
SwitchDoorOrButton(true, alternative);
- SetLootState(GO_ACTIVATED);
+ SetLootState(GO_ACTIVATED, user);
m_cooldownTime = time(NULL) + time_to_restore;
}
@@ -1053,7 +1053,7 @@ void GameObject::Use(Unit* user)
case GAMEOBJECT_TYPE_DOOR: //0
case GAMEOBJECT_TYPE_BUTTON: //1
//doors/buttons never really despawn, only reset to default state/flags
- UseDoorOrButton();
+ UseDoorOrButton(0, false, user);
// activate script
GetMap()->ScriptsStart(sGameObjectScripts, GetDBTableGUIDLow(), spellCaster, this);
@@ -1206,7 +1206,7 @@ void GameObject::Use(Unit* user)
TriggeringLinkedGameObject(trapEntry, user);
SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
- SetLootState(GO_ACTIVATED);
+ SetLootState(GO_ACTIVATED, user);
// this appear to be ok, however others exist in addition to this that should have custom (ex: 190510, 188692, 187389)
if (info->goober.customAnim)
@@ -1864,3 +1864,9 @@ void GameObject::SetDestructibleState(GameObjectDestructibleState state, Player*
}
}
}
+
+void GameObject::SetLootState(LootState s, Unit* unit)
+{
+ m_lootState = s;
+ AI()->OnStateChanged(s, unit);
+}
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index 4daf73370f1..2329ed10e49 100755
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -714,7 +714,8 @@ class GameObject : public WorldObject, public GridObject<GameObject>
void Use(Unit* user);
LootState getLootState() const { return m_lootState; }
- void SetLootState(LootState s) { m_lootState = s; }
+ // Note: unit is only used when s = GO_ACTIVATED
+ void SetLootState(LootState s, Unit* unit = NULL);
uint16 GetLootMode() { return m_LootMode; }
bool HasLootMode(uint16 lootMode) { return m_LootMode & lootMode; }
@@ -748,7 +749,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>
bool hasQuest(uint32 quest_id) const;
bool hasInvolvedQuest(uint32 quest_id) const;
bool ActivateToQuest(Player* target) const;
- void UseDoorOrButton(uint32 time_to_restore = 0, bool alternative = false);
+ void UseDoorOrButton(uint32 time_to_restore = 0, bool alternative = false, Unit* user = NULL);
// 0 = use `gameobject`.`spawntimesecs`
void ResetDoorOrButton();
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index d4e48548aa0..d89849f7ccf 100755
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -45,6 +45,7 @@
#include "TemporarySummon.h"
#include "Totem.h"
#include "OutdoorPvPMgr.h"
+#include "MovementPacketBuilder.h"
uint32 GuidHigh2TypeId(uint32 guid_hi)
{
@@ -309,65 +310,9 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint16 flags) const
*data << self->GetSpeed(MOVE_TURN_RATE);
*data << self->GetSpeed(MOVE_PITCH_RATE);
- Player const* player = ToPlayer();
-
// 0x08000000
- if (player && player->isInFlight())
- {
- uint32 flags3 = SPLINEFLAG_GLIDE;
-
- *data << uint32(flags3); // splines flag
-
- if (flags3 & 0x00004000) // FinalOrientation
- {
- *data << (float)0;
- }
- else if (flags3 & 0x00001000) // FinalOrientation
- {
- *data << (float)0;
- *data << (float)0;
- *data << (float)0;
- }
- else if (flags3 & 0x00002000) // FinalTarget
- {
- *data << uint64(0);
- }
-
- FlightPathMovementGenerator *fmg = (FlightPathMovementGenerator*)(player->GetMotionMaster()->top());
- TaxiPathNodeList const& path = fmg->GetPath();
-
- float x, y, z;
- player->GetPosition(x, y, z);
-
- uint32 inflighttime = uint32(path.GetPassedLength(fmg->GetCurrentNode(), x, y, z) * 32);
- uint32 traveltime = uint32(path.GetTotalLength() * 32);
-
- *data << uint32(inflighttime); // passed move time?
- *data << uint32(traveltime); // full move time?
- *data << uint32(0); // ticks count?
-
- *data << float(0); // added in 3.1
- *data << float(0); // added in 3.1
- *data << float(0); // added in 3.1
-
- *data << uint32(0); // added in 3.1
-
- uint32 poscount = uint32(path.size());
- *data << uint32(poscount); // points count
-
- for (uint32 i = 0; i < poscount; ++i)
- {
- *data << float(path[i].x);
- *data << float(path[i].y);
- *data << float(path[i].z);
- }
-
- *data << uint8(0); // added in 3.0.8
-
- *data << float(path[poscount-1].x);
- *data << float(path[poscount-1].y);
- *data << float(path[poscount-1].z);
- }
+ if (self->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_SPLINE_ENABLED))
+ Movement::PacketBuilder::WriteCreate(*self->movespline, *data);
}
else
{
@@ -1549,6 +1494,70 @@ void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const
z = new_z+ 0.05f; // just to be sure that we are not a few pixel under the surface
}
+void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const
+{
+ switch (GetTypeId())
+ {
+ case TYPEID_UNIT:
+ {
+ // non fly unit don't must be in air
+ // non swim unit must be at ground (mostly speedup, because it don't must be in water and water level check less fast
+ if (!((Creature const*)this)->canFly())
+ {
+ bool canSwim = ((Creature const*)this)->canSwim();
+ float ground_z = z;
+ float max_z = canSwim
+ ? GetBaseMap()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK))
+ : ((ground_z = GetBaseMap()->GetHeight(x, y, z, true)));
+ if (max_z > INVALID_HEIGHT)
+ {
+ if (z > max_z)
+ z = max_z;
+ else if (z < ground_z)
+ z = ground_z;
+ }
+ }
+ else
+ {
+ float ground_z = GetBaseMap()->GetHeight(x, y, z, true);
+ if (z < ground_z)
+ z = ground_z;
+ }
+ break;
+ }
+ case TYPEID_PLAYER:
+ {
+ // for server controlled moves playr work same as creature (but it can always swim)
+ if (!((Player const*)this)->canFly())
+ {
+ float ground_z = z;
+ float max_z = GetBaseMap()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK));
+ if (max_z > INVALID_HEIGHT)
+ {
+ if (z > max_z)
+ z = max_z;
+ else if (z < ground_z)
+ z = ground_z;
+ }
+ }
+ else
+ {
+ float ground_z = GetBaseMap()->GetHeight(x, y, z, true);
+ if (z < ground_z)
+ z = ground_z;
+ }
+ break;
+ }
+ default:
+ {
+ float ground_z = GetBaseMap()->GetHeight(x, y, z, true);
+ if(ground_z > INVALID_HEIGHT)
+ z = ground_z;
+ break;
+ }
+ }
+}
+
bool Position::IsPositionValid() const
{
return Trinity::IsValidMapCoord(m_positionX, m_positionY, m_positionZ, m_orientation);
@@ -1987,7 +1996,8 @@ void Unit::BuildHeartBeatMsg(WorldPacket* data) const
void WorldObject::SendMessageToSet(WorldPacket* data, bool self)
{
- SendMessageToSetInRange(data, GetVisibilityRange(), self);
+ if (IsInWorld())
+ SendMessageToSetInRange(data, GetVisibilityRange(), self);
}
void WorldObject::SendMessageToSetInRange(WorldPacket* data, float dist, bool /*self*/)
@@ -2475,7 +2485,7 @@ void WorldObject::GetNearPoint(WorldObject const* /*searcher*/, float &x, float
{
GetNearPoint2D(x, y, distance2d+searcher_size, absAngle);
z = GetPositionZ();
- UpdateGroundPositionZ(x, y, z);
+ UpdateAllowedPositionZ(x, y, z);
/*
// if detection disabled, return first point
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index b421142bef1..666f71ffe68 100755
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -497,7 +497,9 @@ struct MovementInfo
}
uint32 GetMovementFlags() { return flags; }
+ void SetMovementFlags(uint32 flag) { flags = flag; }
void AddMovementFlag(uint32 flag) { flags |= flag; }
+ void RemoveMovementFlag(uint32 flag) { flags &= ~flag; }
bool HasMovementFlag(uint32 flag) const { return flags & flag; }
uint16 GetExtraMovementFlags() { return flags2; }
@@ -615,6 +617,7 @@ class WorldObject : public Object, public WorldLocation
return (m_valuesCount > UNIT_FIELD_COMBATREACH) ? m_floatValues[UNIT_FIELD_COMBATREACH] : DEFAULT_WORLD_OBJECT_SIZE;
}
void UpdateGroundPositionZ(float x, float y, float &z) const;
+ void UpdateAllowedPositionZ(float x, float y, float &z) const;
void GetRandomPoint(const Position &srcPos, float distance, float &rand_x, float &rand_y, float &rand_z) const;
void GetRandomPoint(const Position &srcPos, float distance, Position &pos) const
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index a211d848f59..8cf1413611b 100755
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -297,15 +297,24 @@ Item* TradeData::GetItem(TradeSlots slot) const
return m_items[slot] ? m_player->GetItemByGuid(m_items[slot]) : NULL;
}
-bool TradeData::HasItem(uint64 item_guid) const
+bool TradeData::HasItem(uint64 itemGuid) const
{
for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
- if (m_items[i] == item_guid)
+ if (m_items[i] == itemGuid)
return true;
return false;
}
+TradeSlots TradeData::GetTradeSlotForItem(uint64 itemGuid) const
+{
+ for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
+ if (m_items[i] == itemGuid)
+ return TradeSlots(i);
+
+ return TRADE_SLOT_INVALID;
+}
+
Item* TradeData::GetSpellCastItem() const
{
return m_spellCastItem ? m_player->GetItemByGuid(m_spellCastItem) : NULL;
@@ -2179,6 +2188,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
// reset movement flags at teleport, because player will continue move with these flags after teleport
SetUnitMovementFlags(0);
+ DisableSpline();
if (m_transport)
{
@@ -2387,9 +2397,14 @@ bool Player::TeleportToBGEntryPoint()
if (m_bgData.joinPos.m_mapId == MAPID_INVALID)
return false;
+ Group* group = GetGroup();
+ if (group && group->isLFGGroup() && group->GetMembersCount() == 1)
+ group->Disband();
+ else
+ ScheduleDelayedOperation(DELAYED_BG_GROUP_RESTORE);
+
ScheduleDelayedOperation(DELAYED_BG_MOUNT_RESTORE);
ScheduleDelayedOperation(DELAYED_BG_TAXI_RESTORE);
- ScheduleDelayedOperation(DELAYED_BG_GROUP_RESTORE);
return TeleportTo(m_bgData.joinPos);
}
@@ -5240,43 +5255,10 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
}
}
-/**
- * FallMode = 0 implies that the player is dying, or already dead, and the proper death state will be set.
- * = 1 simply causes the player to plummet towards the ground, and not suffer any damage.
- * = 2 causes the player to plummet towards the ground, and causes falling damage, regardless
- * of any auras that might of prevented fall damage.
- */
-bool Player::FallGround(uint8 FallMode)
-{
- // Let's abort after we called this function one time
- if (getDeathState() == DEAD_FALLING && FallMode == 0)
- return false;
-
- float x, y, z;
- GetPosition(x, y, z);
- float ground_Z = GetMap()->GetHeight(x, y, z);
- float z_diff = 0.0f;
- if ((z_diff = fabs(ground_Z - z)) < 0.1f)
- return false;
-
- GetMotionMaster()->MoveFall(ground_Z, EVENT_FALL_GROUND);
-
- // Below formula for falling damage is from Player::HandleFall
- if (FallMode == 2 && z_diff >= 14.57f)
- {
- uint32 damage = std::min(GetMaxHealth(), (uint32)((0.018f * z_diff - 0.2426f) * GetMaxHealth() * sWorld->getRate(RATE_DAMAGE_FALL)));
- if (damage)
- EnvironmentalDamage(DAMAGE_FALL, damage);
- }
- else if (FallMode == 0)
- Unit::setDeathState(DEAD_FALLING);
- return true;
-}
-
void Player::KillPlayer()
{
if (IsFlying() && !GetTransport())
- FallGround();
+ i_motionMaster.MoveFall();
SetMovement(MOVE_ROOT);
@@ -7614,6 +7596,22 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
SendInitWorldStates(newZone, newArea); // only if really enters to new zone, not just area change, works strange...
}
+ // group update
+ if (GetGroup())
+ {
+ SetGroupUpdateFlag(GROUP_UPDATE_FULL);
+ Group* grp = GetGroup();
+ if (GetSession() && grp->isLFGGroup() && sLFGMgr->IsTeleported(GetGUID()))
+ {
+ for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player* tempplr = itr->getSource();
+ if (tempplr)
+ GetSession()->SendNameQueryOpcode(tempplr->GetGUID());
+ }
+ }
+ }
+
m_zoneUpdateId = newZone;
m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL;
@@ -7701,10 +7699,6 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
// recent client version not send leave/join channel packets for built-in local channels
UpdateLocalChannels(newZone);
- // group update
- if (GetGroup())
- SetGroupUpdateFlag(GROUP_UPDATE_FULL);
-
UpdateZoneDependentAuras(newZone);
}
@@ -8856,7 +8850,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
}
}
- go->SetLootState(GO_ACTIVATED);
+ go->SetLootState(GO_ACTIVATED, this);
}
if (go->getLootState() == GO_ACTIVATED)
@@ -11955,6 +11949,93 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const
return EQUIP_ERR_ITEM_NOT_FOUND;
}
+InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObject const* lootedObject) const
+{
+ LfgDungeonSet const& dungeons = sLFGMgr->GetSelectedDungeons(GetGUID());
+ if (dungeons.empty())
+ return EQUIP_ERR_OK; // not using LFG
+
+ if (!GetGroup() || !GetGroup()->isLFGGroup())
+ return EQUIP_ERR_OK; // not in LFG group
+
+ // check if looted object is inside the lfg dungeon
+ bool lootedObjectInDungeon = false;
+ Map const* map = lootedObject->GetMap();
+ if (uint32 dungeonId = sLFGMgr->GetDungeon(GetGroup()->GetGUID(), true))
+ if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId))
+ if (dungeon->map == map->GetId() && dungeon->difficulty == map->GetDifficulty())
+ lootedObjectInDungeon = true;
+
+ if (!lootedObjectInDungeon)
+ return EQUIP_ERR_OK;
+
+ if (!proto)
+ return EQUIP_ERR_ITEM_NOT_FOUND;
+ // Used by group, function NeedBeforeGreed, to know if a prototype can be used by a player
+
+ const static uint32 item_weapon_skills[MAX_ITEM_SUBCLASS_WEAPON] =
+ {
+ SKILL_AXES, SKILL_2H_AXES, SKILL_BOWS, SKILL_GUNS, SKILL_MACES,
+ SKILL_2H_MACES, SKILL_POLEARMS, SKILL_SWORDS, SKILL_2H_SWORDS, 0,
+ SKILL_STAVES, 0, 0, SKILL_FIST_WEAPONS, 0,
+ SKILL_DAGGERS, SKILL_THROWN, SKILL_ASSASSINATION, SKILL_CROSSBOWS, SKILL_WANDS,
+ SKILL_FISHING
+ }; //Copy from function Item::GetSkill()
+
+ if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0)
+ return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
+
+ if (proto->RequiredSpell != 0 && !HasSpell(proto->RequiredSpell))
+ return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
+
+ if (proto->RequiredSkill != 0)
+ {
+ if (!GetSkillValue(proto->RequiredSkill))
+ return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
+ else if (GetSkillValue(proto->RequiredSkill) < proto->RequiredSkillRank)
+ return EQUIP_ERR_CANT_EQUIP_SKILL;
+ }
+
+ uint8 _class = getClass();
+
+ if (proto->Class == ITEM_CLASS_WEAPON && GetSkillValue(item_weapon_skills[proto->SubClass]) == 0)
+ return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
+
+ if (proto->Class == ITEM_CLASS_ARMOR && proto->SubClass > ITEM_SUBCLASS_ARMOR_MISCELLANEOUS && proto->SubClass < ITEM_SUBCLASS_ARMOR_BUCKLER && proto->InventoryType != INVTYPE_CLOAK)
+ {
+ if (_class == CLASS_WARRIOR || _class == CLASS_PALADIN || _class == CLASS_DEATH_KNIGHT)
+ {
+ if (getLevel() < 40)
+ {
+ if (proto->SubClass != ITEM_SUBCLASS_ARMOR_MAIL)
+ return EQUIP_ERR_CANT_DO_RIGHT_NOW;
+ }
+ else if (proto->SubClass != ITEM_SUBCLASS_ARMOR_PLATE)
+ return EQUIP_ERR_CANT_DO_RIGHT_NOW;
+ }
+ else if (_class == CLASS_HUNTER || _class == CLASS_SHAMAN)
+ {
+ if (getLevel() < 40)
+ {
+ if (proto->SubClass != ITEM_SUBCLASS_ARMOR_LEATHER)
+ return EQUIP_ERR_CANT_DO_RIGHT_NOW;
+ }
+ else if (proto->SubClass != ITEM_SUBCLASS_ARMOR_MAIL)
+ return EQUIP_ERR_CANT_DO_RIGHT_NOW;
+ }
+
+ if (_class == CLASS_ROGUE || _class == CLASS_DRUID)
+ if (proto->SubClass != ITEM_SUBCLASS_ARMOR_LEATHER)
+ return EQUIP_ERR_CANT_DO_RIGHT_NOW;
+
+ if (_class == CLASS_MAGE || _class == CLASS_PRIEST || _class == CLASS_WARLOCK)
+ if (proto->SubClass != ITEM_SUBCLASS_ARMOR_CLOTH)
+ return EQUIP_ERR_CANT_DO_RIGHT_NOW;
+ }
+
+ return EQUIP_ERR_OK;
+}
+
Item* Player::StoreNewItem(ItemPosCountVec const& dest, uint32 item, bool update, int32 randomPropertyId)
{
AllowedLooterSet allowedLooters;
@@ -12797,6 +12878,14 @@ void Player::SplitItem(uint16 src, uint16 dst, uint32 count)
return;
}
+ //! If trading
+ if (TradeData* tradeData = GetTradeData())
+ {
+ //! If current item is in trade window (only possible with packet spoofing - silent return)
+ if (tradeData->GetTradeSlotForItem(pSrcItem->GetGUID()) != TRADE_SLOT_INVALID)
+ return;
+ }
+
sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: SplitItem bag = %u, slot = %u, item = %u, count = %u", dstbag, dstslot, pSrcItem->GetEntry(), count);
Item* pNewItem = pSrcItem->CloneItem(count, this);
if (!pNewItem)
@@ -12825,7 +12914,7 @@ void Player::SplitItem(uint16 src, uint16 dst, uint32 count)
pSrcItem->SetState(ITEM_CHANGED, this);
StoreItem(dest, pNewItem, true);
}
- else if (IsBankPos (dst))
+ else if (IsBankPos(dst))
{
// change item amount before check (for unique max count check)
pSrcItem->SetCount(pSrcItem->GetCount() - count);
@@ -12845,7 +12934,7 @@ void Player::SplitItem(uint16 src, uint16 dst, uint32 count)
pSrcItem->SetState(ITEM_CHANGED, this);
BankItem(dest, pNewItem, true);
}
- else if (IsEquipmentPos (dst))
+ else if (IsEquipmentPos(dst))
{
// change item amount before check (for unique max count check), provide space for splitted items
pSrcItem->SetCount(pSrcItem->GetCount() - count);
@@ -14055,6 +14144,10 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool
PrepareQuestMenu(source->GetGUID());
}
+ if (source->GetTypeId() == TYPEID_GAMEOBJECT)
+ if (source->ToGameObject()->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER)
+ PrepareQuestMenu(source->GetGUID());
+
for (GossipMenuItemsMap::const_iterator itr = menuItemBounds.first; itr != menuItemBounds.second; ++itr)
{
bool canTalk = true;
@@ -14140,11 +14233,6 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool
switch (itr->second.OptionType)
{
- case GOSSIP_OPTION_QUESTGIVER:
- if (go->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER)
- PrepareQuestMenu(source->GetGUID());
- canTalk = false;
- break;
case GOSSIP_OPTION_GOSSIP:
if (go->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER && go->GetGoType() != GAMEOBJECT_TYPE_GOOBER)
canTalk = false;
@@ -16751,6 +16839,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
_LoadInstanceTimeRestrictions(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADINSTANCELOCKTIMES));
_LoadBGData(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADBGDATA));
+ GetSession()->SetPlayer(this);
MapEntry const* mapEntry = sMapStore.LookupEntry(mapId);
if (!mapEntry || !IsPositionValid())
{
@@ -21577,8 +21666,6 @@ void Player::SendInitialVisiblePackets(Unit* target)
SendAurasForTarget(target);
if (target->isAlive())
{
- if (target->GetMotionMaster()->GetCurrentMovementGeneratorType() != IDLE_MOTION_TYPE)
- target->SendMonsterMoveWithSpeedToCurrentDestination(this);
if (target->HasUnitState(UNIT_STAT_MELEE_ATTACKING) && target->getVictim())
target->SendMeleeAttackStart(target->getVictim());
}
@@ -21836,7 +21923,9 @@ void Player::SendInitialPacketsBeforeAddToMap()
// SMSG_PET_GUIDS
// SMSG_UPDATE_WORLD_STATE
// SMSG_POWER_UPDATE
+
SendCurrencies();
+ SetMover(this);
}
void Player::SendInitialPacketsAfterAddToMap()
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 21027402e84..f462f5af48f 100755
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -290,13 +290,14 @@ struct PvPInfo
struct DuelInfo
{
- DuelInfo() : initiator(NULL), opponent(NULL), startTimer(0), startTime(0), outOfBound(0) {}
+ DuelInfo() : initiator(NULL), opponent(NULL), startTimer(0), startTime(0), outOfBound(0), isMounted(false) {}
Player* initiator;
Player* opponent;
time_t startTimer;
time_t startTime;
time_t outOfBound;
+ bool isMounted;
};
struct Areas
@@ -702,7 +703,8 @@ enum TradeSlots
{
TRADE_SLOT_COUNT = 7,
TRADE_SLOT_TRADED_COUNT = 6,
- TRADE_SLOT_NONTRADED = 6
+ TRADE_SLOT_NONTRADED = 6,
+ TRADE_SLOT_INVALID = -1,
};
enum TransferAbortReason
@@ -1013,7 +1015,8 @@ class TradeData
TradeData* GetTraderData() const;
Item* GetItem(TradeSlots slot) const;
- bool HasItem(uint64 item_guid) const;
+ bool HasItem(uint64 itemGuid) const;
+ TradeSlots GetTradeSlotForItem(uint64 itemGuid) const;
void SetItem(TradeSlots slot, Item* item);
uint32 GetSpell() const { return m_spell; }
@@ -1333,6 +1336,7 @@ class Player : public Unit, public GridObject<Player>
bool HasItemTotemCategory(uint32 TotemCategory) const;
InventoryResult CanUseItem(ItemTemplate const* pItem) const;
InventoryResult CanUseAmmo(uint32 item) const;
+ InventoryResult CanRollForItemInLFG(ItemTemplate const* item, WorldObject const* lootedObject) const;
Item* StoreNewItem(ItemPosCountVec const& pos, uint32 item, bool update, int32 randomPropertyId = 0);
Item* StoreNewItem(ItemPosCountVec const& pos, uint32 item, bool update, int32 randomPropertyId, AllowedLooterSet &allowedLooters);
Item* StoreItem(ItemPosCountVec const& pos, Item* pItem, bool update);
@@ -2046,7 +2050,6 @@ class Player : public Unit, public GridObject<Player>
Corpse* GetCorpse() const;
void SpawnCorpseBones();
void CreateCorpse();
- bool FallGround(uint8 FallMode = 0);
void KillPlayer();
uint32 GetResurrectionSpellId();
void ResurrectPlayer(float restore_percent, bool applySickness = false);
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 430b6adb6ec..103e42a9da9 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -45,16 +45,16 @@
#include "InstanceSaveMgr.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
-#include "Path.h"
#include "CreatureGroups.h"
#include "PetAI.h"
#include "PassiveAI.h"
-#include "Traveller.h"
#include "TemporarySummon.h"
#include "Vehicle.h"
#include "Transport.h"
#include "InstanceScript.h"
#include "SpellInfo.h"
+#include "MoveSplineInit.h"
+#include "MoveSpline.h"
#include <math.h>
@@ -62,9 +62,9 @@ float baseMoveSpeed[MAX_MOVE_TYPE] =
{
2.5f, // MOVE_WALK
7.0f, // MOVE_RUN
- 2.5f, // MOVE_RUN_BACK
+ 4.5f, // MOVE_RUN_BACK
4.722222f, // MOVE_SWIM
- 4.5f, // MOVE_SWIM_BACK
+ 2.5f, // MOVE_SWIM_BACK
3.141594f, // MOVE_TURN_RATE
7.0f, // MOVE_FLIGHT
4.5f, // MOVE_FLIGHT_BACK
@@ -73,9 +73,9 @@ float baseMoveSpeed[MAX_MOVE_TYPE] =
float playerBaseMoveSpeed[MAX_MOVE_TYPE] = {
2.5f, // MOVE_WALK
7.0f, // MOVE_RUN
- 2.5f, // MOVE_RUN_BACK
+ 4.5f, // MOVE_RUN_BACK
4.722222f, // MOVE_SWIM
- 4.5f, // MOVE_SWIM_BACK
+ 2.5f, // MOVE_SWIM_BACK
3.141594f, // MOVE_TURN_RATE
7.0f, // MOVE_FLIGHT
4.5f, // MOVE_FLIGHT_BACK
@@ -148,7 +148,7 @@ Unit::Unit(bool isWorldObject): WorldObject(isWorldObject),
m_movedPlayer(NULL), m_lastSanctuaryTime(0), IsAIEnabled(false), NeedChangeAI(false),
m_ControlledByPlayer(false), i_AI(NULL), i_disabledAI(NULL), m_procDeep(0),
m_removedAurasCount(0), i_motionMaster(this), m_ThreatManager(this), m_vehicle(NULL),
-m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this)
+m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this), movespline(new Movement::MoveSpline())
{
#ifdef _MSC_VER
#pragma warning(default:4355)
@@ -280,6 +280,7 @@ Unit::~Unit()
delete m_charmInfo;
delete m_vehicleKit;
+ delete movespline;
ASSERT(!m_duringRemoveFromWorld);
ASSERT(!m_attacking);
@@ -346,6 +347,7 @@ void Unit::Update(uint32 p_time)
ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, HealthAbovePct(75));
}
+ UpdateSplineMovement(p_time);
i_motionMaster.UpdateMotion(p_time);
}
@@ -357,151 +359,46 @@ bool Unit::haveOffhandWeapon() const
return m_canDualWield;
}
-void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player* player)
+void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed)
{
- float x, y, z;
- if (GetMotionMaster()->GetDestination(x, y, z))
- SendMonsterMoveWithSpeed(x, y, z, 0, player);
-}
-
-void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime, Player* player)
-{
- if (!transitTime)
- {
- if (GetTypeId() == TYPEID_PLAYER)
- {
- Traveller<Player> traveller(*(Player*)this);
- transitTime = traveller.GetTotalTrevelTimeTo(x, y, z);
- }
- else
- {
- Traveller<Creature> traveller(*ToCreature());
- transitTime = traveller.GetTotalTrevelTimeTo(x, y, z);
- }
- }
- //float orientation = (float)atan2((double)dy, (double)dx);
- SendMonsterMove(x, y, z, transitTime, player);
-}
-
-void Unit::SetFacing(float ori, WorldObject* obj)
-{
- SetOrientation(obj ? GetAngle(obj) : ori);
-
- WorldPacket data(SMSG_MONSTER_MOVE, (1+12+4+1+(obj ? 8 : 4)+4+4+4+12+GetPackGUID().size()));
- data.append(GetPackGUID());
- data << uint8(0); // unk
- data << GetPositionX() << GetPositionY() << GetPositionZ();
- data << getMSTime();
- if (obj)
- {
- data << uint8(SPLINETYPE_FACING_TARGET);
- data << uint64(obj->GetGUID());
- }
- else
- {
- data << uint8(SPLINETYPE_FACING_ANGLE);
- data << ori;
- }
- data << uint32(SPLINEFLAG_NONE);
- data << uint32(0); // move time 0
- data << uint32(1); // one point
- data << GetPositionX() << GetPositionY() << GetPositionZ();
- SendMessageToSet(&data, true);
-}
-
-void Unit::SendMonsterStop(bool on_death)
-{
- WorldPacket data(SMSG_MONSTER_MOVE, (17 + GetPackGUID().size()));
- data.append(GetPackGUID());
- data << uint8(0); // new in 3.1
- data << GetPositionX() << GetPositionY() << GetPositionZ();
- data << getMSTime();
-
- if (on_death == true)
- {
- data << uint8(0);
- data << uint32((GetUnitMovementFlags() & MOVEMENTFLAG_LEVITATING) ? SPLINEFLAG_FLYING : SPLINEFLAG_WALKING);
- data << uint32(0); // Time in between points
- data << uint32(1); // 1 single waypoint
- data << GetPositionX() << GetPositionY() << GetPositionZ();
- }
- else
- data << uint8(1);
-
- SendMessageToSet(&data, true);
-
- ClearUnitState(UNIT_STAT_MOVE);
+ Movement::MoveSplineInit init(*this);
+ init.MoveTo(x,y,z);
+ init.SetVelocity(speed);
+ init.Launch();
}
-void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 Time, Player* player)
+void Unit::UpdateSplineMovement(uint32 t_diff)
{
- WorldPacket data(SMSG_MONSTER_MOVE, 1+12+4+1+4+4+4+12+GetPackGUID().size());
- data.append(GetPackGUID());
-
- data << uint8(0); // new in 3.1
- data << GetPositionX() << GetPositionY() << GetPositionZ();
- data << getMSTime();
-
- data << uint8(0);
- data << uint32((GetUnitMovementFlags() & MOVEMENTFLAG_LEVITATING) ? SPLINEFLAG_FLYING : SPLINEFLAG_WALKING);
- data << Time; // Time in between points
- data << uint32(1); // 1 single waypoint
- data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B
-
- if (player)
- player->GetSession()->SendPacket(&data);
- else
- SendMessageToSet(&data, true);
-
- AddUnitState(UNIT_STAT_MOVE);
-}
+ enum{
+ POSITION_UPDATE_DELAY = 400,
+ };
-void Unit::SendMonsterMove(MonsterMoveData const& moveData, Player* player)
-{
- WorldPacket data(SMSG_MONSTER_MOVE, GetPackGUID().size() + 1 + 12 + 4 + 1 + 4 + 8 + 4 + 4 + 12);
- data.append(GetPackGUID());
+ if (movespline->Finalized())
+ return;
- data << uint8(0); // new in 3.1
- data << GetPositionX() << GetPositionY() << GetPositionZ();
- data << getMSTime();
+ movespline->updateState(t_diff);
+ bool arrived = movespline->Finalized();
- data << uint8(0);
- data << moveData.SplineFlag;
+ if (arrived)
+ DisableSpline();
- if (moveData.SplineFlag & SPLINEFLAG_ANIMATIONTIER)
+ m_movesplineTimer.Update(t_diff);
+ if (m_movesplineTimer.Passed() || arrived)
{
- data << uint8(moveData.AnimationState);
- data << uint32(0);
- }
+ m_movesplineTimer.Reset(POSITION_UPDATE_DELAY);
+ Movement::Location loc = movespline->ComputePosition();
- data << moveData.Time;
-
- if (moveData.SplineFlag & SPLINEFLAG_TRAJECTORY)
- {
- data << moveData.SpeedZ;
- data << uint32(0); // walk time after jump
+ if (GetTypeId() == TYPEID_PLAYER)
+ ((Player*)this)->UpdatePosition(loc.x,loc.y,loc.z,loc.orientation);
+ else
+ GetMap()->CreatureRelocation((Creature*)this,loc.x,loc.y,loc.z,loc.orientation);
}
-
- data << uint32(1); // waypoint count
- data << moveData.DestLocation.GetPositionX();
- data << moveData.DestLocation.GetPositionY();
- data << moveData.DestLocation.GetPositionZ();
-
- if (player)
- player->GetSession()->SendPacket(&data);
- else
- SendMessageToSet(&data, true);
}
-void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 MoveFlags, uint32 time, float speedZ, Player* player)
+void Unit::DisableSpline()
{
- MonsterMoveData data;
- data.DestLocation.Relocate(NewPosX, NewPosY, NewPosZ);
- data.SplineFlag = MoveFlags;
- data.Time = time;
- data.SpeedZ = speedZ;
-
- SendMonsterMove(data, player);
+ m_movementInfo.RemoveMovementFlag(MovementFlags(MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD));
+ movespline->_Interrupt();
}
void Unit::SendMonsterMoveExitVehicle(Position const* newPos)
@@ -731,6 +628,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
// duel ends when player has 1 or less hp
bool duel_hasEnded = false;
+ bool duel_wasMounted = false;
if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->duel && damage >= (health-1))
{
// prevent kill only if killed in duel and killed by opponent or opponent controlled creature
@@ -739,6 +637,20 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
duel_hasEnded = true;
}
+ else if (victim->IsVehicle() && damage >= (health-1) && victim->GetCharmer() && victim->GetCharmer()->GetTypeId() == TYPEID_PLAYER)
+ {
+ Player* victimRider = victim->GetCharmer()->ToPlayer();
+
+ if (victimRider && victimRider->duel && victimRider->duel->isMounted)
+ {
+ // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
+ if (victimRider->duel->opponent == this || victimRider->duel->opponent->GetGUID() == GetCharmerGUID())
+ damage = health - 1;
+
+ duel_wasMounted = true;
+ duel_hasEnded = true;
+ }
+ }
if (GetTypeId() == TYPEID_PLAYER && this != victim)
{
@@ -848,8 +760,18 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
// last damage from duel opponent
if (duel_hasEnded)
{
- ASSERT(victim->GetTypeId() == TYPEID_PLAYER);
- Player* he = victim->ToPlayer();
+ Player* he;
+
+ if (duel_wasMounted)
+ {
+ ASSERT(victim->GetCharmer()->GetTypeId() == TYPEID_PLAYER);
+ he = victim->GetCharmer()->ToPlayer();
+ }
+ else
+ {
+ ASSERT(victim->GetTypeId() == TYPEID_PLAYER);
+ he = victim->ToPlayer();
+ }
ASSERT(he->duel);
@@ -2226,12 +2148,12 @@ void Unit::SendMeleeAttackStart(Unit* victim)
void Unit::SendMeleeAttackStop(Unit* victim)
{
- WorldPacket data(SMSG_ATTACKSTOP, (8+8+4)); // we guess size
+ WorldPacket data(SMSG_ATTACKSTOP, (8+8+4));
data.append(GetPackGUID());
data.append(victim ? victim->GetPackGUID() : 0); // can be 0x00...
data << uint32(0); // can be 0x1
SendMessageToSet(&data, true);
- sLog->outStaticDebug("WORLD: Sent SMSG_ATTACKSTART");
+ sLog->outStaticDebug("WORLD: Sent SMSG_ATTACKSTOP");
if (victim)
sLog->outDetail("%s %u stopped attacking %s %u", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow(), (victim->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), victim->GetGUIDLow());
@@ -3115,17 +3037,6 @@ bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
return IsWithinDistInMap(target, distance) && !HasInArc(2 * M_PI - arc, target);
}
-void Unit::SetFacingToObject(WorldObject* pObject)
-{
- // update orientation at server
- SetOrientation(GetAngle(pObject));
-
- // and client
- WorldPacket data;
- BuildHeartBeatMsg(&data);
- SendMessageToSet(&data, false);
-}
-
bool Unit::isInAccessiblePlaceFor(Creature const* c) const
{
if (IsInWater())
@@ -7191,6 +7102,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
return false;
basepoints0 = CalculatePctN(int32(damage), triggerAmount);
triggered_spell_id = 58879;
+ // Cast on spirit wolf
+ CastCustomSpell(this, triggered_spell_id, &basepoints0, NULL, NULL, true, NULL, triggeredByAura);
break;
}
// Shaman T8 Elemental 4P Bonus
@@ -8947,18 +8860,17 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
// Maelstrom Weapon
case 53817:
{
- // Item - Shaman T10 Enhancement 4P Bonus
- if (AuraEffect const* aurEff = GetAuraEffect(70832, 0))
- if (Aura const* maelstrom = GetAura(53817))
- if ((maelstrom->GetStackAmount() == maelstrom->GetSpellInfo()->StackAmount) && roll_chance_i(aurEff->GetAmount()))
- CastSpell(this, 70831, true, castItem, triggeredByAura);
-
// has rank dependant proc chance, ignore too often cases
// PPM = 2.5 * (rank of talent),
uint32 rank = auraSpellInfo->GetRank();
// 5 rank -> 100% 4 rank -> 80% and etc from full rate
if (!roll_chance_i(20*rank))
return false;
+ // Item - Shaman T10 Enhancement 4P Bonus
+ if (AuraEffect const* aurEff = GetAuraEffect(70832, 0))
+ if (Aura const* maelstrom = GetAura(53817))
+ if ((maelstrom->GetStackAmount() == maelstrom->GetSpellInfo()->StackAmount - 1) && roll_chance_i(aurEff->GetAmount()))
+ CastSpell(this, 70831, true, castItem, triggeredByAura);
break;
}
// Astral Shift
@@ -13150,7 +13062,7 @@ void Unit::setDeathState(DeathState s)
ClearDiminishings();
GetMotionMaster()->Clear(false);
GetMotionMaster()->MoveIdle();
- SendMonsterStop(true);
+ StopMoving();
// without this when removing IncreaseMaxHealth aura player may stuck with 1 hp
// do not why since in IncreaseMaxHealth currenthealth is checked
SetHealth(0);
@@ -13969,7 +13881,7 @@ void Unit::SetHealth(uint32 val)
{
if (getDeathState() == JUST_DIED)
val = 0;
- else if (GetTypeId() == TYPEID_PLAYER && (getDeathState() == DEAD || getDeathState() == DEAD_FALLING))
+ else if (GetTypeId() == TYPEID_PLAYER && getDeathState() == DEAD)
val = 1;
else
{
@@ -15145,22 +15057,20 @@ void Unit::StopMoving()
{
ClearUnitState(UNIT_STAT_MOVING);
- // send explicit stop packet
- // rely on vmaps here because for example stormwind is in air
- //float z = sMapMgr->GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true);
- //if (fabs(GetPositionZ() - z) < 2.0f)
- // Relocate(GetPositionX(), GetPositionY(), z);
- //Relocate(GetPositionX(), GetPositionY(), GetPositionZ());
+ // not need send any packets if not in world
+ if (!IsInWorld())
+ return;
- if (!(GetUnitMovementFlags() & MOVEMENTFLAG_ONTRANSPORT))
- SendMonsterStop();
+ Movement::MoveSplineInit init(*this);
+ init.SetFacing(GetOrientation());
+ init.Launch();
}
void Unit::SendMovementFlagUpdate()
{
WorldPacket data;
BuildHeartBeatMsg(&data);
- SendMessageToSet(&data, false);
+ SendMessageToSet(&data, true);
}
bool Unit::IsSitState() const
@@ -16426,6 +16336,7 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
case CHARM_TYPE_VEHICLE:
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
charmer->ToPlayer()->SetClientControl(this, 1);
+ charmer->ToPlayer()->SetMover(this);
charmer->ToPlayer()->SetViewpoint(this, true);
charmer->ToPlayer()->VehicleSpellInitialize();
break;
@@ -16434,6 +16345,7 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
charmer->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
charmer->ToPlayer()->SetClientControl(this, 1);
+ charmer->ToPlayer()->SetMover(this);
charmer->ToPlayer()->SetViewpoint(this, true);
charmer->ToPlayer()->PossessSpellInitialize();
break;
@@ -16724,7 +16636,7 @@ void Unit::GetRaidMember(std::list<Unit*> &nearMembers, float radius)
if (owner->isAlive() && (owner == this || IsWithinDistInMap(owner, radius)))
nearMembers.push_back(owner);
if (Guardian* pet = owner->GetGuardianPet())
- if (pet->isAlive() && (pet == this && IsWithinDistInMap(pet, radius)))
+ if (pet->isAlive() && (pet == this || IsWithinDistInMap(pet, radius)))
nearMembers.push_back(pet);
}
}
@@ -16761,7 +16673,7 @@ void Unit::GetPartyMemberInDist(std::list<Unit*> &TagUnitMap, float radius)
if (owner->isAlive() && (owner == this || IsWithinDistInMap(owner, radius)))
TagUnitMap.push_back(owner);
if (Guardian* pet = owner->GetGuardianPet())
- if (pet->isAlive() && (pet == this && IsWithinDistInMap(pet, radius)))
+ if (pet->isAlive() && (pet == this || IsWithinDistInMap(pet, radius)))
TagUnitMap.push_back(pet);
}
}
@@ -17568,6 +17480,10 @@ void Unit::_ExitVehicle(Position const* exitPosition)
m_vehicle->RemovePassenger(this);
+ // If player is on mouted duel and exits the mount should immediatly lose the duel
+ if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->duel && ToPlayer()->duel->isMounted)
+ ToPlayer()->DuelComplete(DUEL_FLED);
+
// This should be done before dismiss, because there may be some aura removal
Vehicle* vehicle = m_vehicle;
m_vehicle = NULL;
@@ -17599,7 +17515,7 @@ void Unit::_ExitVehicle(Position const* exitPosition)
WorldPacket data2;
BuildHeartBeatMsg(&data2);
- SendMessageToSet(&data2, false);
+ SendMessageToSet(&data2, true);
if (vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION))
if (((Minion*)vehicle->GetBase())->GetOwner() == this)
@@ -17729,13 +17645,13 @@ void Unit::SetFlying(bool apply)
void Unit::NearTeleportTo(float x, float y, float z, float orientation, bool casting /*= false*/)
{
+ DisableSpline();
if (GetTypeId() == TYPEID_PLAYER)
ToPlayer()->TeleportTo(GetMapId(), x, y, z, orientation, TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (casting ? TELE_TO_SPELL : 0));
else
{
- // FIXME: this interrupts spell visual
- DestroyForNearbyPlayers();
UpdatePosition(x, y, z, orientation, true);
+ SendMovementFlagUpdate();
}
}
@@ -18017,3 +17933,26 @@ bool CharmInfo::IsReturning()
{
return m_isReturning;
}
+
+void Unit::SetInFront(Unit const* target)
+{
+ if (!HasUnitState(UNIT_STAT_CANNOT_TURN))
+ SetOrientation(GetAngle(target));
+}
+
+void Unit::SetFacingTo(float ori)
+{
+ Movement::MoveSplineInit init(*this);
+ init.SetFacing(ori);
+ init.Launch();
+}
+
+void Unit::SetFacingToObject(WorldObject* pObject)
+{
+ // never face when already moving
+ if (!IsStopped())
+ return;
+
+ // TODO: figure out under what conditions creature will move towards object instead of facing it where it currently is.
+ SetFacingTo(GetAngle(pObject));
+}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 21dcb4bf3fe..c50cba080c7 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -465,7 +465,6 @@ enum DeathState
CORPSE = 2,
DEAD = 3,
JUST_ALIVED = 4,
- DEAD_FALLING= 5
};
enum UnitState
@@ -493,13 +492,22 @@ enum UnitState
UNIT_STAT_MOVE = 0x00100000,
UNIT_STAT_ROTATING = 0x00200000,
UNIT_STAT_EVADE = 0x00400000,
+ UNIT_STAT_ROAMING_MOVE = 0x00800000,
+ UNIT_STAT_CONFUSED_MOVE = 0x01000000,
+ UNIT_STAT_FLEEING_MOVE = 0x02000000,
+ UNIT_STAT_CHASE_MOVE = 0x04000000,
+ UNIT_STAT_FOLLOW_MOVE = 0x08000000,
UNIT_STAT_UNATTACKABLE = (UNIT_STAT_IN_FLIGHT | UNIT_STAT_ONVEHICLE),
- UNIT_STAT_MOVING = (UNIT_STAT_ROAMING | UNIT_STAT_CHASE),
+ //UNIT_STAT_MOVING = (UNIT_STAT_ROAMING | UNIT_STAT_CHASE),
+ // for real move using movegen check and stop (except unstoppable flight)
+ UNIT_STAT_MOVING = UNIT_STAT_ROAMING_MOVE | UNIT_STAT_CONFUSED_MOVE | UNIT_STAT_FLEEING_MOVE| UNIT_STAT_CHASE_MOVE | UNIT_STAT_FOLLOW_MOVE ,
UNIT_STAT_CONTROLLED = (UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING),
UNIT_STAT_LOST_CONTROL = (UNIT_STAT_CONTROLLED | UNIT_STAT_JUMPING | UNIT_STAT_CHARGING),
UNIT_STAT_SIGHTLESS = (UNIT_STAT_LOST_CONTROL | UNIT_STAT_EVADE),
UNIT_STAT_CANNOT_AUTOATTACK = (UNIT_STAT_LOST_CONTROL | UNIT_STAT_CASTING),
UNIT_STAT_CANNOT_TURN = (UNIT_STAT_LOST_CONTROL | UNIT_STAT_ROTATING),
+ // stay by different reasons
+ UNIT_STAT_NOT_MOVE = UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DIED | UNIT_STAT_DISTRACTED,
UNIT_STAT_ALL_STATE = 0xffffffff //(UNIT_STAT_STOPPED | UNIT_STAT_MOVING | UNIT_STAT_IN_COMBAT | UNIT_STAT_IN_FLIGHT)
};
@@ -719,59 +727,18 @@ enum MovementFlags2
MOVEMENTFLAG2_UNK15 = 0x00004000,
MOVEMENTFLAG2_UNK16 = 0x00008000,
};
+
enum SplineFlags
{
- SPLINEFLAG_NONE = 0x00000000,
- SPLINEFLAG_FORWARD = 0x00000001,
- SPLINEFLAG_BACKWARD = 0x00000002,
- SPLINEFLAG_STRAFE_LEFT = 0x00000004,
- SPLINEFLAG_STRAFE_RIGHT = 0x00000008,
- SPLINEFLAG_LEFT = 0x00000010,
- SPLINEFLAG_RIGHT = 0x00000020,
- SPLINEFLAG_PITCH_UP = 0x00000040,
- SPLINEFLAG_PITCH_DOWN = 0x00000080,
- SPLINEFLAG_DONE = 0x00000100,
- SPLINEFLAG_FALLING = 0x00000200,
- SPLINEFLAG_NO_SPLINE = 0x00000400,
- SPLINEFLAG_TRAJECTORY = 0x00000800,
- SPLINEFLAG_WALKING = 0x00001000,
- SPLINEFLAG_FLYING = 0x00002000,
- SPLINEFLAG_KNOCKBACK = 0x00004000,
- SPLINEFLAG_FINAL_POINT = 0x00008000,
- SPLINEFLAG_FINAL_TARGET = 0x00010000,
- SPLINEFLAG_FINAL_FACING = 0x00020000,
- SPLINEFLAG_CATMULL_ROM = 0x00040000,
- SPLINEFLAG_UNKNOWN20 = 0x00080000,
- SPLINEFLAG_UNKNOWN21 = 0x00100000,
- SPLINEFLAG_ANIMATIONTIER = 0x00200000,
- SPLINEFLAG_UNKNOWN23 = 0x00400000,
- SPLINEFLAG_TRANSPORT = 0x00800000,
- SPLINEFLAG_EXIT_VEHICLE = 0x01000000,
- SPLINEFLAG_UNKNOWN26 = 0x02000000,
- SPLINEFLAG_UNKNOWN27 = 0x04000000,
- SPLINEFLAG_UNKNOWN28 = 0x08000000,
- SPLINEFLAG_UNKNOWN29 = 0x10000000,
- SPLINEFLAG_ANIMATION = 0x20000000,
- SPLINEFLAG_UNKNOWN31 = 0x40000000,
- SPLINEFLAG_UNKNOWN32 = 0x80000000,
-
- SPLINEFLAG_GLIDE = SPLINEFLAG_WALKING | SPLINEFLAG_FLYING,
-};
-
-enum SplineMode
-{
- SPLINEMODE_LINEAR = 0,
- SPLINEMODE_CATMULL_ROM = 1,
- SPLINEMODE_BEZIER3 = 2
+ SPLINEFLAG_WALKMODE = 0x00001000,
+ SPLINEFLAG_FLYING = 0x00002000,
+ SPLINEFLAG_TRANSPORT = 0x00800000,
+ SPLINEFLAG_EXIT_VEHICLE = 0x01000000,
};
enum SplineType
{
- SPLINETYPE_NORMAL = 0,
- SPLINETYPE_STOP = 1,
- SPLINETYPE_FACING_SPOT = 2,
- SPLINETYPE_FACING_TARGET = 3,
- SPLINETYPE_FACING_ANGLE = 4
+ SPLINETYPE_FACING_ANGLE = 4,
};
enum UnitTypeMask
@@ -789,6 +756,10 @@ enum UnitTypeMask
UNIT_MASK_ACCESSORY = 0x00000200,
};
+namespace Movement{
+ class MoveSpline;
+}
+
enum DiminishingLevels
{
DIMINISHING_LEVEL_1 = 0,
@@ -1631,20 +1602,18 @@ class Unit : public WorldObject
void JumpTo(float speedXY, float speedZ, bool forward = true);
void JumpTo(WorldObject* obj, float speedZ);
- void SetFacing(float ori, WorldObject* obj = NULL);
- void SendMonsterStop(bool on_death = false);
- void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 Time, Player* player = NULL);
- void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 MoveFlags, uint32 time, float speedZ, Player* player = NULL);
- void SendMonsterMove(MonsterMoveData const& moveData, Player* receiver = NULL);
+ void MonsterMoveWithSpeed(float x, float y, float z, float speed);
+ //void SetFacing(float ori, WorldObject* obj = NULL);
void SendMonsterMoveExitVehicle(Position const* newPos);
//void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL);
void SendMonsterMoveTransport(Unit* vehicleOwner);
- void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0, Player* player = NULL);
- void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL);
void SendMovementFlagUpdate();
+ bool IsLevitating() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_LEVITATING);}
+ bool IsWalking() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING);}
- template<typename PathElem, typename PathNode>
- void SendMonsterMoveByPath(Path<PathElem, PathNode> const& path, uint32 start, uint32 end);
+ void SetInFront(Unit const* target);
+ void SetFacingTo(float ori);
+ void SetFacingToObject(WorldObject* pObject);
void SendChangeCurrentVictimOpcode(HostileReference* pHostileReference);
void SendClearThreatListOpcode();
@@ -1954,13 +1923,7 @@ class Unit : public WorldObject
void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; }
bool isInFrontInMap(Unit const* target, float distance, float arc = M_PI) const;
- void SetInFront(Unit const* target)
- {
- if (!HasUnitState(UNIT_STAT_CANNOT_TURN))
- SetOrientation(GetAngle(target));
- }
bool isInBackInMap(Unit const* target, float distance, float arc = M_PI) const;
- void SetFacingToObject(WorldObject* pObject);
// Visibility system
bool IsVisible() const { return (m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM) > SEC_PLAYER) ? false : true; }
@@ -2235,6 +2198,9 @@ class Unit : public WorldObject
SetUInt64Value(UNIT_FIELD_TARGET, 0);
}
+ // Movement info
+ Movement::MoveSpline * movespline;
+
protected:
explicit Unit (bool isWorldObject);
@@ -2306,6 +2272,8 @@ class Unit : public WorldObject
bool IsAlwaysVisibleFor(WorldObject const* seer) const;
bool IsAlwaysDetectableFor(WorldObject const* seer) const;
+
+ void DisableSpline();
private:
bool IsTriggeredAtSpellProcEvent(Unit* pVictim, Aura* aura, SpellInfo const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const* & spellProcEvent);
bool HandleDummyAuraProc(Unit* pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
@@ -2319,6 +2287,8 @@ class Unit : public WorldObject
bool HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura);
bool HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura);
+ void UpdateSplineMovement(uint32 t_diff);
+
// player or player's pet
float GetCombatRatingReduction(CombatRating cr) const;
uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const;
@@ -2333,6 +2303,7 @@ class Unit : public WorldObject
uint32 m_state; // Even derived shouldn't modify
uint32 m_CombatTimer;
uint32 m_lastManaUse; // msecs
+ TimeTrackerSmall m_movesplineTimer;
Diminishing m_Diminishing;
// Manage all Units that are threatened by us
@@ -2385,31 +2356,4 @@ namespace Trinity
const bool m_ascending;
};
}
-
-template<typename Elem, typename Node>
-inline void Unit::SendMonsterMoveByPath(Path<Elem, Node> const& path, uint32 start, uint32 end)
-{
- uint32 traveltime = uint32(path.GetTotalLength(start, end) * 32);
- uint32 pathSize = end - start;
- WorldPacket data(SMSG_MONSTER_MOVE, (GetPackGUID().size()+1+4+4+4+4+1+4+4+4+pathSize*4*3));
- data.append(GetPackGUID());
- data << uint8(0);
- data << GetPositionX();
- data << GetPositionY();
- data << GetPositionZ();
- data << uint32(getMSTime());
- data << uint8(0);
- data << uint32(((GetUnitMovementFlags() & MOVEMENTFLAG_LEVITATING) || isInFlight()) ? (SPLINEFLAG_FLYING|SPLINEFLAG_WALKING) : SPLINEFLAG_WALKING);
- data << uint32(traveltime);
- data << uint32(pathSize);
-
- for (uint32 i = start; i < end; ++i)
- {
- data << float(path[i].x);
- data << float(path[i].y);
- data << float(path[i].z);
- }
-
- SendMessageToSet(&data, true);
-}
#endif
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 6d9fbbc435d..30e0efc15a2 100755
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -8762,7 +8762,7 @@ void ObjectMgr::CheckScripts(ScriptsType type, std::set<int32>& ids)
case SCRIPT_COMMAND_TALK:
{
if (!GetTrinityStringLocale (itrM->second.Talk.TextID))
- sLog->outErrorDb("Table `db_script_string` not has string id %u used db script (ID: %u)", itrM->second.Talk.TextID, itrMM->first);
+ sLog->outErrorDb("Table `%s` references invalid text id %u from `db_script_string`, script id: %u.", GetScriptsTableNameByType(type).c_str(), itrM->second.Talk.TextID, itrMM->first);
if (ids.find(itrM->second.Talk.TextID) != ids.end())
ids.erase(itrM->second.Talk.TextID);
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 0411d8854ad..fd5b40f8031 100755
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -190,6 +190,9 @@ void Group::LoadGroupFromDB(Field* fields)
m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL;
else
m_raidDifficulty = Difficulty(r_diff);
+
+ if (m_groupType & GROUPTYPE_LFG)
+ sLFGMgr->_LoadFromDB(fields, GetGUID());
}
void Group::LoadMemberFromDB(uint32 guidLow, uint8 memberFlags, uint8 subgroup, uint8 roles)
@@ -200,7 +203,9 @@ void Group::LoadMemberFromDB(uint32 guidLow, uint8 memberFlags, uint8 subgroup,
// skip non-existed member
if (!sObjectMgr->GetPlayerNameByGUID(member.guid, member.name))
{
- CharacterDatabase.PQuery("DELETE FROM group_member WHERE memberGuid=%u", guidLow);
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_MEMBER);
+ stmt->setUInt32(0, guidLow);
+ CharacterDatabase.Execute(stmt);
return;
}
@@ -211,6 +216,14 @@ void Group::LoadMemberFromDB(uint32 guidLow, uint8 memberFlags, uint8 subgroup,
m_memberSlots.push_back(member);
SubGroupCounterIncrease(subgroup);
+
+ if (isLFGGroup())
+ {
+ LfgDungeonSet Dungeons;
+ Dungeons.insert(sLFGMgr->GetDungeon(GetGUID()));
+ sLFGMgr->SetSelectedDungeons(member.guid, Dungeons);
+ sLFGMgr->SetState(member.guid, sLFGMgr->GetState(GetGUID()));
+ }
}
void Group::ConvertToLFG()
@@ -472,7 +485,7 @@ bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOV
return m_memberSlots.size();
// remove member and change leader (if need) only if strong more 2 members _before_ member remove (BG allow 1 member group)
- if (GetMembersCount() > (isBGGroup() ? 1u : 2u))
+ if (GetMembersCount() > ((isBGGroup() || isLFGGroup()) ? 1u : 2u))
{
Player* player = ObjectAccessor::FindPlayer(guid);
if (player)
@@ -516,6 +529,8 @@ bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOV
CharacterDatabase.Execute(stmt);
+ DelinkMember(guid);
+
// Reevaluate group enchanter if the leaving player had enchanting skill or the player is offline
if ((player && player->GetSkillValue(SKILL_ENCHANTING)) || !player)
ResetMaxEnchantingLevel();
@@ -566,6 +581,20 @@ bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOV
SendUpdate();
+ if (isLFGGroup() && GetMembersCount() == 1)
+ {
+ Player* Leader = ObjectAccessor::FindPlayer(GetLeaderGUID());
+ LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(sLFGMgr->GetDungeon(GetGUID()));
+ if ((Leader && dungeon && Leader->isAlive() && Leader->GetMapId() != dungeon->map) || !dungeon)
+ {
+ Disband();
+ return false;
+ }
+ }
+
+ if (m_memberMgr.getSize() < ((isLFGGroup() || isBGGroup()) ? 1u : 2u))
+ Disband();
+
return true;
}
// If group size before player removal <= 2 then disband it
@@ -705,6 +734,10 @@ void Group::Disband(bool hideDestroy /* = false */)
ResetInstances(INSTANCE_RESET_GROUP_DISBAND, false, NULL);
ResetInstances(INSTANCE_RESET_GROUP_DISBAND, true, NULL);
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_LFG_DATA);
+ stmt->setUInt32(0, m_dbStoreId);
+ CharacterDatabase.Execute(stmt);
+
sGroupMgr->FreeGroupDbStoreId(this);
}
@@ -741,6 +774,28 @@ void Group::SendLootStartRoll(uint32 countDown, uint32 mapid, const Roll &r)
}
}
+void Group::SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p, bool canNeed, Roll const& r)
+{
+ if (!p || !p->GetSession())
+ return;
+
+ WorldPacket data(SMSG_LOOT_START_ROLL, (8 + 4 + 4 + 4 + 4 + 4 + 4 + 1 ));
+ data << uint64(r.itemGUID); // guid of rolled item
+ data << uint32(mapId); // 3.3.3 mapid
+ data << uint32(r.totalPlayersRolling); // maybe the number of players rolling for it???
+ data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for
+ data << uint32(r.itemRandomSuffix); // randomSuffix
+ data << uint32(r.itemRandomPropId); // item random property ID
+ data << uint32(r.itemCount); // items in stack
+ data << uint32(countDown); // the countdown time to choose "need" or "greed"
+ uint8 voteMask = r.rollVoteMask;
+ if (!canNeed)
+ voteMask &= ~ROLL_FLAG_TYPE_NEED;
+ data << uint8(voteMask); // roll type mask
+
+ p->GetSession()->SendPacket(&data);
+}
+
void Group::SendLootRoll(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r)
{
WorldPacket data(SMSG_LOOT_ROLL, (8+4+8+4+4+4+1+1+1));
@@ -919,11 +974,11 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject)
}
}
-void Group::NeedBeforeGreed(Loot* loot, WorldObject* pLootedObject)
+void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject)
{
ItemTemplate const* item;
uint8 itemSlot = 0;
- for (std::vector<LootItem>::iterator i=loot->items.begin(); i != loot->items.end(); ++i, ++itemSlot)
+ for (std::vector<LootItem>::iterator i = loot->items.begin(); i != loot->items.end(); ++i, ++itemSlot)
{
if (i->freeforall)
continue;
@@ -934,7 +989,7 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* pLootedObject)
if (item->Quality >= uint32(m_lootThreshold))
{
uint64 newitemGUID = MAKE_NEW_GUID(sObjectMgr->GenerateLowGuid(HIGHGUID_ITEM), 0, HIGHGUID_ITEM);
- Roll* r=new Roll(newitemGUID, *i);
+ Roll* r = new Roll(newitemGUID, *i);
for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
@@ -943,21 +998,17 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* pLootedObject)
continue;
bool allowedForPlayer = i->AllowedForPlayer(playerToRoll);
- if (playerToRoll->CanUseItem(item) == EQUIP_ERR_OK && allowedForPlayer)
+ if (allowedForPlayer && playerToRoll->IsWithinDistInMap(lootedObject, sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE), false))
{
- if (playerToRoll->IsWithinDistInMap(pLootedObject, sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE), false))
+ r->totalPlayersRolling++;
+ if (playerToRoll->GetPassOnGroupLoot())
{
- r->totalPlayersRolling++;
-
- if (playerToRoll->GetPassOnGroupLoot())
- {
- r->playerVote[playerToRoll->GetGUID()] = PASS;
- r->totalPass++;
- // can't broadcast the pass now. need to wait until all rolling players are known.
- }
- else
- r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET;
+ r->playerVote[playerToRoll->GetGUID()] = PASS;
+ r->totalPass++;
+ // can't broadcast the pass now. need to wait until all rolling players are known.
}
+ else
+ r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET;
}
}
@@ -973,29 +1024,31 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* pLootedObject)
loot->items[itemSlot].is_blocked = true;
- // If there is any "auto pass", broadcast the pass now.
- if (r->totalPass)
+ //Broadcast Pass and Send Rollstart
+ for (Roll::PlayerVote::const_iterator itr = r->playerVote.begin(); itr != r->playerVote.end(); ++itr)
{
- for (Roll::PlayerVote::const_iterator itr=r->playerVote.begin(); itr != r->playerVote.end(); ++itr)
- {
- Player* p = ObjectAccessor::FindPlayer(itr->first);
- if (!p || !p->GetSession())
- continue;
+ Player* p = ObjectAccessor::FindPlayer(itr->first);
+ if (!p || !p->GetSession())
+ continue;
- if (itr->second == PASS)
- SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r);
- }
+ if (itr->second == PASS)
+ SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r);
+ else
+ SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, p->CanRollForItemInLFG(item, lootedObject) == EQUIP_ERR_OK, *r);
}
- SendLootStartRoll(60000, pLootedObject->GetMapId(), *r);
-
RollId.push_back(r);
- if (Creature* creature = pLootedObject->ToCreature())
+ if (Creature* creature = lootedObject->ToCreature())
{
creature->m_groupLootTimer = 60000;
creature->lootingGroupLowGUID = GetLowGUID();
}
+ else if (GameObject* go = lootedObject->ToGameObject())
+ {
+ go->m_groupLootTimer = 60000;
+ go->lootingGroupLowGUID = GetLowGUID();
+ }
}
else
delete r;
@@ -1274,9 +1327,7 @@ void Group::SendTargetIconList(WorldSession* session)
void Group::SendUpdate()
{
for (member_witerator witr = m_memberSlots.begin(); witr != m_memberSlots.end(); ++witr)
- {
SendUpdateToPlayer(witr->guid, &(*witr));
- }
}
void Group::SendUpdateToPlayer(uint64 playerGUID, MemberSlot* slot)
@@ -2149,8 +2200,19 @@ void Group::LinkMember(GroupReference* pRef)
m_memberMgr.insertFirst(pRef);
}
-void Group::DelinkMember(GroupReference* /*pRef*/) const
+void Group::DelinkMember(uint64 guid)
{
+ GroupReference* ref = m_memberMgr.getFirst();
+ while (ref)
+ {
+ GroupReference* nextRef = ref->next();
+ if (ref->getSource()->GetGUID() == guid)
+ {
+ ref->unlink();
+ break;
+ }
+ ref = nextRef;
+ }
}
Group::BoundInstancesMap& Group::GetBoundInstances(Difficulty difficulty)
diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h
index 63c89069f52..08246614627 100755
--- a/src/server/game/Groups/Group.h
+++ b/src/server/game/Groups/Group.h
@@ -276,6 +276,7 @@ class Group
bool isRollLootActive() const;
void SendLootStartRoll(uint32 CountDown, uint32 mapid, const Roll &r);
+ void SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p, bool canNeed, Roll const& r);
void SendLootRoll(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r);
void SendLootRollWon(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r);
void SendLootAllPassed(uint32 NumberOfPlayers, const Roll &r);
@@ -292,7 +293,7 @@ class Group
void ResetMaxEnchantingLevel();
void LinkMember(GroupReference* pRef);
- void DelinkMember(GroupReference* /*pRef*/) const;
+ void DelinkMember(uint64 guid);
InstanceGroupBind* BindToInstance(InstanceSave* save, bool permanent, bool load = false);
void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false);
diff --git a/src/server/game/Groups/GroupMgr.cpp b/src/server/game/Groups/GroupMgr.cpp
index 412814a60d2..ae400852c73 100644
--- a/src/server/game/Groups/GroupMgr.cpp
+++ b/src/server/game/Groups/GroupMgr.cpp
@@ -119,10 +119,10 @@ void GroupMgr::LoadGroups()
// Delete all groups with less than 2 members
CharacterDatabase.DirectExecute("DELETE FROM groups WHERE guid NOT IN (SELECT guid FROM group_member GROUP BY guid HAVING COUNT(guid) > 1)");
- // 0 1 2 3 4 5 6 7 8 9
- QueryResult result = CharacterDatabase.PQuery("SELECT leaderGuid, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6"
- // 10 11 12 13 14 15
- ", icon7, icon8, groupType, difficulty, raiddifficulty, guid FROM groups ORDER BY guid ASC");
+ // 0 1 2 3 4 5 6 7 8 9
+ QueryResult result = CharacterDatabase.PQuery("SELECT g.leaderGuid, g.lootMethod, g.looterGuid, g.lootThreshold, g.icon1, g.icon2, g.icon3, g.icon4, g.icon5, g.icon6"
+ // 10 11 12 13 14 15 16 17
+ ", g.icon7, g.icon8, g.groupType, g.difficulty, g.raiddifficulty, g.guid, lfg.dungeon, lfg.state FROM groups g LEFT JOIN lfg_data lfg ON lfg.guid = g.guid ORDER BY g.guid ASC");
if (!result)
{
sLog->outString(">> Loaded 0 group definitions. DB table `groups` is empty!");
diff --git a/src/server/game/Groups/GroupReference.cpp b/src/server/game/Groups/GroupReference.cpp
index 4d5890aa4e6..68d85c5bce9 100755
--- a/src/server/game/Groups/GroupReference.cpp
+++ b/src/server/game/Groups/GroupReference.cpp
@@ -28,12 +28,12 @@ void GroupReference::targetObjectBuildLink()
void GroupReference::targetObjectDestroyLink()
{
// called from unlink()
- getTarget()->DelinkMember(this);
+ //getTarget()->DelinkMember(this);
}
void GroupReference::sourceObjectDestroyLink()
{
// called from invalidate()
- getTarget()->DelinkMember(this);
+ //getTarget()->DelinkMember(this);
}
diff --git a/src/server/game/Server/Protocol/Handlers/AddonHandler.cpp b/src/server/game/Handlers/AddonHandler.cpp
index ef537cb6198..ef537cb6198 100755
--- a/src/server/game/Server/Protocol/Handlers/AddonHandler.cpp
+++ b/src/server/game/Handlers/AddonHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/AddonHandler.h b/src/server/game/Handlers/AddonHandler.h
index 36cb19e5698..36cb19e5698 100755
--- a/src/server/game/Server/Protocol/Handlers/AddonHandler.h
+++ b/src/server/game/Handlers/AddonHandler.h
diff --git a/src/server/game/Server/Protocol/Handlers/ArenaTeamHandler.cpp b/src/server/game/Handlers/ArenaTeamHandler.cpp
index 8fb820713ce..8fb820713ce 100755
--- a/src/server/game/Server/Protocol/Handlers/ArenaTeamHandler.cpp
+++ b/src/server/game/Handlers/ArenaTeamHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp
index 845f3279356..845f3279356 100755
--- a/src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp
+++ b/src/server/game/Handlers/AuctionHouseHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/AuthHandler.cpp b/src/server/game/Handlers/AuthHandler.cpp
index c5dbcb4f946..c5dbcb4f946 100755
--- a/src/server/game/Server/Protocol/Handlers/AuthHandler.cpp
+++ b/src/server/game/Handlers/AuthHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp
index 00f18217eed..00f18217eed 100755
--- a/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp
+++ b/src/server/game/Handlers/BattleGroundHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp
index be547c84b19..be547c84b19 100755
--- a/src/server/game/Server/Protocol/Handlers/CalendarHandler.cpp
+++ b/src/server/game/Handlers/CalendarHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp b/src/server/game/Handlers/ChannelHandler.cpp
index efa2d54a65d..efa2d54a65d 100755
--- a/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp
+++ b/src/server/game/Handlers/ChannelHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 62b9fe0b582..ee68a15c301 100644
--- a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -43,6 +43,7 @@
#include "Battleground.h"
#include "AccountMgr.h"
#include "DBCStores.h"
+#include "LFGMgr.h"
class LoginQueryHolder : public SQLQueryHolder
{
@@ -196,7 +197,7 @@ bool LoginQueryHolder::Initialize()
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES);
stmt->setUInt32(0, m_accountId);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADINSTANCELOCKTIMES, stmt);
-
+
return res;
}
@@ -872,6 +873,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
// "GetAccountId() == db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools)
if (!pCurrChar->LoadFromDB(GUID_LOPART(playerGuid), holder))
{
+ SetPlayer(NULL);
KickPlayer(); // disconnect client, player no set to session and it will not deleted or saved at kick
delete pCurrChar; // delete it manually
delete holder; // delete all unprocessed queries
@@ -880,9 +882,6 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
}
pCurrChar->GetMotionMaster()->Initialize();
-
- SetPlayer(pCurrChar);
-
pCurrChar->SendDungeonDifficulty(false);
WorldPacket data(SMSG_LOGIN_VERIFY_WORLD, 20);
@@ -992,6 +991,17 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
}
}
+ if (Group* group = pCurrChar->GetGroup())
+ {
+ if (group->isLFGGroup())
+ {
+ LfgDungeonSet Dungeons;
+ Dungeons.insert(sLFGMgr->GetDungeon(group->GetGUID()));
+ sLFGMgr->SetSelectedDungeons(pCurrChar->GetGUID(), Dungeons);
+ sLFGMgr->SetState(pCurrChar->GetGUID(), sLFGMgr->GetState(group->GetGUID()));
+ }
+ }
+
if (!pCurrChar->GetMap()->AddPlayerToMap(pCurrChar) || !pCurrChar->CheckInstanceLoginValid())
{
AreaTrigger const* at = sObjectMgr->GetGoBackTrigger(pCurrChar->GetMapId());
diff --git a/src/server/game/Server/Protocol/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp
index 3a47f214099..3a47f214099 100755
--- a/src/server/game/Server/Protocol/Handlers/ChatHandler.cpp
+++ b/src/server/game/Handlers/ChatHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/CombatHandler.cpp b/src/server/game/Handlers/CombatHandler.cpp
index 6693cdfca27..6693cdfca27 100755
--- a/src/server/game/Server/Protocol/Handlers/CombatHandler.cpp
+++ b/src/server/game/Handlers/CombatHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/DuelHandler.cpp b/src/server/game/Handlers/DuelHandler.cpp
index 8afd9f3b978..8afd9f3b978 100755
--- a/src/server/game/Server/Protocol/Handlers/DuelHandler.cpp
+++ b/src/server/game/Handlers/DuelHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp
index 7d99213acf0..7d99213acf0 100755
--- a/src/server/game/Server/Protocol/Handlers/GroupHandler.cpp
+++ b/src/server/game/Handlers/GroupHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/GuildHandler.cpp b/src/server/game/Handlers/GuildHandler.cpp
index fff068a0a04..fff068a0a04 100755
--- a/src/server/game/Server/Protocol/Handlers/GuildHandler.cpp
+++ b/src/server/game/Handlers/GuildHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp
index 2146b8a89bb..2146b8a89bb 100755
--- a/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp
+++ b/src/server/game/Handlers/ItemHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp
index 7d4e4ec28ae..842e19cf510 100755
--- a/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp
+++ b/src/server/game/Handlers/LFGHandler.cpp
@@ -50,7 +50,8 @@ void BuildPartyLockDungeonBlock(WorldPacket& data, const LfgLockPartyMap& lockMa
void WorldSession::HandleLfgJoinOpcode(WorldPacket& recv_data)
{
if (!sWorld->getBoolConfig(CONFIG_DUNGEON_FINDER_ENABLE) ||
- (GetPlayer()->GetGroup() && GetPlayer()->GetGroup()->GetLeaderGUID() != GetPlayer()->GetGUID()))
+ (GetPlayer()->GetGroup() && GetPlayer()->GetGroup()->GetLeaderGUID() != GetPlayer()->GetGUID() &&
+ (GetPlayer()->GetGroup()->GetMembersCount() == MAXGROUPSIZE || !GetPlayer()->GetGroup()->isLFGGroup())))
{
recv_data.rfinish();
return;
diff --git a/src/server/game/Server/Protocol/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp
index b17817e196f..6508f08dc22 100755
--- a/src/server/game/Server/Protocol/Handlers/LootHandler.cpp
+++ b/src/server/game/Handlers/LootHandler.cpp
@@ -324,7 +324,7 @@ void WorldSession::DoLootRelease(uint64 lguid)
else
{
// not fully looted object
- go->SetLootState(GO_ACTIVATED);
+ go->SetLootState(GO_ACTIVATED, player);
// if the round robin player release, reset it.
if (player->GetGUID() == loot->roundRobinPlayer)
diff --git a/src/server/game/Server/Protocol/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp
index 95459bae0fa..95459bae0fa 100755
--- a/src/server/game/Server/Protocol/Handlers/MailHandler.cpp
+++ b/src/server/game/Handlers/MailHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index 843aa8fd6c0..0b3a675e762 100755
--- a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -160,7 +160,8 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data)
else
{
go->AI()->GossipSelect(_player, menuId, gossipListId);
- sScriptMgr->OnGossipSelect(_player, go, _player->PlayerTalkClass->GetGossipOptionSender(gossipListId), _player->PlayerTalkClass->GetGossipOptionAction(gossipListId));
+ if (!sScriptMgr->OnGossipSelect(_player, go, _player->PlayerTalkClass->GetGossipOptionSender(gossipListId), _player->PlayerTalkClass->GetGossipOptionAction(gossipListId)))
+ _player->OnGossipSelect(go, gossipListId, menuId);
}
}
}
@@ -169,6 +170,11 @@ void WorldSession::HandleWhoOpcode(WorldPacket & recv_data)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_WHO Message");
+ time_t now = time(NULL);
+ if (now - timeLastWhoCommand < 5)
+ return;
+ else timeLastWhoCommand = now;
+
uint32 matchcount = 0;
uint32 level_min, level_max, racemask, classmask, zones_count, str_count;
diff --git a/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index 71dfc670145..5cac0b99c77 100755
--- a/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -479,19 +479,8 @@ void WorldSession::HandleSetActiveMoverOpcode(WorldPacket &recv_data)
if (GetPlayer()->IsInWorld())
{
- if (Unit* mover = ObjectAccessor::GetUnit(*GetPlayer(), guid))
- {
- GetPlayer()->SetMover(mover);
- if (mover != GetPlayer() && mover->canFly())
- {
- GetPlayer()->SendSetFlyPacket(true);
- }
- }
- else
- {
+ if (_player->m_mover->GetGUID() != guid)
sLog->outError("HandleSetActiveMoverOpcode: incorrect mover guid: mover is " UI64FMTD " (%s - Entry: %u) and should be " UI64FMTD, guid, GetLogNameForGuid(guid), GUID_ENPART(guid), _player->m_mover->GetGUID());
- GetPlayer()->SetMover(GetPlayer());
- }
}
}
diff --git a/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp
index c1b59b41ebb..c1b59b41ebb 100755
--- a/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp
+++ b/src/server/game/Handlers/NPCHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/NPCHandler.h b/src/server/game/Handlers/NPCHandler.h
index af84b71a74f..af84b71a74f 100755
--- a/src/server/game/Server/Protocol/Handlers/NPCHandler.h
+++ b/src/server/game/Handlers/NPCHandler.h
diff --git a/src/server/game/Server/Protocol/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 90cda17d477..00a19adc8ae 100755
--- a/src/server/game/Server/Protocol/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -160,6 +160,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint16 spellid
case COMMAND_STAY: //flat=1792 //STAY
pet->AttackStop();
pet->InterruptNonMeleeSpells(false);
+ pet->GetMotionMaster()->Clear(false);
pet->GetMotionMaster()->MoveIdle();
charmInfo->SetCommandState(COMMAND_STAY);
diff --git a/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp b/src/server/game/Handlers/PetitionsHandler.cpp
index dce5e0f78ba..dce5e0f78ba 100755
--- a/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp
+++ b/src/server/game/Handlers/PetitionsHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp
index abb62fb0185..abb62fb0185 100755
--- a/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp
+++ b/src/server/game/Handlers/QueryHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp
index a3debe82ac1..a3debe82ac1 100755
--- a/src/server/game/Server/Protocol/Handlers/QuestHandler.cpp
+++ b/src/server/game/Handlers/QuestHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/ReferAFriendHandler.cpp b/src/server/game/Handlers/ReferAFriendHandler.cpp
index 58d425ddf98..58d425ddf98 100644
--- a/src/server/game/Server/Protocol/Handlers/ReferAFriendHandler.cpp
+++ b/src/server/game/Handlers/ReferAFriendHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp
index 2e4ef5cb40d..2e4ef5cb40d 100755
--- a/src/server/game/Server/Protocol/Handlers/SkillHandler.cpp
+++ b/src/server/game/Handlers/SkillHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
index 09ba46654ee..09ba46654ee 100755
--- a/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp
+++ b/src/server/game/Handlers/SpellHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp
index 81481bdef31..3533b153bd8 100755
--- a/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp
+++ b/src/server/game/Handlers/TaxiHandler.cpp
@@ -27,7 +27,6 @@
#include "UpdateMask.h"
#include "Path.h"
#include "WaypointMovementGenerator.h"
-#include "DestinationHolderImp.h"
void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPacket & recv_data)
{
diff --git a/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp b/src/server/game/Handlers/TicketHandler.cpp
index a270d42b000..a270d42b000 100755
--- a/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp
+++ b/src/server/game/Handlers/TicketHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp
index 900f036df0a..900f036df0a 100755
--- a/src/server/game/Server/Protocol/Handlers/TradeHandler.cpp
+++ b/src/server/game/Handlers/TradeHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/VehicleHandler.cpp b/src/server/game/Handlers/VehicleHandler.cpp
index ce4f6ccb8fe..ce4f6ccb8fe 100644
--- a/src/server/game/Server/Protocol/Handlers/VehicleHandler.cpp
+++ b/src/server/game/Handlers/VehicleHandler.cpp
diff --git a/src/server/game/Server/Protocol/Handlers/VoiceChatHandler.cpp b/src/server/game/Handlers/VoiceChatHandler.cpp
index 34ad5ac3eae..34ad5ac3eae 100755
--- a/src/server/game/Server/Protocol/Handlers/VoiceChatHandler.cpp
+++ b/src/server/game/Handlers/VoiceChatHandler.cpp
diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp
index 9fb2fdf1c25..722b7089a17 100755
--- a/src/server/game/Instances/InstanceSaveMgr.cpp
+++ b/src/server/game/Instances/InstanceSaveMgr.cpp
@@ -532,8 +532,8 @@ void InstanceSaveManager::_ResetInstance(uint32 mapid, uint32 instanceId)
if (iMap && iMap->IsDungeon())
((InstanceMap*)iMap)->Reset(INSTANCE_RESET_RESPAWN_DELAY);
- else
- sObjectMgr->DeleteRespawnTimeForInstance(instanceId); // even if map is not loaded
+
+ sObjectMgr->DeleteRespawnTimeForInstance(instanceId); // even if map is not loaded
// Free up the instance id and allow it to be reused
sMapMgr->FreeInstanceId(instanceId);
diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp
index dd9abbed372..1869a21c738 100755
--- a/src/server/game/Instances/InstanceScript.cpp
+++ b/src/server/game/Instances/InstanceScript.cpp
@@ -302,21 +302,21 @@ void InstanceScript::DoUpdateWorldState(uint32 uiStateId, uint32 uiStateData)
}
// Send Notify to all players in instance
-void InstanceScript::DoSendNotifyToInstance(const char *format, ...)
+void InstanceScript::DoSendNotifyToInstance(char const* format, ...)
{
- InstanceMap::PlayerList const &PlayerList = instance->GetPlayers();
+ InstanceMap::PlayerList const& players = instance->GetPlayers();
- if (!PlayerList.isEmpty())
+ if (!players.isEmpty())
{
va_list ap;
va_start(ap, format);
- for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
- {
- if (Player* player = i->getSource())
- if (WorldSession* pSession = player->GetSession())
- pSession->SendNotification(format, ap);
- }
+ char buff[1024];
+ vsnprintf(buff, 1024, format, ap);
va_end(ap);
+ for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
+ if (Player* player = i->getSource())
+ if (WorldSession* session = player->GetSession())
+ session->SendNotification(buff);
}
}
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index bbe349d76df..ec362cf1a83 100755
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -1539,6 +1539,24 @@ inline GridMap* Map::GetGrid(float x, float y)
return GridMaps[gx][gy];
}
+float Map::GetWaterOrGroundLevel(float x, float y, float z, float* ground /*= NULL*/, bool swim /*= false*/) const
+{
+ if (const_cast<Map*>(this)->GetGrid(x, y))
+ {
+ // we need ground level (including grid height version) for proper return water level in point
+ float ground_z = GetHeight(x, y, z, true, 50.0f);
+ if (ground)
+ *ground = ground_z;
+
+ LiquidData liquid_status;
+
+ ZLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status);
+ return res ? ( swim ? liquid_status.level - 2.0f : liquid_status.level) : ground_z;
+ }
+
+ return VMAP_INVALID_HEIGHT_VALUE;
+}
+
float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
{
// find raw .map surface under Z coordinates
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 9f6b936541e..f3b45bd8f37 100755
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -424,6 +424,8 @@ class Map : public GridRefManager<NGridType>
InstanceMap* ToInstanceMap(){ if (IsDungeon()) return reinterpret_cast<InstanceMap*>(this); else return NULL; }
const InstanceMap* ToInstanceMap() const { if (IsDungeon()) return (const InstanceMap*)((InstanceMap*)this); else return NULL; }
+ float GetWaterOrGroundLevel(float x, float y, float z, float* ground = NULL, bool swim = false) const;
+
private:
void LoadMapAndVMap(int gx, int gy);
void LoadVMap(int gx, int gy);
diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp
index 62520cf2ace..6890ec8ac2e 100755
--- a/src/server/game/Maps/MapManager.cpp
+++ b/src/server/game/Maps/MapManager.cpp
@@ -25,7 +25,6 @@
#include "GridDefines.h"
#include "MapInstanced.h"
#include "InstanceScript.h"
-#include "DestinationHolderImp.h"
#include "Config.h"
#include "World.h"
#include "CellImpl.h"
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 66610adc1f0..e751dbf92fe 100755
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -492,9 +492,9 @@ enum TrinityStrings
LANG_MOVEGENS_WAYPOINT = 529,
LANG_MOVEGENS_ANIMAL_RANDOM = 530,
LANG_MOVEGENS_CONFUSED = 531,
- LANG_MOVEGENS_TARGETED_PLAYER = 532,
- LANG_MOVEGENS_TARGETED_CREATURE = 533,
- LANG_MOVEGENS_TARGETED_NULL = 534,
+ LANG_MOVEGENS_CHASE_PLAYER = 532,
+ LANG_MOVEGENS_CHASE_CREATURE = 533,
+ LANG_MOVEGENS_CHASE_NULL = 534,
LANG_MOVEGENS_HOME_CREATURE = 535,
LANG_MOVEGENS_HOME_PLAYER = 536,
LANG_MOVEGENS_FLIGHT = 537,
@@ -807,7 +807,11 @@ enum TrinityStrings
LANG_CHAR_NOT_BANNED = 1136,
LANG_DEV_ON = 1137,
LANG_DEV_OFF = 1138,
- // Room for more level 3 1139-1199 not used
+ LANG_MOVEGENS_FOLLOW_PLAYER = 1139,
+ LANG_MOVEGENS_FOLLOW_CREATURE = 1140,
+ LANG_MOVEGENS_FOLLOW_NULL = 1141,
+ LANG_MOVEGENS_EFFECT = 1142,
+ // Room for more level 3 1143-1199 not used
// Debug commands
LANG_CINEMATIC_NOT_EXIST = 1200,
diff --git a/src/server/game/Movement/DestinationHolder.cpp b/src/server/game/Movement/DestinationHolder.cpp
deleted file mode 100755
index 4b763112968..00000000000
--- a/src/server/game/Movement/DestinationHolder.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "DestinationHolder.h"
-
diff --git a/src/server/game/Movement/DestinationHolder.h b/src/server/game/Movement/DestinationHolder.h
deleted file mode 100755
index 5ae4ee88ce3..00000000000
--- a/src/server/game/Movement/DestinationHolder.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TRINITY_DESTINATION_HOLDER_H
-#define TRINITY_DESTINATION_HOLDER_H
-
-#include "Define.h"
-#include "Timer.h"
-
-class WorldObject;
-class Map;
-
-#define TRAVELLER_UPDATE_INTERVAL 300
-
-template<typename TRAVELLER>
-class DestinationHolder
-{
- TimeTrackerSmall i_tracker;
- uint32 i_totalTravelTime;
- uint32 i_timeElapsed;
- bool i_destSet;
- float i_fromX, i_fromY, i_fromZ;
- float i_destX, i_destY, i_destZ;
-
- public:
- DestinationHolder() : i_tracker(TRAVELLER_UPDATE_INTERVAL), i_totalTravelTime(0), i_timeElapsed(0),
- i_destSet(false), i_fromX(0), i_fromY(0), i_fromZ(0), i_destX(0), i_destY(0), i_destZ(0) {}
-
- uint32 SetDestination(TRAVELLER &traveller, float dest_x, float dest_y, float dest_z, bool sendMove = true);
- void GetDestination(float &x, float &y, float &z) const { x = i_destX; y = i_destY; z = i_destZ; }
- bool UpdateExpired(void) const { return i_tracker.Passed(); }
- void ResetUpdate(uint32 t = TRAVELLER_UPDATE_INTERVAL) { i_tracker.Reset(t); }
- uint32 GetTotalTravelTime(void) const { return i_totalTravelTime; }
- void IncreaseTravelTime(uint32 increment) { i_totalTravelTime += increment; }
- void ResetTravelTime() { i_totalTravelTime = 0; }
- bool HasDestination(void) const { return i_destSet; }
- float GetDestinationDiff(float x, float y, float z) const;
- bool HasArrived(void) const { return (i_totalTravelTime == 0 || i_timeElapsed >= i_totalTravelTime); }
- bool UpdateTraveller(TRAVELLER &traveller, uint32 diff, bool micro_movement=false);
- uint32 StartTravel(TRAVELLER &traveller, bool sendMove = true);
- void GetLocationNow(const Map* map, float &x, float &y, float &z, bool is3D = false) const;
- void GetLocationNowNoMicroMovement(float &x, float &y, float &z) const; // For use without micro movement
- float GetDistance3dFromDestSq(const WorldObject &obj) const;
-
- private:
- void _findOffSetPoint(float x1, float y1, float x2, float y2, float offset, float &x, float &y);
-
-};
-#endif
-
diff --git a/src/server/game/Movement/DestinationHolderImp.h b/src/server/game/Movement/DestinationHolderImp.h
deleted file mode 100755
index 4d6e6f0c741..00000000000
--- a/src/server/game/Movement/DestinationHolderImp.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TRINITY_DESTINATIONHOLDERIMP_H
-#define TRINITY_DESTINATIONHOLDERIMP_H
-
-#include "MapManager.h"
-#include "DestinationHolder.h"
-
-#include <cmath>
-
-template<typename TRAVELLER>
-void
-DestinationHolder<TRAVELLER>::_findOffSetPoint(float x1, float y1, float x2, float y2, float offset, float &x, float &y)
-{
- /* given the point (x1, y1) and (x2, y2).. need to find the point (x, y) on the same line
- * such that the distance from (x, y) to (x2, y2) is offset.
- * Let the distance of p1 to p2 = d.. then the ratio of offset/d = (x2-x)/(x2-x1)
- * hence x = x2 - (offset/d)*(x2-x1)
- * like wise offset/d = (y2-y)/(y2-y1);
- */
- if (offset == 0)
- {
- x = x2;
- y = y2;
- }
- else
- {
- double x_diff = double(x2 - x1);
- double y_diff = double(y2 - y1);
- double distance_d = (double)((x_diff*x_diff) + (y_diff * y_diff));
- if (distance_d == 0)
- {
- x = x2;
- y = y2;
- }
- else
- {
- distance_d = ::sqrt(distance_d); // starting distance
- double distance_ratio = (double)(distance_d - offset)/(double)distance_d;
- // line above has revised formula which is more correct, I think
- x = (float)(x1 + (distance_ratio*x_diff));
- y = (float)(y1 + (distance_ratio*y_diff));
- }
- }
-}
-
-template<typename TRAVELLER>
-uint32
-DestinationHolder<TRAVELLER>::SetDestination(TRAVELLER &traveller, float dest_x, float dest_y, float dest_z, bool sendMove)
-{
- i_destSet = true;
- i_destX = dest_x;
- i_destY = dest_y;
- i_destZ = dest_z;
-
- return StartTravel(traveller, sendMove);
-}
-
-template<typename TRAVELLER>
-uint32
-DestinationHolder<TRAVELLER>::StartTravel(TRAVELLER &traveller, bool sendMove)
-{
- if (!i_destSet) return 0;
-
- i_fromX = traveller.GetPositionX();
- i_fromY = traveller.GetPositionY();
- i_fromZ = traveller.GetPositionZ();
-
- i_totalTravelTime = traveller.GetTotalTrevelTimeTo(i_destX, i_destY, i_destZ);
- i_timeElapsed = 0;
- if (sendMove)
- traveller.MoveTo(i_destX, i_destY, i_destZ, i_totalTravelTime);
- return i_totalTravelTime;
-}
-
-template<typename TRAVELLER>
-bool
-DestinationHolder<TRAVELLER>::UpdateTraveller(TRAVELLER &traveller, uint32 diff, bool micro_movement)
-{
- i_timeElapsed += diff;
-
- // Update every TRAVELLER_UPDATE_INTERVAL
- i_tracker.Update(diff);
- if (!i_tracker.Passed())
- return false;
- else
- ResetUpdate();
-
- if (!i_destSet) return true;
-
- float x, y, z;
- if (!micro_movement)
- GetLocationNowNoMicroMovement(x, y, z);
- else
- {
- if (!traveller.GetTraveller().HasUnitState(UNIT_STAT_MOVING | UNIT_STAT_IN_FLIGHT))
- return true;
-
- if (traveller.GetTraveller().HasUnitState(UNIT_STAT_IN_FLIGHT))
- GetLocationNow(traveller.GetTraveller().GetBaseMap(), x, y, z, true); // Should reposition Object with right Coord, so I can bypass some Grid Relocation
- else
- GetLocationNow(traveller.GetTraveller().GetBaseMap(), x, y, z, false);
-
- // Change movement computation to micro movement based on last tick coords, this makes system work
- // even on multiple floors zones without hugh vmaps usage ;)
-
- // Take care of underrun of uint32
- if (i_totalTravelTime >= i_timeElapsed)
- i_totalTravelTime -= i_timeElapsed; // Consider only the remaining part
- else
- i_totalTravelTime = 0;
-
- i_timeElapsed = 0;
- i_fromX = x; // and change origine
- i_fromY = y; // then I take into account only micro movement
- i_fromZ = z;
- }
-
- if (traveller.GetTraveller().GetPositionX() != x || traveller.GetTraveller().GetPositionY() != y || traveller.GetTraveller().GetPositionZ() != z)
- {
- float ori = traveller.GetTraveller().GetAngle(x, y);
- traveller.Relocation(x, y, z, ori);
- }
-
- return true;
-}
-
-template<typename TRAVELLER>
-void
-DestinationHolder<TRAVELLER>::GetLocationNow(const Map* map, float &x, float &y, float &z, bool is3D) const
-{
- if (HasArrived())
- {
- x = i_destX;
- y = i_destY;
- z = i_destZ;
- }
- else if (HasDestination())
- {
- double percent_passed = (double)i_timeElapsed / (double)i_totalTravelTime;
- const float distanceX = (float)((i_destX - i_fromX) * percent_passed);
- const float distanceY = (float)((i_destY - i_fromY) * percent_passed);
- const float distanceZ = (float)((i_destZ - i_fromZ) * percent_passed);
- x = i_fromX + distanceX;
- y = i_fromY + distanceY;
- float z2 = i_fromZ + distanceZ;
- // All that is not finished but previous code neither... Traveller need be able to swim.
- if (is3D)
- z = z2;
- else
- {
- //That part is good for mob Walking on the floor. But the floor is not always what we thought.
- z = map->GetHeight(x, y, i_fromZ, false); // Disable cave check
- const float groundDist = sqrt(distanceX*distanceX + distanceY*distanceY);
- const float zDist = fabs(i_fromZ - z) + 0.000001f;
- const float slope = groundDist / zDist;
- if (slope < 1.0f) // This prevents the ground returned by GetHeight to be used when in cave
- z = z2; // a climb or jump of more than 45 is denied
- }
- }
-}
-
-template<typename TRAVELLER>
-float
-DestinationHolder<TRAVELLER>::GetDistance3dFromDestSq(const WorldObject &obj) const
-{
- float x, y, z;
- obj.GetPosition(x, y, z);
- return (i_destX-x)*(i_destX-x)+(i_destY-y)*(i_destY-y)+(i_destZ-z)*(i_destZ-z);
-}
-
-template<typename TRAVELLER>
-float
-DestinationHolder<TRAVELLER>::GetDestinationDiff(float x, float y, float z) const
-{
- return sqrt(((x-i_destX)*(x-i_destX)) + ((y-i_destY)*(y-i_destY)) + ((z-i_destZ)*(z-i_destZ)));
-}
-
-template<typename TRAVELLER>
-void
-DestinationHolder<TRAVELLER>::GetLocationNowNoMicroMovement(float &x, float &y, float &z) const
-{
- if (HasArrived())
- {
- x = i_destX;
- y = i_destY;
- z = i_destZ;
- }
- else
- {
- double percent_passed = (double)i_timeElapsed / (double)i_totalTravelTime;
- x = (float)(i_fromX + ((i_destX - i_fromX) * percent_passed));
- y = (float)(i_fromY + ((i_destY - i_fromY) * percent_passed));
- z = (float)(i_fromZ + ((i_destZ - i_fromZ) * percent_passed));
- }
-}
-
-#endif
-
diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp
index 51725c118ce..8975a2d7d7b 100755
--- a/src/server/game/Movement/MotionMaster.cpp
+++ b/src/server/game/Movement/MotionMaster.cpp
@@ -19,7 +19,6 @@
#include "MotionMaster.h"
#include "CreatureAISelector.h"
#include "Creature.h"
-#include "Traveller.h"
#include "ConfusedMovementGenerator.h"
#include "FleeingMovementGenerator.h"
@@ -29,7 +28,8 @@
#include "TargetedMovementGenerator.h"
#include "WaypointMovementGenerator.h"
#include "RandomMovementGenerator.h"
-
+#include "MoveSpline.h"
+#include "MoveSplineInit.h"
#include <cassert>
inline bool isStatic(MovementGenerator *mv)
@@ -175,12 +175,11 @@ void MotionMaster::DelayedExpire()
--i_top;
}
-void MotionMaster::MoveIdle(MovementSlot slot)
+void MotionMaster::MoveIdle()
{
- //if (empty() || !isStatic(top()))
- // push(&si_idleMovement);
- if (!isStatic(Impl[slot]))
- Mutate(&si_idleMovement, slot);
+ //! Should be preceded by MovementExpired or Clear if there's an overlying movementgenerator active
+ if (empty() || !isStatic(top()))
+ Mutate(&si_idleMovement, MOTION_SLOT_IDLE);
}
void MotionMaster::MoveRandom(float spawndist)
@@ -194,16 +193,23 @@ void MotionMaster::MoveRandom(float spawndist)
void MotionMaster::MoveTargetedHome()
{
- //if (i_owner->HasUnitState(UNIT_STAT_FLEEING))
- // return;
-
Clear(false);
- if (i_owner->GetTypeId() == TYPEID_UNIT)
+ if (i_owner->GetTypeId()==TYPEID_UNIT && !((Creature*)i_owner)->GetCharmerOrOwnerGUID())
{
sLog->outStaticDebug("Creature (Entry: %u GUID: %u) targeted home", i_owner->GetEntry(), i_owner->GetGUIDLow());
Mutate(new HomeMovementGenerator<Creature>(), MOTION_SLOT_ACTIVE);
}
+ else if (i_owner->GetTypeId()==TYPEID_UNIT && ((Creature*)i_owner)->GetCharmerOrOwnerGUID())
+ {
+ sLog->outStaticDebug("Pet or controlled creature (Entry: %u GUID: %u) targeting home", i_owner->GetEntry(), i_owner->GetGUIDLow() );
+ Unit *target = ((Creature*)i_owner)->GetCharmerOrOwner();
+ if (target)
+ {
+ sLog->outStaticDebug("Following %s (GUID: %u)", target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : ((Creature*)target)->GetDBTableGUIDLow() );
+ Mutate(new FollowMovementGenerator<Creature>(*target,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE), MOTION_SLOT_ACTIVE);
+ }
+ }
else
{
sLog->outError("Player (GUID: %u) attempt targeted home", i_owner->GetGUIDLow());
@@ -231,14 +237,14 @@ void MotionMaster::MoveChase(Unit* target, float dist, float angle)
if (!target || target == i_owner || i_owner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE))
return;
- i_owner->ClearUnitState(UNIT_STAT_FOLLOW);
+ //i_owner->ClearUnitState(UNIT_STAT_FOLLOW);
if (i_owner->GetTypeId() == TYPEID_PLAYER)
{
sLog->outStaticDebug("Player (GUID: %u) chase to %s (GUID: %u)",
i_owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
- Mutate(new TargetedMovementGenerator<Player>(*target, dist, angle), MOTION_SLOT_ACTIVE);
+ Mutate(new ChaseMovementGenerator<Player>(*target,dist,angle), MOTION_SLOT_ACTIVE);
}
else
{
@@ -246,7 +252,7 @@ void MotionMaster::MoveChase(Unit* target, float dist, float angle)
i_owner->GetEntry(), i_owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
- Mutate(new TargetedMovementGenerator<Creature>(*target, dist, angle), MOTION_SLOT_ACTIVE);
+ Mutate(new ChaseMovementGenerator<Creature>(*target,dist,angle), MOTION_SLOT_ACTIVE);
}
}
@@ -256,13 +262,13 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlo
if (!target || target == i_owner || i_owner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE))
return;
- i_owner->AddUnitState(UNIT_STAT_FOLLOW);
+ //i_owner->AddUnitState(UNIT_STAT_FOLLOW);
if (i_owner->GetTypeId() == TYPEID_PLAYER)
{
sLog->outStaticDebug("Player (GUID: %u) follow to %s (GUID: %u)", i_owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
- Mutate(new TargetedMovementGenerator<Player>(*target, dist, angle), slot);
+ Mutate(new FollowMovementGenerator<Player>(*target,dist,angle), slot);
}
else
{
@@ -270,7 +276,7 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlo
i_owner->GetEntry(), i_owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
- Mutate(new TargetedMovementGenerator<Creature>(*target, dist, angle), slot);
+ Mutate(new FollowMovementGenerator<Creature>(*target,dist,angle), slot);
}
}
@@ -291,54 +297,32 @@ void MotionMaster::MovePoint(uint32 id, float x, float y, float z)
void MotionMaster::MoveLand(uint32 id, Position const& pos, float speed)
{
- if (i_owner->GetTypeId() != TYPEID_UNIT)
- return;
-
- uint32 moveFlag = SPLINEFLAG_FLYING | SPLINEFLAG_ANIMATIONTIER;
- uint32 moveTime = uint32(i_owner->GetExactDist(&pos) / speed) * IN_MILLISECONDS;
-
- // CHARGING state makes the unit use m_TempSpeed and JUMPING prevents sending movement packet in PointMovementGenerator
- i_owner->AddUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING);
- i_owner->m_TempSpeed = speed;
-
float x, y, z;
pos.GetPosition(x, y, z);
- sLog->outStaticDebug("Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", i_owner->GetEntry(), id, x, y, z);
- Mutate(new PointMovementGenerator<Creature>(id, x, y, z), MOTION_SLOT_ACTIVE);
- MonsterMoveData data;
- data.DestLocation.Relocate(pos);
- data.SplineFlag = moveFlag;
- data.Time = moveTime;
- data.AnimationState = ANIMATION_ON_GROUND;
+ sLog->outStaticDebug("Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", i_owner->GetEntry(), id, x, y, z);
- i_owner->SendMonsterMove(data);
+ Movement::MoveSplineInit init(*i_owner);
+ init.MoveTo(x,y,z);
+ init.SetVelocity(speed);
+ init.SetAnimation(Movement::ToGround);
+ init.Launch();
+ Mutate(new EffectMovementGenerator(id), MOTION_SLOT_ACTIVE);
}
void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, float speed)
{
- if (i_owner->GetTypeId() != TYPEID_UNIT)
- return;
-
- uint32 moveFlag = SPLINEFLAG_FLYING | SPLINEFLAG_ANIMATIONTIER;
- uint32 moveTime = uint32(i_owner->GetExactDist(&pos) / speed) * IN_MILLISECONDS;
-
- // CHARGING state makes the unit use m_TempSpeed and JUMPING prevents sending movement packet in PointMovementGenerator
- i_owner->AddUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING);
- i_owner->m_TempSpeed = speed;
-
float x, y, z;
pos.GetPosition(x, y, z);
- sLog->outStaticDebug("Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", i_owner->GetEntry(), id, x, y, z);
- Mutate(new PointMovementGenerator<Creature>(id, x, y, z), MOTION_SLOT_ACTIVE);
- MonsterMoveData data;
- data.DestLocation.Relocate(pos);
- data.SplineFlag = moveFlag;
- data.Time = moveTime;
- data.AnimationState = ANIMATION_FLYING;
+ sLog->outStaticDebug("Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", i_owner->GetEntry(), id, x, y, z);
- i_owner->SendMonsterMove(data);
+ Movement::MoveSplineInit init(*i_owner);
+ init.MoveTo(x,y,z);
+ init.SetVelocity(speed);
+ init.SetAnimation(Movement::ToFly);
+ init.Launch();
+ Mutate(new EffectMovementGenerator(id), MOTION_SLOT_ACTIVE);
}
void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ)
@@ -348,7 +332,9 @@ void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, floa
return;
float x, y, z;
- float dist = speedXY * speedZ * 0.1f;
+ float moveTimeHalf = speedZ / Movement::gravity;
+ float dist = 2 * moveTimeHalf * speedXY;
+
i_owner->GetNearPoint(i_owner, x, y, z, i_owner->GetObjectSize(), dist, i_owner->GetAngle(srcX, srcY) + M_PI);
MoveJump(x, y, z, speedXY, speedZ);
}
@@ -360,35 +346,51 @@ void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ)
return;
float x, y, z;
- float dist = speedXY * speedZ * 0.1f;
+
+ float moveTimeHalf = speedZ / Movement::gravity;
+ float dist = 2 * moveTimeHalf * speedXY;
i_owner->GetClosePoint(x, y, z, i_owner->GetObjectSize(), dist, angle);
MoveJump(x, y, z, speedXY, speedZ);
}
-void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float speedZ)
+void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id)
{
- uint32 moveFlag = SPLINEFLAG_TRAJECTORY | SPLINEFLAG_WALKING;
- uint32 time = uint32(speedZ * 100);
+ sLog->outStaticDebug("Unit (GUID: %u) jump to point (X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), x, y, z);
- // Instantly interrupt non melee spells being casted
- if (i_owner->IsNonMeleeSpellCasted(true))
- i_owner->InterruptNonMeleeSpells(true);
+ float moveTimeHalf = speedZ / Movement::gravity;
+ float max_height = -Movement::computeFallElevation(moveTimeHalf,false,-speedZ);
- i_owner->AddUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING);
- i_owner->m_TempSpeed = speedXY;
+ Movement::MoveSplineInit init(*i_owner);
+ init.MoveTo(x,y,z);
+ init.SetParabolic(max_height,0);
+ init.SetVelocity(speedXY);
+ init.Launch();
if (i_owner->GetTypeId() == TYPEID_PLAYER)
- {
- sLog->outStaticDebug("Player (GUID: %u) jump to point (X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), x, y, z);
- Mutate(new PointMovementGenerator<Player>(0, x, y, z), MOTION_SLOT_CONTROLLED);
- }
+ Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED);
else
+ Mutate(new EffectMovementGenerator(id), MOTION_SLOT_ACTIVE);
+}
+
+void MotionMaster::MoveFall(uint32 id/*=0*/)
+{
+ // use larger distance for vmap height search than in most other cases
+ float tz = i_owner->GetMap()->GetHeight(i_owner->GetPositionX(), i_owner->GetPositionY(), i_owner->GetPositionZ(), true, MAX_FALL_DISTANCE);
+ if (tz <= INVALID_HEIGHT)
{
- sLog->outStaticDebug("Creature (Entry: %u GUID: %u) jump to point (X: %f Y: %f Z: %f)",
- i_owner->GetEntry(), i_owner->GetGUIDLow(), x, y, z);
- Mutate(new PointMovementGenerator<Creature>(0, x, y, z), MOTION_SLOT_CONTROLLED);
+ sLog->outStaticDebug("MotionMaster::MoveFall: unable retrive a proper height at map %u (x: %f, y: %f, z: %f).",
+ i_owner->GetMap()->GetId(), i_owner->GetPositionX(), i_owner->GetPositionX(), i_owner->GetPositionZ());
+ return;
}
- i_owner->SendMonsterMove(x, y, z, moveFlag, time, speedZ);
+ // Abort too if the ground is very near
+ if (fabs(i_owner->GetPositionZ() - tz) < 0.1f)
+ return;
+
+ Movement::MoveSplineInit init(*i_owner);
+ init.MoveTo(i_owner->GetPositionX(),i_owner->GetPositionY(),tz);
+ init.SetFall();
+ init.Launch();
+ Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED);
}
void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id)
@@ -396,29 +398,19 @@ void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id)
if (Impl[MOTION_SLOT_CONTROLLED] && Impl[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE)
return;
- i_owner->AddUnitState(UNIT_STAT_CHARGING);
- i_owner->m_TempSpeed = speed;
if (i_owner->GetTypeId() == TYPEID_PLAYER)
{
sLog->outStaticDebug("Player (GUID: %u) charge point (X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), x, y, z);
- Mutate(new PointMovementGenerator<Player>(id, x, y, z), MOTION_SLOT_CONTROLLED);
+ Mutate(new PointMovementGenerator<Player>(id, x, y, z, speed), MOTION_SLOT_CONTROLLED);
}
else
{
sLog->outStaticDebug("Creature (Entry: %u GUID: %u) charge point (X: %f Y: %f Z: %f)",
i_owner->GetEntry(), i_owner->GetGUIDLow(), x, y, z);
- Mutate(new PointMovementGenerator<Creature>(id, x, y, z), MOTION_SLOT_CONTROLLED);
+ Mutate(new PointMovementGenerator<Creature>(id, x, y, z, speed), MOTION_SLOT_CONTROLLED);
}
}
-void MotionMaster::MoveFall(float z, uint32 id)
-{
- i_owner->SetFlying(false);
- i_owner->SendMovementFlagUpdate();
- //AddUnitMovementFlag(MOVEMENTFLAG_FALLING);
- MoveCharge(i_owner->GetPositionX(), i_owner->GetPositionY(), z, SPEED_CHARGE, id);
-}
-
void MotionMaster::MoveSeekAssistance(float x, float y, float z)
{
if (i_owner->GetTypeId() == TYPEID_PLAYER)
@@ -562,7 +554,7 @@ void MotionMaster::MovePath(uint32 path_id, bool repeatable)
//i_owner->GetTypeId() == TYPEID_PLAYER ?
//Mutate(new WaypointMovementGenerator<Player>(path_id, repeatable)):
- Mutate(new WaypointMovementGenerator<Creature>(path_id, repeatable), MOTION_SLOT_IDLE);
+ Mutate(new WaypointMovementGenerator<Creature>(path_id, repeatable), MOTION_SLOT_IDLE);
sLog->outStaticDebug("%s (GUID: %u) start moving over path(Id:%u, repeatable: %s)",
i_owner->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature",
@@ -633,8 +625,12 @@ void MotionMaster::DelayedDelete(_Ty curr)
bool MotionMaster::GetDestination(float &x, float &y, float &z)
{
- if (empty())
+ if (i_owner->movespline->Finalized())
return false;
- return top()->GetDestination(x, y, z);
+ const G3D::Vector3& dest = i_owner->movespline->FinalDestination();
+ x = dest.x;
+ y = dest.y;
+ z = dest.z;
+ return true;
}
diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h
index 64026ea7b80..a5bd0861b04 100755
--- a/src/server/game/Movement/MotionMaster.h
+++ b/src/server/game/Movement/MotionMaster.h
@@ -39,7 +39,7 @@ enum MovementGeneratorType
MAX_DB_MOTION_TYPE = 3, // *** this and below motion types can't be set in DB.
ANIMAL_RANDOM_MOTION_TYPE = MAX_DB_MOTION_TYPE, // AnimalRandomMovementGenerator.h
CONFUSED_MOTION_TYPE = 4, // ConfusedMovementGenerator.h
- TARGETED_MOTION_TYPE = 5, // TargetedMovementGenerator.h
+ CHASE_MOTION_TYPE = 5, // TargetedMovementGenerator.h
HOME_MOTION_TYPE = 6, // HomeMovementGenerator.h
FLIGHT_MOTION_TYPE = 7, // WaypointMovementGenerator.h
POINT_MOTION_TYPE = 8, // PointMovementGenerator.h
@@ -48,8 +48,10 @@ enum MovementGeneratorType
ASSISTANCE_MOTION_TYPE= 11, // PointMovementGenerator.h (first part of flee for assistance)
ASSISTANCE_DISTRACT_MOTION_TYPE = 12, // IdleMovementGenerator.h (second part of flee for assistance)
TIMED_FLEEING_MOTION_TYPE = 13, // FleeingMovementGenerator.h (alt.second part of flee for assistance)
- ROTATE_MOTION_TYPE = 14,
- NULL_MOTION_TYPE = 15,
+ FOLLOW_MOTION_TYPE = 14,
+ ROTATE_MOTION_TYPE = 15,
+ EFFECT_MOTION_TYPE = 16,
+ NULL_MOTION_TYPE = 17,
};
enum MovementSlot
@@ -86,7 +88,6 @@ class MotionMaster //: private std::stack<MovementGenerator *>
typedef std::vector<_Ty> ExpireList;
int i_top;
- bool empty() const { return (i_top < 0); }
void pop() { Impl[i_top] = NULL; --i_top; }
void push(_Ty _Val) { ++i_top; Impl[i_top] = _Val; }
@@ -107,6 +108,7 @@ class MotionMaster //: private std::stack<MovementGenerator *>
void Initialize();
void InitDefault();
+ bool empty() const { return (i_top < 0); }
int size() const { return i_top + 1; }
_Ty top() const { return Impl[i_top]; }
_Ty GetMotionSlot(int slot) const { return Impl[slot]; }
@@ -142,7 +144,7 @@ class MotionMaster //: private std::stack<MovementGenerator *>
DirectExpire(reset);
}
- void MoveIdle(MovementSlot slot = MOTION_SLOT_ACTIVE);
+ void MoveIdle();
void MoveTargetedHome();
void MoveRandom(float spawndist = 0.0f);
void MoveFollow(Unit* target, float dist, float angle, MovementSlot slot = MOTION_SLOT_ACTIVE);
@@ -158,10 +160,11 @@ class MotionMaster //: private std::stack<MovementGenerator *>
void MoveTakeoff(uint32 id, Position const& pos, float speed);
void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE);
- void MoveFall(float z, uint32 id = 0);
void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ);
void MoveJumpTo(float angle, float speedXY, float speedZ);
- void MoveJump(float x, float y, float z, float speedXY, float speedZ);
+ void MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id = 0);
+ void MoveFall(uint32 id = 0);
+
void MoveSeekAssistance(float x, float y, float z);
void MoveSeekAssistanceDistract(uint32 timer);
void MoveTaxiFlight(uint32 path, uint32 pathnode);
diff --git a/src/server/game/Movement/MovementGenerator.cpp b/src/server/game/Movement/MovementGenerator.cpp
index 103b8876959..73921ea86ff 100755
--- a/src/server/game/Movement/MovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerator.cpp
@@ -21,4 +21,3 @@
MovementGenerator::~MovementGenerator()
{
}
-
diff --git a/src/server/game/Movement/MovementGenerator.h b/src/server/game/Movement/MovementGenerator.h
index 06450d938ae..dd9ba32f337 100755
--- a/src/server/game/Movement/MovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerator.h
@@ -43,8 +43,6 @@ class MovementGenerator
virtual MovementGeneratorType GetMovementGeneratorType() = 0;
virtual void unitSpeedChanged() { }
-
- virtual bool GetDestination(float& /*x*/, float& /*y*/, float& /*z*/) const { return false; }
};
template<class T, class D>
diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
index bf5c8bafc49..94608d85420 100755
--- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
@@ -18,10 +18,11 @@
#include "Creature.h"
#include "MapManager.h"
-#include "Opcodes.h"
#include "ConfusedMovementGenerator.h"
-#include "DestinationHolderImp.h"
#include "VMapFactory.h"
+#include "MoveSplineInit.h"
+#include "MoveSpline.h"
+#include "Player.h"
#ifdef MAP_BASED_RAND_GEN
#define rand_norm() unit.rand_norm()
@@ -31,8 +32,8 @@
template<class T>
void ConfusedMovementGenerator<T>::Initialize(T &unit)
{
- float const wanderDistance = 4;
- float x, y, z;
+ const float wander_distance=4;
+ float x,y,z;
x = unit.GetPositionX();
y = unit.GetPositionY();
z = unit.GetPositionZ();
@@ -44,52 +45,33 @@ void ConfusedMovementGenerator<T>::Initialize(T &unit)
bool is_water_ok, is_land_ok;
_InitSpecific(unit, is_water_ok, is_land_ok);
- for (uint8 idx = 0; idx <= MAX_CONF_WAYPOINTS; ++idx)
+ for (uint8 idx = 0; idx < MAX_CONF_WAYPOINTS + 1; ++idx)
{
- float wanderX = x + wanderDistance * (float)rand_norm() - wanderDistance/2;
- float wanderY = y + wanderDistance * (float)rand_norm() - wanderDistance/2;
- Trinity::NormalizeMapCoord(wanderX);
- Trinity::NormalizeMapCoord(wanderY);
+ const float wanderX=wander_distance*(float)rand_norm() - wander_distance/2;
+ const float wanderY=wander_distance*(float)rand_norm() - wander_distance/2;
- float new_z = map->GetHeight(wanderX, wanderY, z, true);
- if (new_z > INVALID_HEIGHT && unit.IsWithinLOS(wanderX, wanderY, new_z))
- {
- // Don't move in water if we're not already in
- // Don't move on land if we're not already on it either
- bool is_water_now = map->IsInWater(x, y, z);
- bool is_water_next = map->IsInWater(wanderX, wanderY, new_z);
- if ((is_water_now && !is_water_next && !is_land_ok) || (!is_water_now && is_water_next && !is_water_ok))
- {
- i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x; // Back to previous location
- i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y;
- i_waypoints[idx][2] = idx > 0 ? i_waypoints[idx-1][2] : z;
- continue;
- }
-
- // Taken from FleeingMovementGenerator
- if (!(new_z - z) || wanderDistance / fabs(new_z - z) > 1.0f)
- {
- i_waypoints[idx][0] = wanderX;
- i_waypoints[idx][1] = wanderY;
- i_waypoints[idx][2] = new_z;
- continue;
- }
- }
- else // Back to previous location
+ i_waypoints[idx][0] = x + wanderX;
+ i_waypoints[idx][1] = y + wanderY;
+
+ // prevent invalid coordinates generation
+ Trinity::NormalizeMapCoord(i_waypoints[idx][0]);
+ Trinity::NormalizeMapCoord(i_waypoints[idx][1]);
+
+ bool is_water = map->IsInWater(i_waypoints[idx][0],i_waypoints[idx][1],z);
+ // if generated wrong path just ignore
+ if ((is_water && !is_water_ok) || (!is_water && !is_land_ok))
{
i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x;
i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y;
- i_waypoints[idx][2] = idx > 0 ? i_waypoints[idx-1][2] : z;
- continue;
}
+
+ unit.UpdateAllowedPositionZ(i_waypoints[idx][0], i_waypoints[idx][1], z);
+ i_waypoints[idx][2] = z;
}
- unit.SetTarget(0);
- unit.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
- unit.CastStop();
unit.StopMoving();
- unit.AddUnitMovementFlag(MOVEMENTFLAG_WALKING); // Should actually be splineflag
- unit.AddUnitState(UNIT_STAT_CONFUSED);
+ unit.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
+ unit.AddUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
}
template<>
@@ -111,69 +93,70 @@ void ConfusedMovementGenerator<T>::Reset(T &unit)
{
i_nextMove = 1;
i_nextMoveTime.Reset(0);
- i_destinationHolder.ResetUpdate();
unit.StopMoving();
+ unit.AddUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
}
template<class T>
-bool ConfusedMovementGenerator<T>::Update(T &unit, const uint32 diff)
+bool ConfusedMovementGenerator<T>::Update(T &unit, const uint32 &diff)
{
- if (!&unit)
- return true;
-
if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
return true;
if (i_nextMoveTime.Passed())
{
// currently moving, update location
- Traveller<T> traveller(unit);
- if (i_destinationHolder.UpdateTraveller(traveller, diff))
+ unit.AddUnitState(UNIT_STAT_CONFUSED_MOVE);
+
+ if (unit.movespline->Finalized())
{
- if (i_destinationHolder.HasArrived())
- {
- // arrived, stop and wait a bit
- unit.ClearUnitState(UNIT_STAT_MOVE);
-
- i_nextMove = urand(1, MAX_CONF_WAYPOINTS);
- i_nextMoveTime.Reset(urand(100, 1000));
- }
+ i_nextMove = urand(1,MAX_CONF_WAYPOINTS);
+ i_nextMoveTime.Reset(urand(0, 1500-1)); // TODO: check the minimum reset time, should be probably higher
}
}
else
{
// waiting for next move
i_nextMoveTime.Update(diff);
- if (i_nextMoveTime.Passed())
+ if(i_nextMoveTime.Passed() )
{
// start moving
- ASSERT(i_nextMove <= MAX_CONF_WAYPOINTS);
- const float x = i_waypoints[i_nextMove][0];
- const float y = i_waypoints[i_nextMove][1];
- const float z = i_waypoints[i_nextMove][2];
- Traveller<T> traveller(unit);
- i_destinationHolder.SetDestination(traveller, x, y, z);
+ unit.AddUnitState(UNIT_STAT_CONFUSED_MOVE);
+
+ ASSERT( i_nextMove <= MAX_CONF_WAYPOINTS );
+ float x = i_waypoints[i_nextMove][0];
+ float y = i_waypoints[i_nextMove][1];
+ float z = i_waypoints[i_nextMove][2];
+ Movement::MoveSplineInit init(unit);
+ init.MoveTo(x, y, z);
+ init.SetWalk(true);
+ init.Launch();
}
}
+
return true;
}
-template<class T>
-void ConfusedMovementGenerator<T>::Finalize(T &unit)
+template<>
+void ConfusedMovementGenerator<Player>::Finalize(Player &unit)
{
unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
- unit.ClearUnitState(UNIT_STAT_CONFUSED);
+ unit.ClearUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
+}
- if (unit.GetTypeId() == TYPEID_UNIT && unit.getVictim())
+template<>
+void ConfusedMovementGenerator<Creature>::Finalize(Creature &unit)
+{
+ unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
+ unit.ClearUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
+ if (unit.getVictim())
unit.SetTarget(unit.getVictim()->GetGUID());
}
template void ConfusedMovementGenerator<Player>::Initialize(Player &player);
template void ConfusedMovementGenerator<Creature>::Initialize(Creature &creature);
-template void ConfusedMovementGenerator<Player>::Finalize(Player &player);
-template void ConfusedMovementGenerator<Creature>::Finalize(Creature &creature);
template void ConfusedMovementGenerator<Player>::Reset(Player &player);
template void ConfusedMovementGenerator<Creature>::Reset(Creature &creature);
-template bool ConfusedMovementGenerator<Player>::Update(Player &player, const uint32 diff);
-template bool ConfusedMovementGenerator<Creature>::Update(Creature &creature, const uint32 diff);
+template bool ConfusedMovementGenerator<Player>::Update(Player &player, const uint32 &diff);
+template bool ConfusedMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff);
diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h
index d3981ee2dcf..b9f96bb785d 100755
--- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h
@@ -20,8 +20,7 @@
#define TRINITY_CONFUSEDGENERATOR_H
#include "MovementGenerator.h"
-#include "DestinationHolder.h"
-#include "Traveller.h"
+#include "Timer.h"
#define MAX_CONF_WAYPOINTS 24
@@ -35,21 +34,13 @@ class ConfusedMovementGenerator
void Initialize(T &);
void Finalize(T &);
void Reset(T &);
- bool Update(T &, const uint32);
-
- bool GetDestination(float &x, float &y, float &z) const
- {
- if (i_destinationHolder.HasArrived()) return false;
- i_destinationHolder.GetDestination(x, y, z);
- return true;
- }
+ bool Update(T &, const uint32 &);
MovementGeneratorType GetMovementGeneratorType() { return CONFUSED_MOTION_TYPE; }
private:
void _InitSpecific(T &, bool &, bool &);
TimeTracker i_nextMoveTime;
float i_waypoints[MAX_CONF_WAYPOINTS+1][3];
- DestinationHolder< Traveller<T> > i_destinationHolder;
uint32 i_nextMove;
};
#endif
diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
index d2b3fcee384..458e6f9a62c 100755
--- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
@@ -20,8 +20,9 @@
#include "CreatureAI.h"
#include "MapManager.h"
#include "FleeingMovementGenerator.h"
-#include "DestinationHolderImp.h"
#include "ObjectAccessor.h"
+#include "MoveSplineInit.h"
+#include "MoveSpline.h"
#define MIN_QUIET_DISTANCE 28.0f
#define MAX_QUIET_DISTANCE 43.0f
@@ -43,25 +44,12 @@ FleeingMovementGenerator<T>::_setTargetLocation(T &owner)
if (!_getPoint(owner, x, y, z))
return;
- owner.AddUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING);
- Traveller<T> traveller(owner);
- i_destinationHolder.SetDestination(traveller, x, y, z);
-}
-
-template<>
-bool FleeingMovementGenerator<Creature>::GetDestination(float &x, float &y, float &z) const
-{
- if (i_destinationHolder.HasArrived())
- return false;
+ owner.AddUnitState(UNIT_STAT_FLEEING_MOVE);
- i_destinationHolder.GetDestination(x, y, z);
- return true;
-}
-
-template<>
-bool FleeingMovementGenerator<Player>::GetDestination(float & /*x*/, float & /*y*/, float & /*z*/) const
-{
- return false;
+ Movement::MoveSplineInit init(owner);
+ init.MoveTo(x,y,z);
+ init.SetWalk(false);
+ init.Launch();
}
template<class T>
@@ -75,10 +63,10 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
y = owner.GetPositionY();
z = owner.GetPositionZ();
- float temp_x, temp_y, angle = 0;
+ float temp_x, temp_y, angle;
const Map* _map = owner.GetBaseMap();
//primitive path-finding
- for (uint8 i = 0; i < 18; ++i)
+ for(uint8 i = 0; i < 18; ++i)
{
if (i_only_forward && i > 2)
break;
@@ -143,11 +131,11 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
distance /= 4;
break;
case 15:
- angle = i_cur_angle + static_cast<float>(M_PI*3/4);
+ angle = i_cur_angle + static_cast<float>(3*M_PI/4);
distance /= 2;
break;
case 16:
- angle = i_cur_angle - static_cast<float>(M_PI*3/4);
+ angle = i_cur_angle - static_cast<float>(3*M_PI/4);
distance /= 2;
break;
case 17:
@@ -161,9 +149,9 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
Trinity::NormalizeMapCoord(temp_y);
if (owner.IsWithinLOS(temp_x, temp_y, z))
{
- bool is_water_now = _map->IsInWater(x, y, z);
+ bool is_water_now = _map->IsInWater(x,y,z);
- if (is_water_now && _map->IsInWater(temp_x, temp_y, z))
+ if (is_water_now && _map->IsInWater(temp_x,temp_y,z))
{
x = temp_x;
y = temp_y;
@@ -181,8 +169,8 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
if (!(new_z - z) || distance / fabs(new_z - z) > 1.0f)
{
- float new_z_left = _map->GetHeight(temp_x + (float)(cos(angle+M_PI/2)), temp_y + (float)(sin(angle+M_PI/2)), z, true);
- float new_z_right = _map->GetHeight(temp_x + (float)(cos(angle-M_PI/2)), temp_y + (float)(sin(angle-M_PI/2)), z, true);
+ float new_z_left = _map->GetHeight(temp_x + 1.0f*cos(angle+static_cast<float>(M_PI/2)),temp_y + 1.0f*sin(angle+static_cast<float>(M_PI/2)),z,true);
+ float new_z_right = _map->GetHeight(temp_x + 1.0f*cos(angle-static_cast<float>(M_PI/2)),temp_y + 1.0f*sin(angle-static_cast<float>(M_PI/2)),z,true);
if (fabs(new_z_left - new_z) < 1.2f && fabs(new_z_right - new_z) < 1.2f)
{
x = temp_x;
@@ -194,7 +182,7 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
}
}
i_to_distance_from_caster = 0.0f;
- i_nextCheckTime.Reset(urand(500, 1000));
+ i_nextCheckTime.Reset( urand(500,1000) );
return false;
}
@@ -213,12 +201,12 @@ FleeingMovementGenerator<T>::_setMoveData(T &owner)
(i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster) ||
// if we reach bigger distance
(cur_dist_xyz > MAX_QUIET_DISTANCE) || // if we are too far
- (i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE))
+ (i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE) )
// if we leave 'quiet zone'
{
// we are very far or too close, stopping
i_to_distance_from_caster = 0.0f;
- i_nextCheckTime.Reset(urand(500, 1000));
+ i_nextCheckTime.Reset( urand(500,1000) );
return false;
}
else
@@ -232,9 +220,7 @@ FleeingMovementGenerator<T>::_setMoveData(T &owner)
float cur_dist;
float angle_to_caster;
- Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID);
-
- if (fright)
+ if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
{
cur_dist = fright->GetDistance(&owner);
if (cur_dist < cur_dist_xyz)
@@ -284,7 +270,7 @@ FleeingMovementGenerator<T>::_setMoveData(T &owner)
i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + (float)rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
}
- int8 sign = rand_norm() > 0.5f ? 1 : -1;
+ int8 sign = (float)rand_norm() > 0.5f ? 1 : -1;
i_cur_angle = sign*angle + angle_to_caster;
// current distance
@@ -300,14 +286,12 @@ FleeingMovementGenerator<T>::Initialize(T &owner)
if (!&owner)
return;
- _Init(owner);
- owner.CastStop();
- owner.AddUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING);
owner.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
- owner.SetTarget(0);
- owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
+ owner.AddUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
- if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
+ _Init(owner);
+
+ if (Unit *fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
{
i_caster_x = fright->GetPositionX();
i_caster_y = fright->GetPositionY();
@@ -334,6 +318,7 @@ FleeingMovementGenerator<Creature>::_Init(Creature &owner)
if (!&owner)
return;
+ //owner.SetTargetGuid(ObjectGuid());
is_water_ok = owner.canSwim();
is_land_ok = owner.canWalk();
}
@@ -346,51 +331,44 @@ FleeingMovementGenerator<Player>::_Init(Player &)
is_land_ok = true;
}
-template<class T>
-void
-FleeingMovementGenerator<T>::Finalize(T &owner)
+template<>
+void FleeingMovementGenerator<Player>::Finalize(Player &owner)
+{
+ owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
+ owner.ClearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
+}
+
+template<>
+void FleeingMovementGenerator<Creature>::Finalize(Creature &owner)
{
owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
- owner.ClearUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING);
- if (owner.GetTypeId() == TYPEID_UNIT && owner.getVictim())
+ owner.ClearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
+ if (owner.getVictim())
owner.SetTarget(owner.getVictim()->GetGUID());
}
template<class T>
-void
-FleeingMovementGenerator<T>::Reset(T &owner)
+void FleeingMovementGenerator<T>::Reset(T &owner)
{
Initialize(owner);
}
template<class T>
bool
-FleeingMovementGenerator<T>::Update(T &owner, const uint32 time_diff)
+FleeingMovementGenerator<T>::Update(T &owner, const uint32 &time_diff)
{
if (!&owner || !owner.isAlive())
return false;
if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED))
+ {
+ owner.ClearUnitState(UNIT_STAT_FLEEING_MOVE);
return true;
-
- Traveller<T> traveller(owner);
+ }
i_nextCheckTime.Update(time_diff);
-
- if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || !i_destinationHolder.HasDestination())
- {
+ if (i_nextCheckTime.Passed() && owner.movespline->Finalized())
_setTargetLocation(owner);
- return true;
- }
- if (i_destinationHolder.UpdateTraveller(traveller, time_diff))
- {
- i_destinationHolder.ResetUpdate(50);
- if (i_nextCheckTime.Passed() && i_destinationHolder.HasArrived())
- {
- _setTargetLocation(owner);
- return true;
- }
- }
return true;
}
@@ -402,17 +380,15 @@ template bool FleeingMovementGenerator<Player>::_getPoint(Player &, float &, flo
template bool FleeingMovementGenerator<Creature>::_getPoint(Creature &, float &, float &, float &);
template void FleeingMovementGenerator<Player>::_setTargetLocation(Player &);
template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature &);
-template void FleeingMovementGenerator<Player>::Finalize(Player &);
-template void FleeingMovementGenerator<Creature>::Finalize(Creature &);
template void FleeingMovementGenerator<Player>::Reset(Player &);
template void FleeingMovementGenerator<Creature>::Reset(Creature &);
-template bool FleeingMovementGenerator<Player>::Update(Player &, const uint32);
-template bool FleeingMovementGenerator<Creature>::Update(Creature &, const uint32);
+template bool FleeingMovementGenerator<Player>::Update(Player &, const uint32 &);
+template bool FleeingMovementGenerator<Creature>::Update(Creature &, const uint32 &);
void TimedFleeingMovementGenerator::Finalize(Unit &owner)
{
owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
- owner.ClearUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING);
+ owner.ClearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
if (Unit* victim = owner.getVictim())
{
if (owner.isAlive())
@@ -429,13 +405,20 @@ bool TimedFleeingMovementGenerator::Update(Unit & owner, const uint32 time_diff)
return false;
if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED))
+ {
+ owner.ClearUnitState(UNIT_STAT_FLEEING_MOVE);
return true;
+ }
+
+ i_totalFleeTime.Update(time_diff);
+ if (i_totalFleeTime.Passed())
+ return false;
i_totalFleeTime.Update(time_diff);
if (i_totalFleeTime.Passed())
return false;
- // This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, const uint32) version
+ // This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, const 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 4d4631fe932..750db52bb5a 100755
--- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h
@@ -20,8 +20,6 @@
#define TRINITY_FLEEINGMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
-#include "DestinationHolder.h"
-#include "Traveller.h"
template<class T>
class FleeingMovementGenerator
@@ -33,8 +31,7 @@ class FleeingMovementGenerator
void Initialize(T &);
void Finalize(T &);
void Reset(T &);
- bool Update(T &, const uint32);
- bool GetDestination(float &x, float &y, float &z) const;
+ bool Update(T &, const uint32 &);
MovementGeneratorType GetMovementGeneratorType() { return FLEEING_MOTION_TYPE; }
@@ -56,8 +53,6 @@ class FleeingMovementGenerator
float i_cur_angle;
uint64 i_frightGUID;
TimeTracker i_nextCheckTime;
-
- DestinationHolder< Traveller<T> > i_destinationHolder;
};
class TimedFleeingMovementGenerator
diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
index 16153dd6ccb..84997d6d1ae 100755
--- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
@@ -19,22 +19,16 @@
#include "HomeMovementGenerator.h"
#include "Creature.h"
#include "CreatureAI.h"
-#include "Traveller.h"
-#include "DestinationHolderImp.h"
#include "WorldPacket.h"
+#include "MoveSplineInit.h"
+#include "MoveSpline.h"
void HomeMovementGenerator<Creature>::Initialize(Creature & owner)
{
- owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
owner.AddUnitState(UNIT_STAT_EVADE);
_setTargetLocation(owner);
}
-void HomeMovementGenerator<Creature>::Finalize(Creature & owner)
-{
- owner.ClearUnitState(UNIT_STAT_EVADE);
-}
-
void HomeMovementGenerator<Creature>::Reset(Creature &)
{
}
@@ -47,42 +41,35 @@ void HomeMovementGenerator<Creature>::_setTargetLocation(Creature & owner)
if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
return;
- float x, y, z;
- owner.GetHomePosition(x, y, z, ori);
+ Movement::MoveSplineInit init(owner);
+ float x, y, z, o;
+ // at apply we can select more nice return points base at current movegen
+ //if (owner.GetMotionMaster()->empty() || !owner.GetMotionMaster()->top()->GetResetPosition(owner,x,y,z))
+ //{
+ owner.GetHomePosition(x, y, z, o);
+ init.SetFacing(o);
+ //}
+ init.MoveTo(x,y,z);
+ init.SetWalk(false);
+ init.Launch();
- CreatureTraveller traveller(owner);
-
- uint32 travel_time = i_destinationHolder.SetDestination(traveller, x, y, z);
- modifyTravelTime(travel_time);
- owner.ClearUnitState(uint32(UNIT_STAT_ALL_STATE & ~UNIT_STAT_EVADE));
+ arrived = false;
+ owner.ClearUnitState(UNIT_STAT_ALL_STATE & ~UNIT_STAT_EVADE);
}
bool HomeMovementGenerator<Creature>::Update(Creature &owner, const uint32 time_diff)
{
- CreatureTraveller traveller(owner);
- i_destinationHolder.UpdateTraveller(traveller, time_diff);
+ arrived = owner.movespline->Finalized();
+ return !arrived;
+}
- if (time_diff > i_travel_timer)
+void HomeMovementGenerator<Creature>::Finalize(Creature& owner)
+{
+ if (arrived)
{
- owner.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
-
- // restore orientation of not moving creature at returning to home
- if (owner.GetDefaultMovementType() == IDLE_MOTION_TYPE)
- {
- //sLog->outDebug("Entering HomeMovement::GetDestination(z, y, z)");
- owner.SetOrientation(ori);
- WorldPacket packet;
- owner.BuildHeartBeatMsg(&packet);
- owner.SendMessageToSet(&packet, false);
- }
-
owner.ClearUnitState(UNIT_STAT_EVADE);
+ owner.SetWalk(true);
owner.LoadCreaturesAddon(true);
owner.AI()->JustReachedHome();
- return false;
}
-
- i_travel_timer -= time_diff;
-
- return true;
}
diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h
index ba34899dee5..c724edc91ff 100755
--- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h
@@ -20,8 +20,6 @@
#define TRINITY_HOMEMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
-#include "DestinationHolder.h"
-#include "Traveller.h"
class Creature;
@@ -34,24 +32,18 @@ class HomeMovementGenerator<Creature>
{
public:
- HomeMovementGenerator() {}
+ HomeMovementGenerator() : arrived(false) {}
~HomeMovementGenerator() {}
void Initialize(Creature &);
void Finalize(Creature &);
void Reset(Creature &);
bool Update(Creature &, const uint32);
- void modifyTravelTime(uint32 travel_time) { i_travel_timer = travel_time; }
MovementGeneratorType GetMovementGeneratorType() { return HOME_MOTION_TYPE; }
- bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x, y, z); return true; }
-
private:
void _setTargetLocation(Creature &);
- DestinationHolder< Traveller<Creature> > i_destinationHolder;
-
- float ori;
- uint32 i_travel_timer;
+ bool arrived;
};
#endif
diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp
index af2207ae141..88465017dc2 100755
--- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp
@@ -20,84 +20,84 @@
#include "Errors.h"
#include "Creature.h"
#include "CreatureAI.h"
-#include "DestinationHolderImp.h"
#include "World.h"
+#include "MoveSplineInit.h"
+#include "MoveSpline.h"
+#include "Player.h"
//----- Point Movement Generator
template<class T>
void PointMovementGenerator<T>::Initialize(T &unit)
{
- unit.StopMoving();
- Traveller<T> traveller(unit);
- // OLD: knockback effect has UNIT_STAT_JUMPING set, so if here we disable sentmonstermove there will be creature position sync problem between client and server
- // NEW: reactivated this check - UNIT_STAT_JUMPING is only used in MoveJump, which sends its own packet
- i_destinationHolder.SetDestination(traveller, i_x, i_y, i_z, /*true*/ !unit.HasUnitState(UNIT_STAT_JUMPING));
+ if (!unit.IsStopped())
+ unit.StopMoving();
+
+ unit.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
+ Movement::MoveSplineInit init(unit);
+ init.MoveTo(i_x, i_y, i_z);
+ if (speed > 0.0f)
+ init.SetVelocity(speed);
+ init.Launch();
}
template<class T>
-bool PointMovementGenerator<T>::Update(T &unit, const uint32 diff)
+bool PointMovementGenerator<T>::Update(T &unit, const uint32 &diff)
{
if (!&unit)
return false;
- if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED))
+ if(unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED))
{
- if (unit.HasUnitState(UNIT_STAT_CHARGING))
- return false;
- else
- return true;
+ unit.ClearUnitState(UNIT_STAT_ROAMING_MOVE);
+ return true;
}
- Traveller<T> traveller(unit);
-
- i_destinationHolder.UpdateTraveller(traveller, diff);
-
- if (i_destinationHolder.HasArrived())
- {
- unit.ClearUnitState(UNIT_STAT_MOVE);
- arrived = true;
- return false;
- }
- else if (!unit.HasUnitState(UNIT_STAT_MOVE) && !unit.HasUnitState(UNIT_STAT_JUMPING))
- {
- i_destinationHolder.StartTravel(traveller);
- }
-
- return true;
+ unit.AddUnitState(UNIT_STAT_ROAMING_MOVE);
+ return !unit.movespline->Finalized();
}
template<class T>
void PointMovementGenerator<T>:: Finalize(T &unit)
{
- if (unit.HasUnitState(UNIT_STAT_CHARGING))
- unit.ClearUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING);
- if (arrived) // without this crash!
+ unit.ClearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
+
+ if (unit.movespline->Finalized())
MovementInform(unit);
}
template<class T>
+void PointMovementGenerator<T>::Reset(T &unit)
+{
+ if (!unit.IsStopped())
+ unit.StopMoving();
+
+ unit.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
+}
+
+template<class T>
void PointMovementGenerator<T>::MovementInform(T & /*unit*/)
{
}
template <> void PointMovementGenerator<Creature>::MovementInform(Creature &unit)
{
- if (id == EVENT_FALL_GROUND)
- {
- unit.setDeathState(JUST_DIED);
- unit.SetFlying(true);
- }
- unit.AI()->MovementInform(POINT_MOTION_TYPE, id);
+ //if (id == EVENT_FALL_GROUND)
+ //{
+ // unit.setDeathState(JUST_DIED);
+ // unit.SetFlying(true);
+ //}
+ if (unit.AI())
+ unit.AI()->MovementInform(POINT_MOTION_TYPE, id);
}
template void PointMovementGenerator<Player>::Initialize(Player&);
-template bool PointMovementGenerator<Player>::Update(Player &, const uint32 diff);
-template void PointMovementGenerator<Player>::MovementInform(Player&);
-template void PointMovementGenerator<Player>::Finalize(Player&);
-
template void PointMovementGenerator<Creature>::Initialize(Creature&);
-template bool PointMovementGenerator<Creature>::Update(Creature&, const uint32 diff);
+template void PointMovementGenerator<Player>::Finalize(Player&);
template void PointMovementGenerator<Creature>::Finalize(Creature&);
+template void PointMovementGenerator<Player>::Reset(Player&);
+template void PointMovementGenerator<Creature>::Reset(Creature&);
+template bool PointMovementGenerator<Player>::Update(Player &, const uint32 &);
+template bool PointMovementGenerator<Creature>::Update(Creature&, const uint32 &);
void AssistanceMovementGenerator::Finalize(Unit &unit)
{
@@ -107,3 +107,24 @@ void AssistanceMovementGenerator::Finalize(Unit &unit)
unit.GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY));
}
+bool EffectMovementGenerator::Update(Unit &unit, const uint32)
+{
+ return !unit.movespline->Finalized();
+}
+
+void EffectMovementGenerator::Finalize(Unit &unit)
+{
+ if (unit.GetTypeId() != TYPEID_UNIT)
+ return;
+
+ if (((Creature&)unit).AI() && unit.movespline->Finalized())
+ ((Creature&)unit).AI()->MovementInform(EFFECT_MOTION_TYPE, m_Id);
+ // Need restore previous movement since we have no proper states system
+ //if (unit.isAlive() && !unit.HasUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_FLEEING))
+ //{
+ // if (Unit * victim = unit.getVictim())
+ // unit.GetMotionMaster()->MoveChase(victim);
+ // else
+ // unit.GetMotionMaster()->Initialize();
+ //}
+}
diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h
index 2504f1a38e3..e47f3d93450 100755
--- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h
@@ -20,8 +20,6 @@
#define TRINITY_POINTMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
-#include "DestinationHolder.h"
-#include "Traveller.h"
#include "FollowerReference.h"
template<class T>
@@ -29,13 +27,13 @@ class PointMovementGenerator
: public MovementGeneratorMedium< T, PointMovementGenerator<T> >
{
public:
- PointMovementGenerator(uint32 _id, float _x, float _y, float _z) : id(_id),
- i_x(_x), i_y(_y), i_z(_z), i_nextMoveTime(0), arrived(false) {}
+ PointMovementGenerator(uint32 _id, float _x, float _y, float _z, float _speed = 0.0f) : id(_id),
+ i_x(_x), i_y(_y), i_z(_z), speed(_speed) {}
void Initialize(T &);
- void Finalize(T &unit);
- void Reset(T &unit){unit.StopMoving();}
- bool Update(T &, const uint32 diff);
+ void Finalize(T &);
+ void Reset(T &);
+ bool Update(T &, const uint32 &);
void MovementInform(T &);
@@ -45,9 +43,7 @@ class PointMovementGenerator
private:
uint32 id;
float i_x, i_y, i_z;
- TimeTracker i_nextMoveTime;
- DestinationHolder< Traveller<T> > i_destinationHolder;
- bool arrived;
+ float speed;
};
class AssistanceMovementGenerator
@@ -61,5 +57,19 @@ class AssistanceMovementGenerator
void Finalize(Unit &);
};
+// Does almost nothing - just doesn't allows previous movegen interrupt current effect.
+class EffectMovementGenerator : public MovementGenerator
+{
+ public:
+ explicit EffectMovementGenerator(uint32 Id) : m_Id(Id) {}
+ void Initialize(Unit &) {}
+ void Finalize(Unit &unit);
+ void Reset(Unit &) {}
+ bool Update(Unit &u, const uint32);
+ MovementGeneratorType GetMovementGeneratorType() { return EFFECT_MOTION_TYPE; }
+ private:
+ uint32 m_Id;
+};
+
#endif
diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
index 981ec031cf9..0205b734058 100755
--- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
@@ -19,123 +19,103 @@
#include "Creature.h"
#include "MapManager.h"
#include "RandomMovementGenerator.h"
-#include "Traveller.h"
#include "ObjectAccessor.h"
-#include "DestinationHolderImp.h"
#include "Map.h"
#include "Util.h"
#include "CreatureGroups.h"
+#include "MoveSplineInit.h"
+#include "MoveSpline.h"
#define RUNNING_CHANCE_RANDOMMV 20 //will be "1 / RUNNING_CHANCE_RANDOMMV"
-template<>
-bool
-RandomMovementGenerator<Creature>::GetDestination(float &x, float &y, float &z) const
-{
- if (i_destinationHolder.HasArrived())
- return false;
-
- i_destinationHolder.GetDestination(x, y, z);
- return true;
-}
-
#ifdef MAP_BASED_RAND_GEN
#define rand_norm() creature.rand_norm()
#endif
template<>
-void
-RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
+void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
- float X, Y, Z, nx, ny, nz, ori, dist;
-
- creature.GetHomePosition(X, Y, Z, ori);
-
+ float respX, respY, respZ, respO, currZ, destX, destY, destZ, travelDistZ;
+ creature.GetHomePosition(respX, respY, respZ, respO);
+ currZ = creature.GetPositionZ();
Map const* map = creature.GetBaseMap();
// For 2D/3D system selection
- //bool is_land_ok = creature.canWalk();
- //bool is_water_ok = creature.canSwim();
- bool is_air_ok = creature.canFly();
+ //bool is_land_ok = creature.CanWalk(); // not used?
+ //bool is_water_ok = creature.CanSwim(); // not used?
+ bool is_air_ok = creature.canFly();
- for (uint32 i = 0; ; ++i)
- {
- const float angle = (float)rand_norm()*static_cast<float>(M_PI*2);
- const float range = (float)rand_norm()*wander_distance;
- const float distanceX = range * cos(angle);
- const float distanceY = range * sin(angle);
+ 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 * cos(angle);
+ const float distanceY = range * sin(angle);
- nx = X + distanceX;
- ny = Y + distanceY;
+ destX = respX + distanceX;
+ destY = respY + distanceY;
- // prevent invalid coordinates generation
- Trinity::NormalizeMapCoord(nx);
- Trinity::NormalizeMapCoord(ny);
+ // prevent invalid coordinates generation
+ Trinity::NormalizeMapCoord(destX);
+ Trinity::NormalizeMapCoord(destY);
- dist = (nx - X)*(nx - X) + (ny - Y)*(ny - Y);
+ travelDistZ = distanceX*distanceX + distanceY*distanceY;
- if (i == 5)
- {
- nz = Z;
- break;
- }
+ if (is_air_ok) // 3D system above ground and above water (flying mode)
+ {
+ // Limit height change
+ const float distanceZ = float(rand_norm()) * sqrtf(travelDistZ)/2.0f;
+ destZ = respZ + distanceZ;
+ float levelZ = map->GetWaterOrGroundLevel(destX, destY, destZ-2.0f);
+
+ // 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 >= 100.0f ? 10.0f : sqrtf(travelDistZ);
- if (is_air_ok) // 3D system above ground and above water (flying mode)
- {
- const float distanceZ = (float)(rand_norm()) * sqrtf(dist)/2; // Limit height change
- nz = Z + distanceZ;
- float tz = map->GetHeight(nx, ny, nz-2.0f, false); // Map check only, vmap needed here but need to alter vmaps checks for height.
- float wz = map->GetWaterLevel(nx, ny);
- if (tz >= nz || wz >= nz)
- continue; // Problem here, we must fly above the ground and water, not under. Let's try on next tick
- }
- //else if (is_water_ok) // 3D system under water and above ground (swimming mode)
- else // 2D only
+ // 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(destX, destY, respZ+travelDistZ-2.0f, false);
+
+ if (fabs(destZ - respZ) > travelDistZ) // Map check
{
- dist = dist >= 100.0f ? 10.0f : sqrtf(dist); // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE)
+ // Vmap Horizontal or above
+ destZ = map->GetHeight(destX, destY, respZ - 2.0f, true);
- // 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.
- nz = map->GetHeight(nx, ny, Z+dist-2.0f, false); // Map check
- if (fabs(nz-Z)>dist)
+ if (fabs(destZ - respZ) > travelDistZ)
{
- nz = map->GetHeight(nx, ny, Z-2.0f, true); // Vmap Horizontal or above
- if (fabs(nz-Z)>dist)
- {
- nz = map->GetHeight(nx, ny, Z+dist-2.0f, true); // Vmap Higher
- if (fabs(nz-Z)>dist)
- continue; // let's forget this bad coords where a z cannot be find and retry at next tick
- }
+ // Vmap Higher
+ destZ = map->GetHeight(destX, destY, respZ+travelDistZ-2.0f, true);
+
+ // let's forget this bad coords where a z cannot be find and retry at next tick
+ if (fabs(destZ - respZ) > travelDistZ)
+ return;
}
}
- break;
}
- Traveller<Creature> traveller(creature);
- creature.SetOrientation(creature.GetAngle(nx, ny));
- i_destinationHolder.SetDestination(traveller, nx, ny, nz);
- creature.AddUnitState(UNIT_STAT_ROAMING);
if (is_air_ok)
- {
- i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
- }
- //else if (is_water_ok) // Swimming mode to be done with more than this check
+ i_nextMoveTime.Reset(0);
else
- {
- i_nextMoveTime.Reset(urand(500+i_destinationHolder.GetTotalTravelTime(), 5000+i_destinationHolder.GetTotalTravelTime()));
- creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
- }
+ i_nextMoveTime.Reset(urand(500, 10000));
+
+ creature.AddUnitState(UNIT_STAT_ROAMING_MOVE);
+
+ Movement::MoveSplineInit init(creature);
+ init.MoveTo(destX, destY, destZ);
+ init.SetWalk(true);
+ init.Launch();
//Call for creature group update
if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature)
- {
- creature.GetFormation()->LeaderMoveTo(nx, ny, nz);
- }
+ creature.GetFormation()->LeaderMoveTo(destX, destY, destZ);
}
template<>
-void
-RandomMovementGenerator<Creature>::Initialize(Creature &creature)
+void RandomMovementGenerator<Creature>::Initialize(Creature &creature)
{
if (!creature.isAlive())
return;
@@ -143,8 +123,7 @@ RandomMovementGenerator<Creature>::Initialize(Creature &creature)
if (!wander_distance)
wander_distance = creature.GetRespawnRadius();
- if (irand(0, RUNNING_CHANCE_RANDOMMV) > 0)
- creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
+ creature.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
_setRandomLocation(creature);
}
@@ -156,8 +135,11 @@ RandomMovementGenerator<Creature>::Reset(Creature &creature)
}
template<>
-void
-RandomMovementGenerator<Creature>::Finalize(Creature & /*creature*/){}
+void RandomMovementGenerator<Creature>::Finalize(Creature &creature)
+{
+ creature.ClearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
+ creature.SetWalk(false);
+}
template<>
bool
@@ -165,35 +147,29 @@ RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32 diff)
{
if (creature.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
{
- i_nextMoveTime.Update(i_nextMoveTime.GetExpiry()); // Expire the timer
- creature.ClearUnitState(UNIT_STAT_ROAMING);
+ i_nextMoveTime.Reset(0); // Expire the timer
+ creature.ClearUnitState(UNIT_STAT_ROAMING_MOVE);
return true;
}
- i_nextMoveTime.Update(diff);
-
- if (i_destinationHolder.HasArrived() && !creature.IsStopped() && !creature.canFly())
- creature.ClearUnitState(UNIT_STAT_ROAMING | UNIT_STAT_MOVE);
-
- if (!i_destinationHolder.HasArrived() && creature.IsStopped())
- creature.AddUnitState(UNIT_STAT_ROAMING);
-
- CreatureTraveller traveller(creature);
-
- if (i_destinationHolder.UpdateTraveller(traveller, diff, true))
+ if (creature.movespline->Finalized())
{
+ i_nextMoveTime.Update(diff);
if (i_nextMoveTime.Passed())
- {
- if (irand(0, RUNNING_CHANCE_RANDOMMV) > 0)
- creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
_setRandomLocation(creature);
- }
- else if (creature.isPet() && creature.GetOwner() && !creature.IsWithinDist(creature.GetOwner(), PET_FOLLOW_DIST+2.5f))
- {
- creature.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
- _setRandomLocation(creature);
- }
}
return true;
}
+template<>
+bool RandomMovementGenerator<Creature>::GetResetPosition(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);
+
+ return true;
+}
diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
index 816e325f3b1..67161b6fc29 100755
--- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
@@ -20,15 +20,12 @@
#define TRINITY_RANDOMMOTIONGENERATOR_H
#include "MovementGenerator.h"
-#include "DestinationHolder.h"
-#include "Traveller.h"
template<class T>
class RandomMovementGenerator
: public MovementGeneratorMedium< T, RandomMovementGenerator<T> >
{
public:
- // Wander dist is related on db spawn dist. So what if we wanna set eandom movement on summoned creature?!
RandomMovementGenerator(float spawn_dist = 0.0f) : i_nextMoveTime(0), wander_distance(spawn_dist) {}
void _setRandomLocation(T &);
@@ -36,18 +33,13 @@ class RandomMovementGenerator
void Finalize(T &);
void Reset(T &);
bool Update(T &, const uint32);
- bool GetDestination(float &x, float &y, float &z) const;
- void UpdateMapPosition(uint32 mapid, float &x, float &y, float &z)
- {
- i_destinationHolder.GetLocationNow(mapid, x, y, z);
- }
+ bool GetResetPosition(T&, float& x, float& y, float& z);
MovementGeneratorType GetMovementGeneratorType() { return RANDOM_MOTION_TYPE; }
private:
TimeTrackerSmall i_nextMoveTime;
- DestinationHolder< Traveller<T> > i_destinationHolder;
- float wander_distance;
uint32 i_nextMove;
+ float wander_distance;
};
#endif
diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
index e0ca5231000..0d2982ab6b7 100755
--- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
@@ -21,106 +21,43 @@
#include "Errors.h"
#include "Creature.h"
#include "CreatureAI.h"
-#include "DestinationHolderImp.h"
#include "World.h"
-
-#define SMALL_ALPHA 0.05f
+#include "MoveSplineInit.h"
+#include "MoveSpline.h"
+#include "Player.h"
#include <cmath>
-/*
-struct StackCleaner
-{
- Creature &i_creature;
- StackCleaner(Creature &creature) : i_creature(creature) {}
- void Done(void) { i_creature.StopMoving(); }
- ~StackCleaner()
- {
- i_creature->Clear();
- }
-};
-*/
-template<class T>
-TargetedMovementGenerator<T>::TargetedMovementGenerator(Unit &target, float offset, float angle)
-: TargetedMovementGeneratorBase(target)
-, i_offset(offset), i_angle(angle), i_recalculateTravel(false)
-{
- target.GetPosition(i_targetX, i_targetY, i_targetZ);
-}
-
-template<class T>
-bool
-TargetedMovementGenerator<T>::_setTargetLocation(T &owner)
+template<class T, typename D>
+void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner)
{
if (!i_target.isValid() || !i_target->IsInWorld())
- return false;
+ return;
- if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
- return false;
+ if (owner.HasUnitState(UNIT_STAT_NOT_MOVE))
+ return;
float x, y, z;
- Traveller<T> traveller(owner);
- if (i_destinationHolder.HasDestination())
+
+ if (i_offset && i_target->IsWithinDistInMap(&owner,2*i_offset))
{
- if (i_destinationHolder.HasArrived())
- {
- // prevent redundant micro-movement
- if (!i_offset)
- {
- if (i_target->IsWithinMeleeRange(&owner))
- return false;
- }
- else if (!i_angle && !owner.HasUnitState(UNIT_STAT_FOLLOW))
- {
- if (i_target->IsWithinDistInMap(&owner, i_offset))
- return false;
- }
- else
- {
- if (i_target->IsWithinDistInMap(&owner, i_offset + 1.0f))
- return false;
- }
- }
- else
- {
- bool stop = false;
- if (!i_offset)
- {
- if (i_target->IsWithinMeleeRange(&owner, 0))
- stop = true;
- }
- else if (!i_angle && !owner.HasUnitState(UNIT_STAT_FOLLOW))
- {
- if (i_target->IsWithinDist(&owner, i_offset * 0.8f))
- stop = true;
- }
-
- if (stop)
- {
- owner.GetPosition(x, y, z);
- i_destinationHolder.SetDestination(traveller, x, y, z);
- i_destinationHolder.StartTravel(traveller, false);
- owner.StopMoving();
- return false;
- }
- }
+ if (!owner.movespline->Finalized())
+ return;
- if (i_target->GetExactDistSq(i_targetX, i_targetY, i_targetZ) < 0.01f)
- return false;
+ owner.GetPosition(x, y, z);
}
-
- if (!i_offset)
+ else if (!i_offset)
{
+ if (i_target->IsWithinMeleeRange(&owner))
+ return;
+
// to nearest random contact position
i_target->GetRandomContactPoint(&owner, x, y, z, 0, MELEE_RANGE - 0.5f);
}
- else if (!i_angle && !owner.HasUnitState(UNIT_STAT_FOLLOW))
- {
- // caster chase
- i_target->GetContactPoint(&owner, x, y, z, i_offset * urand(80, 95) * 0.01f);
- }
else
{
+ if (i_target->IsWithinDistInMap(&owner, i_offset + 1.0f))
+ return;
// to at i_offset distance from target and i_angle from target facing
i_target->GetClosePoint(x, y, z, owner.GetObjectSize(), i_offset, i_angle);
}
@@ -137,55 +74,65 @@ TargetedMovementGenerator<T>::_setTargetLocation(T &owner)
ralf
//We don't update Mob Movement, if the difference between New destination and last destination is < BothObjectSize
- float bothObjectSize = i_target->GetObjectSize() + owner.GetObjectSize() + CONTACT_DISTANCE;
- if (i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x, y, z) < bothObjectSize)
+ float bothObjectSize = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + CONTACT_DISTANCE;
+ if( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize )
return;
*/
- i_destinationHolder.SetDestination(traveller, x, y, z);
- owner.AddUnitState(UNIT_STAT_CHASE);
- i_destinationHolder.StartTravel(traveller);
- return true;
+
+
+ D::_addUnitStateMove(owner);
+ i_targetReached = false;
+ i_recalculateTravel = false;
+
+ Movement::MoveSplineInit init(owner);
+ init.MoveTo(x,y,z);
+ init.SetWalk(((D*)this)->EnableWalking());
+ init.Launch();
}
-template<class T>
-void
-TargetedMovementGenerator<T>::Initialize(T &owner)
+template<>
+void TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::UpdateFinalDistance(float /*fDistance*/)
{
- if (owner.isInCombat())
- owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
+ // nothing to do for Player
+}
- _setTargetLocation(owner);
+template<>
+void TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::UpdateFinalDistance(float /*fDistance*/)
+{
+ // nothing to do for Player
}
-template<class T>
-void
-TargetedMovementGenerator<T>::Finalize(T &owner)
+template<>
+void TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::UpdateFinalDistance(float fDistance)
{
- owner.ClearUnitState(UNIT_STAT_CHASE);
+ i_offset = fDistance;
+ i_recalculateTravel = true;
}
-template<class T>
-void
-TargetedMovementGenerator<T>::Reset(T &owner)
+template<>
+void TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::UpdateFinalDistance(float fDistance)
{
- Initialize(owner);
+ i_offset = fDistance;
+ i_recalculateTravel = true;
}
-template<class T>
-bool
-TargetedMovementGenerator<T>::Update(T &owner, const uint32 time_diff)
+template<class T, typename D>
+bool TargetedMovementGeneratorMedium<T,D>::Update(T &owner, const uint32 & time_diff)
{
if (!i_target.isValid() || !i_target->IsInWorld())
return false;
- if (!&owner || !owner.isAlive())
+ if (!owner.isAlive())
return true;
- if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DISTRACTED))
+ if (owner.HasUnitState(UNIT_STAT_NOT_MOVE))
+ {
+ D::_clearUnitStateMove(owner);
return true;
+ }
// prevent movement while casting spells with cast time or channel time
- if (owner.HasUnitState(UNIT_STAT_CASTING))
+ if (owner.IsNonMeleeSpellCasted(false, false, true))
{
if (!owner.IsStopped())
owner.StopMoving();
@@ -193,85 +140,184 @@ TargetedMovementGenerator<T>::Update(T &owner, const uint32 time_diff)
}
// prevent crash after creature killed pet
- if (!owner.HasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget())
+ if (static_cast<D*>(this)->_lostTarget(owner))
+ {
+ D::_clearUnitStateMove(owner);
return true;
+ }
- Traveller<T> traveller(owner);
-
- if (!i_destinationHolder.HasDestination())
- _setTargetLocation(owner);
- else if (owner.IsStopped() && !i_destinationHolder.HasArrived())
+ i_recheckDistance.Update(time_diff);
+ if (i_recheckDistance.Passed())
{
- owner.AddUnitState(UNIT_STAT_CHASE);
- i_destinationHolder.StartTravel(traveller);
- return true;
+ i_recheckDistance.Reset(50);
+ //More distance let have better performance, less distance let have more sensitive reaction at target move.
+ float allowed_dist = i_target->GetObjectSize() + owner.GetObjectSize() + MELEE_RANGE - 0.5f;
+ float dist = (owner.movespline->FinalDestination() - G3D::Vector3(i_target->GetPositionX(),i_target->GetPositionY(),i_target->GetPositionZ())).squaredLength();
+ if (dist >= allowed_dist * allowed_dist)
+ _setTargetLocation(owner);
}
- if (i_destinationHolder.UpdateTraveller(traveller, time_diff))
+ if (owner.movespline->Finalized())
{
- // put targeted movement generators on a higher priority
- //if (owner.GetObjectSize())
- //i_destinationHolder.ResetUpdate(50);
+ static_cast<D*>(this)->MovementInform(owner);
+ if (i_angle == 0.f && !owner.HasInArc(0.01f, i_target.getTarget()))
+ owner.SetInFront(i_target.getTarget());
- // target moved
- if (i_targetX != i_target->GetPositionX() || i_targetY != i_target->GetPositionY()
- || i_targetZ != i_target->GetPositionZ())
+ if (!i_targetReached)
{
- if (_setTargetLocation(owner) || !owner.HasUnitState(UNIT_STAT_FOLLOW))
- owner.SetInFront(i_target.getTarget());
- i_target->GetPosition(i_targetX, i_targetY, i_targetZ);
+ i_targetReached = true;
+ static_cast<D*>(this)->_reachTarget(owner);
}
+ }
+ else
+ {
+ if (i_recalculateTravel)
+ _setTargetLocation(owner);
+ }
+ return true;
+}
- if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel)
- {
- i_recalculateTravel = false;
- //Angle update will take place into owner.StopMoving()
- owner.SetInFront(i_target.getTarget());
+//-----------------------------------------------//
+template<class T>
+void ChaseMovementGenerator<T>::_reachTarget(T &owner)
+{
+ if (owner.IsWithinMeleeRange(this->i_target.getTarget()))
+ owner.Attack(this->i_target.getTarget(),true);
+}
- owner.StopMoving();
- if (owner.IsWithinMeleeRange(i_target.getTarget()) && !owner.HasUnitState(UNIT_STAT_FOLLOW))
- owner.Attack(i_target.getTarget(), true);
- }
- }
+template<>
+void ChaseMovementGenerator<Player>::Initialize(Player &owner)
+{
+ owner.AddUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE);
+ _setTargetLocation(owner);
+}
- // Implemented for PetAI to handle resetting flags when pet owner reached
- if (i_destinationHolder.HasArrived())
- MovementInform(owner);
+template<>
+void ChaseMovementGenerator<Creature>::Initialize(Creature &owner)
+{
+ owner.SetWalk(false);
+ owner.AddUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE);
+ _setTargetLocation(owner);
+}
- return true;
+template<class T>
+void ChaseMovementGenerator<T>::Finalize(T &owner)
+{
+ owner.ClearUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE);
}
template<class T>
-Unit*
-TargetedMovementGenerator<T>::GetTarget() const
+void ChaseMovementGenerator<T>::Reset(T &owner)
{
- return i_target.getTarget();
+ Initialize(owner);
}
template<class T>
-void TargetedMovementGenerator<T>::MovementInform(T & /*unit*/)
+void ChaseMovementGenerator<T>::MovementInform(T & /*unit*/)
{
}
-template <> void TargetedMovementGenerator<Creature>::MovementInform(Creature &unit)
+template<>
+void ChaseMovementGenerator<Creature>::MovementInform(Creature &unit)
{
// Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
- unit.AI()->MovementInform(TARGETED_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
+ if (unit.AI())
+ unit.AI()->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
+}
+
+//-----------------------------------------------//
+template<>
+bool FollowMovementGenerator<Creature>::EnableWalking() const
+{
+ return i_target.isValid() && i_target->IsWalking();
+}
+
+template<>
+bool FollowMovementGenerator<Player>::EnableWalking() const
+{
+ return false;
+}
+
+template<>
+void FollowMovementGenerator<Player>::_updateSpeed(Player &/*u*/)
+{
+ // nothing to do for Player
+}
+
+template<>
+void FollowMovementGenerator<Creature>::_updateSpeed(Creature &u)
+{
+ // pet only sync speed with owner
+ if (!((Creature&)u).isPet() || !i_target.isValid() || i_target->GetGUID() != u.GetOwnerGUID())
+ return;
+
+ u.UpdateSpeed(MOVE_RUN,true);
+ u.UpdateSpeed(MOVE_WALK,true);
+ u.UpdateSpeed(MOVE_SWIM,true);
+}
+
+template<>
+void FollowMovementGenerator<Player>::Initialize(Player &owner)
+{
+ owner.AddUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE);
+ _updateSpeed(owner);
+ _setTargetLocation(owner);
+}
+
+template<>
+void FollowMovementGenerator<Creature>::Initialize(Creature &owner)
+{
+ owner.AddUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE);
+ _updateSpeed(owner);
+ _setTargetLocation(owner);
+}
+
+template<class T>
+void FollowMovementGenerator<T>::Finalize(T &owner)
+{
+ owner.ClearUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE);
+ _updateSpeed(owner);
}
-template void TargetedMovementGenerator<Player>::MovementInform(Player&); // Not implemented for players
-template TargetedMovementGenerator<Player>::TargetedMovementGenerator(Unit &target, float offset, float angle);
-template TargetedMovementGenerator<Creature>::TargetedMovementGenerator(Unit &target, float offset, float angle);
-template bool TargetedMovementGenerator<Player>::_setTargetLocation(Player &);
-template bool TargetedMovementGenerator<Creature>::_setTargetLocation(Creature &);
-template void TargetedMovementGenerator<Player>::Initialize(Player &);
-template void TargetedMovementGenerator<Creature>::Initialize(Creature &);
-template void TargetedMovementGenerator<Player>::Finalize(Player &);
-template void TargetedMovementGenerator<Creature>::Finalize(Creature &);
-template void TargetedMovementGenerator<Player>::Reset(Player &);
-template void TargetedMovementGenerator<Creature>::Reset(Creature &);
-template bool TargetedMovementGenerator<Player>::Update(Player &, const uint32);
-template bool TargetedMovementGenerator<Creature>::Update(Creature &, const uint32);
-template Unit* TargetedMovementGenerator<Player>::GetTarget() const;
-template Unit* TargetedMovementGenerator<Creature>::GetTarget() const;
+template<class T>
+void FollowMovementGenerator<T>::Reset(T &owner)
+{
+ Initialize(owner);
+}
+
+template<class T>
+void FollowMovementGenerator<T>::MovementInform(T & /*unit*/)
+{
+}
+
+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()->GetGUIDLow());
+}
+//-----------------------------------------------//
+template void TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::_setTargetLocation(Player &);
+template void TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::_setTargetLocation(Player &);
+template void TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::_setTargetLocation(Creature &);
+template void TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::_setTargetLocation(Creature &);
+template bool TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::Update(Player &, const uint32 &);
+template bool TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::Update(Player &, const uint32 &);
+template bool TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::Update(Creature &, const uint32 &);
+template bool TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::Update(Creature &, const uint32 &);
+
+template void ChaseMovementGenerator<Player>::_reachTarget(Player &);
+template void ChaseMovementGenerator<Creature>::_reachTarget(Creature &);
+template void ChaseMovementGenerator<Player>::Finalize(Player &);
+template void ChaseMovementGenerator<Creature>::Finalize(Creature &);
+template void ChaseMovementGenerator<Player>::Reset(Player &);
+template void ChaseMovementGenerator<Creature>::Reset(Creature &);
+template void ChaseMovementGenerator<Player>::MovementInform(Player &unit);
+
+template void FollowMovementGenerator<Player>::Finalize(Player &);
+template void FollowMovementGenerator<Creature>::Finalize(Creature &);
+template void FollowMovementGenerator<Player>::Reset(Player &);
+template void FollowMovementGenerator<Creature>::Reset(Creature &);
+template void FollowMovementGenerator<Player>::MovementInform(Player &unit);
diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h
index edb4fca8fce..696c99e1460 100755
--- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h
@@ -20,9 +20,9 @@
#define TRINITY_TARGETEDMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
-#include "DestinationHolder.h"
-#include "Traveller.h"
#include "FollowerReference.h"
+#include "Timer.h"
+#include "Unit.h"
class TargetedMovementGeneratorBase
{
@@ -33,41 +33,84 @@ class TargetedMovementGeneratorBase
FollowerReference i_target;
};
+template<class T, typename D>
+class TargetedMovementGeneratorMedium
+: public MovementGeneratorMedium< T, D >, public TargetedMovementGeneratorBase
+{
+ protected:
+ TargetedMovementGeneratorMedium(Unit &target, float offset, float angle) :
+ TargetedMovementGeneratorBase(target), i_offset(offset), i_angle(angle),
+ i_recalculateTravel(false), i_targetReached(false), i_recheckDistance(0)
+ {
+ }
+ ~TargetedMovementGeneratorMedium() {}
+
+ public:
+ bool Update(T &, const uint32 &);
+ Unit* GetTarget() const { return i_target.getTarget(); }
+
+ void unitSpeedChanged() { i_recalculateTravel=true; }
+ void UpdateFinalDistance(float fDistance);
+
+ protected:
+ void _setTargetLocation(T &);
+
+ TimeTrackerSmall i_recheckDistance;
+ float i_offset;
+ float i_angle;
+ bool i_recalculateTravel : 1;
+ bool i_targetReached : 1;
+};
+
template<class T>
-class TargetedMovementGenerator
-: public MovementGeneratorMedium< T, TargetedMovementGenerator<T> >, public TargetedMovementGeneratorBase
+class ChaseMovementGenerator : public TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >
{
public:
- TargetedMovementGenerator(Unit &target, float offset = 0, float angle = 0);
- ~TargetedMovementGenerator() {}
+ ChaseMovementGenerator(Unit &target)
+ : TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target) {}
+ ChaseMovementGenerator(Unit &target, float offset, float angle)
+ : TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target, offset, angle) {}
+ ~ChaseMovementGenerator() {}
+
+ MovementGeneratorType GetMovementGeneratorType() { return CHASE_MOTION_TYPE; }
void Initialize(T &);
void Finalize(T &);
void Reset(T &);
- bool Update(T &, const uint32);
- MovementGeneratorType GetMovementGeneratorType() { return TARGETED_MOTION_TYPE; }
-
void MovementInform(T &);
- Unit* GetTarget() const;
+ static void _clearUnitStateMove(T &u) { u.ClearUnitState(UNIT_STAT_CHASE_MOVE); }
+ static void _addUnitStateMove(T &u) { u.AddUnitState(UNIT_STAT_CHASE_MOVE); }
+ bool EnableWalking() const { return false;}
+ bool _lostTarget(T &u) const { return u.getVictim() != this->GetTarget(); }
+ void _reachTarget(T &);
+};
- bool GetDestination(float &x, float &y, float &z) const
- {
- if (i_destinationHolder.HasArrived() || !i_destinationHolder.HasDestination()) return false;
- i_destinationHolder.GetDestination(x, y, z);
- return true;
- }
+template<class T>
+class FollowMovementGenerator : public TargetedMovementGeneratorMedium<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() {}
- void unitSpeedChanged() { i_recalculateTravel=true; }
- private:
+ MovementGeneratorType GetMovementGeneratorType() { return FOLLOW_MOTION_TYPE; }
- bool _setTargetLocation(T &);
+ void Initialize(T &);
+ void Finalize(T &);
+ void Reset(T &);
+ void MovementInform(T &);
- float i_offset;
- float i_angle;
- DestinationHolder< Traveller<T> > i_destinationHolder;
- bool i_recalculateTravel;
- float i_targetX, i_targetY, i_targetZ;
+ static void _clearUnitStateMove(T &u) { u.ClearUnitState(UNIT_STAT_FOLLOW_MOVE); }
+ static void _addUnitStateMove(T &u) { u.AddUnitState(UNIT_STAT_FOLLOW_MOVE); }
+ bool EnableWalking() const;
+ bool _lostTarget(T &) const { return false; }
+ void _reachTarget(T &) {}
+ private:
+ void _updateSpeed(T &u);
};
+
#endif
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index f88ed249aca..ce8628af1ca 100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -17,222 +17,166 @@
*/
//Basic headers
#include "WaypointMovementGenerator.h"
-#include "DestinationHolderImp.h"
//Extended headers
#include "ObjectMgr.h"
#include "World.h"
-#include "MapManager.h" // for flightmaster grid preloading
+//Flightmaster grid preloading
+#include "MapManager.h"
//Creature-specific headers
#include "Creature.h"
#include "CreatureAI.h"
#include "CreatureGroups.h"
//Player-specific
#include "Player.h"
+#include "MoveSplineInit.h"
+#include "MoveSpline.h"
-template<class T>
-void
-WaypointMovementGenerator<T>::Initialize(T & /*u*/){}
-
-template<>
-void
-WaypointMovementGenerator<Creature>::Finalize(Creature & /*u*/){}
+void WaypointMovementGenerator<Creature>::LoadPath(Creature &creature)
+{
+ if (!path_id)
+ path_id = creature.GetWaypointPath();
-template<>
-void
-WaypointMovementGenerator<Player>::Finalize(Player & /*u*/){}
+ i_path = sWaypointMgr->GetPath(path_id);
-template<class T>
-void
-WaypointMovementGenerator<T>::MovementInform(T & /*unit*/){}
+ if (!i_path)
+ {
+ // No movement found for entry
+ sLog->outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path id: %u", creature.GetName(), creature.GetEntry(), creature.GetGUIDLow(), path_id);
+ return;
+ }
-template<>
-void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit)
-{
- unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
+ StartMoveNow(creature);
}
-template<>
-bool WaypointMovementGenerator<Creature>::GetDestination(float &x, float &y, float &z) const
+void WaypointMovementGenerator<Creature>::Initialize(Creature &creature)
{
- if (i_destinationHolder.HasArrived())
- return false;
-
- i_destinationHolder.GetDestination(x, y, z);
- return true;
+ LoadPath(creature);
+ creature.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
}
-template<>
-bool WaypointMovementGenerator<Player>::GetDestination(float & /*x*/, float & /*y*/, float & /*z*/) const
+void WaypointMovementGenerator<Creature>::Finalize(Creature &creature)
{
- return false;
+ creature.ClearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
+ creature.SetWalk(false);
}
-template<>
-void WaypointMovementGenerator<Creature>::Reset(Creature & /*unit*/)
+void WaypointMovementGenerator<Creature>::Reset(Creature &creature)
{
- StopedByPlayer = true;
- i_nextMoveTime.Reset(0);
+ creature.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
+ StartMoveNow(creature);
}
-template<>
-void WaypointMovementGenerator<Player>::Reset(Player & /*unit*/){}
-
-template<>
-void WaypointMovementGenerator<Creature>::InitTraveller(Creature &unit, const WaypointData &node)
+void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature)
{
- node.run ? unit.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING):
- unit.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
+ if (!i_path || i_path->empty())
+ return;
+ if (m_isArrivalDone)
+ return;
- unit.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
- unit.SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
+ creature.ClearUnitState(UNIT_STAT_ROAMING_MOVE);
+ m_isArrivalDone = true;
- // TODO: make this part of waypoint node, so that creature can walk when desired?
- if (unit.canFly())
- unit.SetByteFlag(UNIT_FIELD_BYTES_1, 3, 0x02);
+ if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance)
+ {
+ sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for %u.", i_path->at(i_currentNode)->event_id, i_currentNode, creature.GetGUID());
+ creature.GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, &creature, NULL/*, false*/);
+ }
- unit.AddUnitState(UNIT_STAT_ROAMING);
+ // Inform script
+ MovementInform(creature);
+ creature.UpdateWaypointID(i_currentNode);
+ Stop(i_path->at(i_currentNode)->delay);
}
-template<>
-void
-WaypointMovementGenerator<Creature>::Initialize(Creature &u)
+bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature)
{
- u.StopMoving();
- //i_currentNode = -1; // uint32, become 0 in the first update
- //i_nextMoveTime.Reset(0);
- StopedByPlayer = false;
- if (!path_id)
- path_id = u.GetWaypointPath();
- waypoints = sWaypointMgr->GetPath(path_id);
- i_currentNode = 0;
- if (waypoints && waypoints->size())
+ if (!i_path || i_path->empty())
+ return false;
+ if (Stopped())
+ return true;
+
+ if (m_isArrivalDone)
{
- node = waypoints->front();
- Traveller<Creature> traveller(u);
- InitTraveller(u, *node);
- i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
- i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
-
- //Call for creature group update
- if (u.GetFormation() && u.GetFormation()->getLeader() == &u)
- u.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
+ if ((i_currentNode == i_path->size() - 1) && !repeating) // If that's our last waypoint
+ {
+ creature.SetHomePosition(i_path->at(i_currentNode)->x, i_path->at(i_currentNode)->y, i_path->at(i_currentNode)->z, creature.GetOrientation());
+ creature.GetMotionMaster()->Initialize();
+ return false;
+ }
+
+ i_currentNode = (i_currentNode+1) % i_path->size();
}
- else
- node = NULL;
-}
-template<>
-void WaypointMovementGenerator<Player>::InitTraveller(Player & /*unit*/, const WaypointData & /*node*/){}
+ const WaypointData *node = i_path->at(i_currentNode);
-template<class T>
-bool
-WaypointMovementGenerator<T>::Update(T & /*unit*/, const uint32 /*diff*/)
-{
- return false;
-}
+ m_isArrivalDone = false;
-template<>
-bool
-WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 diff)
-{
- if (!&unit)
- return true;
+ creature.AddUnitState(UNIT_STAT_ROAMING_MOVE);
+
+ Movement::MoveSplineInit init(creature);
+ init.MoveTo(node->x, node->y, node->z);
- if (!path_id)
- return false;
+ if (node->orientation != 100 && node->delay != 0)
+ init.SetFacing(node->orientation);
+
+ init.SetWalk(!node->run);
+ init.Launch();
+
+ //Call for creature group update
+ if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature)
+ creature.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
+
+ return true;
+}
+bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
+{
// Waypoint movement can be switched on/off
// This is quite handy for escort quests and other stuff
- if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
+ if (creature.HasUnitState(UNIT_STAT_NOT_MOVE))
+ {
+ creature.ClearUnitState(UNIT_STAT_ROAMING_MOVE);
return true;
-
- // Clear the generator if the path doesn't exist
- if (!waypoints || !waypoints->size())
+ }
+ // prevent a crash at empty waypoint path.
+ if (!i_path || i_path->empty())
return false;
- Traveller<Creature> traveller(unit);
-
- i_nextMoveTime.Update(diff);
- i_destinationHolder.UpdateTraveller(traveller, diff, true);
-
- if (i_nextMoveTime.GetExpiry() < TIMEDIFF_NEXT_WP)
+ if (Stopped())
{
- if (unit.IsStopped())
- {
- if (StopedByPlayer)
- {
- ASSERT(node);
- InitTraveller(unit, *node);
- i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
- i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
- StopedByPlayer = false;
- return true;
- }
-
- if (i_currentNode == waypoints->size() - 1) // If that's our last waypoint
- {
- if (repeating) // If the movement is repeating
- i_currentNode = 0; // Start moving all over again
- else
- {
- unit.SetHomePosition(node->x, node->y, node->z, unit.GetOrientation());
- unit.GetMotionMaster()->Initialize();
- return false; // Clear the waypoint movement
- }
- }
- else
- ++i_currentNode;
-
- node = waypoints->at(i_currentNode);
- InitTraveller(unit, *node);
- i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
- i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
-
- //Call for creature group update
- if (unit.GetFormation() && unit.GetFormation()->getLeader() == &unit)
- unit.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
- }
- else
- {
- //Determine waittime
- if (node->delay)
- i_nextMoveTime.Reset(node->delay);
-
- //note: disable "start" for mtmap
- if (node->event_id && urand(0, 99) < node->event_chance)
- unit.GetMap()->ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL/*, false*/);
-
- i_destinationHolder.ResetTravelTime();
- MovementInform(unit);
- unit.UpdateWaypointID(i_currentNode);
- unit.ClearUnitState(UNIT_STAT_ROAMING);
- if (node->orientation)
- {
- unit.Relocate(node->x, node->y, node->z, node->orientation);
- unit.SetFacing(node->orientation, NULL);
- }
- else
- unit.Relocate(node->x, node->y, node->z);
- }
+ if (CanMove(diff))
+ return StartMove(creature);
}
- else
+ else
{
- if (unit.IsStopped() && !i_destinationHolder.HasArrived())
+ if (creature.IsStopped())
+ Stop(STOP_TIME_FOR_PLAYER);
+ else if (creature.movespline->Finalized())
{
- if (!StopedByPlayer)
- {
- i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER);
- i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER);
- StopedByPlayer = true;
- }
- }
+ OnArrived(creature);
+ return StartMove(creature);
+ }
}
+ return true;
+ }
+
+void WaypointMovementGenerator<Creature>::MovementInform(Creature &creature)
+{
+ if (creature.AI())
+ creature.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
+}
+
+bool WaypointMovementGenerator<Creature>::GetResetPosition(Creature&, float& x, float& y, float& z)
+{
+ // prevent a crash at empty waypoint path.
+ if (!i_path || i_path->empty())
+ return false;
+
+ const WaypointData* node = i_path->at(i_currentNode);
+ x = node->x; y = node->y; z = node->z;
return true;
}
-template void WaypointMovementGenerator<Player>::Initialize(Player &);
-template bool WaypointMovementGenerator<Player>::Update(Player &, const uint32);
-template void WaypointMovementGenerator<Player>::MovementInform(Player &);
//----------------------------------------------------//
@@ -253,71 +197,72 @@ uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const
void FlightPathMovementGenerator::Initialize(Player &player)
{
- player.getHostileRefManager().setOnlineOfflineState(false);
- player.AddUnitState(UNIT_STAT_IN_FLIGHT);
- player.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
- Traveller<Player> traveller(player);
- // do not send movement, it was sent already
- i_destinationHolder.SetDestination(traveller, (*i_path)[i_currentNode].x, (*i_path)[i_currentNode].y, (*i_path)[i_currentNode].z, false);
- // For preloading end grid
+ Reset(player);
InitEndGridInfo();
- player.SendMonsterMoveByPath(GetPath(), GetCurrentNode(), GetPathAtMapEnd());
}
void FlightPathMovementGenerator::Finalize(Player & player)
{
+ // remove flag to prevent send object build movement packets for flight state and crash (movement generator already not at top of stack)
player.ClearUnitState(UNIT_STAT_IN_FLIGHT);
- float x = 0;
- float y = 0;
- float z = 0;
- i_destinationHolder.GetLocationNow(player.GetBaseMap(), x, y, z);
- player.UpdatePosition(x, y, z, player.GetOrientation());
+ player.Dismount();
+ player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
+ if(player.m_taxi.empty())
+ {
+ player.getHostileRefManager().setOnlineOfflineState(true);
+ if(player.pvpInfo.inHostileArea)
+ player.CastSpell(&player, 2479, true);
+
+ // update z position to ground and orientation for landing point
+ // this prevent cheating with landing point at lags
+ // when client side flight end early in comparison server side
+ player.StopMoving();
+ }
+}
+
+#define PLAYER_FLIGHT_SPEED 32.0f
+
+void FlightPathMovementGenerator::Reset(Player & player)
+{
+ player.getHostileRefManager().setOnlineOfflineState(false);
+ player.AddUnitState(UNIT_STAT_IN_FLIGHT);
+ player.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
+
+ Movement::MoveSplineInit init(player);
+ uint32 end = GetPathAtMapEnd();
+ for (uint32 i = GetCurrentNode(); i != end; ++i)
+ {
+ G3D::Vector3 vertice((*i_path)[i].x,(*i_path)[i].y,(*i_path)[i].z);
+ init.Path().push_back(vertice);
+ }
+ init.SetFirstPointId(GetCurrentNode());
+ init.SetFly();
+ init.SetVelocity(PLAYER_FLIGHT_SPEED);
+ init.Launch();
}
bool FlightPathMovementGenerator::Update(Player &player, const uint32 diff)
{
- if (MovementInProgress())
+ uint32 pointId = (uint32)player.movespline->currentPathIdx();
+ if (pointId > i_currentNode)
{
- Traveller<Player> traveller(player);
- if (i_destinationHolder.UpdateTraveller(traveller, diff))
+ bool departureEvent = true;
+ do
{
- i_destinationHolder.ResetUpdate(FLIGHT_TRAVEL_UPDATE);
- if (i_destinationHolder.HasArrived())
- {
- DoEventIfAny(player, (*i_path)[i_currentNode], false);
-
- uint32 curMap = (*i_path)[i_currentNode].mapid;
- ++i_currentNode;
- if (MovementInProgress())
- {
- DoEventIfAny(player, (*i_path)[i_currentNode], true);
-
- sLog->outStaticDebug("loading node %u for player %s", i_currentNode, player.GetName());
- if ((*i_path)[i_currentNode].mapid == curMap)
- {
- // do not send movement, it was sent already
- i_destinationHolder.SetDestination(traveller, (*i_path)[i_currentNode].x, (*i_path)[i_currentNode].y, (*i_path)[i_currentNode].z, false);
- }
-
- // check if it's time to preload the flightmaster grid at path end
- if (i_currentNode == m_preloadTargetNode)
- PreloadEndGrid();
-
- return true;
- }
- //else HasArrived()
- }
- else
- return true;
+ DoEventIfAny(player, (*i_path)[i_currentNode], departureEvent);
+ if (pointId == i_currentNode)
+ break;
+ if (i_currentNode == _preloadTargetNode)
+ PreloadEndGrid();
+ i_currentNode += (uint32)departureEvent;
+ departureEvent = !departureEvent;
}
- else
- return true;
+ while (true);
}
- // we have arrived at the end of the path
- return false;
+ return i_currentNode < (i_path->size()-1);
}
void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
@@ -336,42 +281,48 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
}
}
+void FlightPathMovementGenerator::DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure)
+{
+ if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID)
+ {
+ sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.index, node.path, player.GetName());
+ player.GetMap()->ScriptsStart(sEventScripts, eventid, &player, &player);
+ }
+}
+
+bool FlightPathMovementGenerator::GetResetPosition(Player&, float& x, float& y, float& z)
+{
+ const TaxiPathNodeEntry& node = (*i_path)[i_currentNode];
+ x = node.x; y = node.y; z = node.z;
+ return true;
+}
+
void FlightPathMovementGenerator::InitEndGridInfo()
{
- // Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will
- // be reinitialized for each flightmaster at the end of each spline (or stop) in the flight.
-
- uint32 nodeCount = (*i_path).size(); // Get the number of nodes in the path.
- m_endMapId = (*i_path)[nodeCount -1].mapid; // Get the map ID from the last node
- m_preloadTargetNode = nodeCount - 3; // 2 nodes before the final node, we pre-load the grid
- m_endGridX = (*i_path)[nodeCount -1].x; // Get the X position from the last node
- m_endGridY = (*i_path)[nodeCount -1].y; // Get the Y position from the last node
+ /*! Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will
+ be reinitialized for each flightmaster at the end of each spline (or stop) in the flight. */
+ uint32 nodeCount = (*i_path).size(); //! Number of nodes in path.
+ _endMapId = (*i_path)[nodeCount - 1].mapid; //! MapId of last node
+ _preloadTargetNode = nodeCount - 3;
+ _endGridX = (*i_path)[nodeCount - 1].x;
+ _endGridY = (*i_path)[nodeCount - 1].y;
}
void FlightPathMovementGenerator::PreloadEndGrid()
{
// used to preload the final grid where the flightmaster is
- Map* endMap = sMapMgr->FindBaseNonInstanceMap(m_endMapId);
+ Map* endMap = sMapMgr->FindBaseNonInstanceMap(_endMapId);
// Load the grid
if (endMap)
{
- sLog->outDetail("Preloading flightmaster at grid (%f, %f) for map %u", m_endGridX, m_endGridY, m_endMapId);
- endMap->LoadGrid(m_endGridX, m_endGridY);
+ sLog->outDetail("Preloading rid (%f, %f) for map %u at node index %u/%u", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path->size()-1));
+ endMap->LoadGrid(_endGridX, _endGridY);
}
else
sLog->outDetail("Unable to determine map to preload flightmaster grid");
}
-void FlightPathMovementGenerator::DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure)
-{
- if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID)
- {
- sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.index, node.path, player.GetName());
- player.GetMap()->ScriptsStart(sEventScripts, eventid, &player, &player);
- }
-}
-
//
// Unique1's ASTAR Pathfinding Code... For future use & reference...
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
index 230630936ff..aa6d327db3b 100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
@@ -26,10 +26,8 @@
*/
#include "MovementGenerator.h"
-#include "DestinationHolder.h"
#include "WaypointManager.h"
#include "Path.h"
-#include "Traveller.h"
#include "Player.h"
@@ -44,49 +42,68 @@ template<class T, class P>
class PathMovementBase
{
public:
- PathMovementBase() : i_currentNode(0) {}
+ PathMovementBase() : i_currentNode(0), i_path(NULL) {}
virtual ~PathMovementBase() {};
- bool MovementInProgress(void) const { return i_currentNode < i_path->size(); }
-
+ // template pattern, not defined .. override required
void LoadPath(T &);
- void ReloadPath(T &);
uint32 GetCurrentNode() const { return i_currentNode; }
- bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x, y, z); return true; }
- bool GetPosition(float& x, float& y, float& z) const { i_destinationHolder.GetLocationNowNoMicroMovement(x, y, z); return true; }
-
protected:
- uint32 i_currentNode;
- DestinationHolder< Traveller<T> > i_destinationHolder;
P i_path;
+ uint32 i_currentNode;
};
template<class T>
+class WaypointMovementGenerator;
-class WaypointMovementGenerator
- : public MovementGeneratorMedium< T, WaypointMovementGenerator<T> >, public PathMovementBase<T, WaypointPath const*>
+template<>
+class WaypointMovementGenerator<Creature>
+: public MovementGeneratorMedium< Creature, WaypointMovementGenerator<Creature> >,
+public PathMovementBase<Creature, WaypointPath const*>
{
public:
- WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true) :
- node(NULL), path_id(_path_id), i_nextMoveTime(0), repeating(_repeating), StopedByPlayer(false) {}
-
- void Initialize(T &);
- void Finalize(T &);
- void MovementInform(T &);
- void InitTraveller(T &, const WaypointData &);
- void GeneratePathId(T &);
- void Reset(T &unit);
- bool Update(T &, const uint32);
- bool GetDestination(float &x, float &y, float &z) const;
+ WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true) : i_nextMoveTime(0), path_id(_path_id), m_isArrivalDone(false), repeating(_repeating) {}
+ ~WaypointMovementGenerator() { i_path = NULL; }
+ void Initialize(Creature &);
+ void Finalize(Creature &);
+ void Reset(Creature &);
+ bool Update(Creature &, const uint32 &diff);
+
+ void MovementInform(Creature &);
+
MovementGeneratorType GetMovementGeneratorType() { return WAYPOINT_MOTION_TYPE; }
+ // now path movement implmementation
+ void LoadPath(Creature &c);
+
+ bool GetResetPosition(Creature&, float& x, float& y, float& z);
+
private:
- WaypointData* node;
- uint32 path_id;
+
+ void Stop(int32 time) { i_nextMoveTime.Reset(time);}
+
+ bool Stopped() { return !i_nextMoveTime.Passed();}
+
+ bool CanMove(int32 diff)
+ {
+ i_nextMoveTime.Update(diff);
+ return i_nextMoveTime.Passed();
+ }
+
+ void OnArrived(Creature&);
+ bool StartMove(Creature&);
+
+ void StartMoveNow(Creature& creature)
+ {
+ i_nextMoveTime.Reset(0);
+ StartMove(creature);
+ }
+
TimeTrackerSmall i_nextMoveTime;
- WaypointPath const* waypoints;
- bool repeating, StopedByPlayer;
+ bool m_isArrivalDone;
+ uint32 path_id;
+ bool repeating;
};
/** FlightPathMovementGenerator generates movement of the player for the paths
@@ -103,7 +120,7 @@ public PathMovementBase<Player, TaxiPathNodeList const*>
i_currentNode = startNode;
}
void Initialize(Player &);
- void Reset(Player & /*u*/){};
+ void Reset(Player &);
void Finalize(Player &);
bool Update(Player &, const uint32);
MovementGeneratorType GetMovementGeneratorType() { return FLIGHT_MOTION_TYPE; }
@@ -115,17 +132,16 @@ public PathMovementBase<Player, TaxiPathNodeList const*>
void SkipCurrentNode() { ++i_currentNode; }
void DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure);
- bool GetDestination(float& x, float& y, float& z) const { return PathMovementBase<Player, TaxiPathNodeList const*>::GetDestination(x, y, z); }
+ bool GetResetPosition(Player&, float& x, float& y, float& z);
- void PreloadEndGrid();
void InitEndGridInfo();
+ void PreloadEndGrid();
+
private:
- // storage for preloading the flightmaster grid at end
- // before reaching final waypoint
- uint32 m_endMapId;
- uint32 m_preloadTargetNode;
- float m_endGridX;
- float m_endGridY;
+ float _endGridX; //! X coord of last node location
+ float _endGridY; //! Y coord of last node location
+ uint32 _endMapId; //! map Id of last node location
+ uint32 _preloadTargetNode; //! node index where preloading starts
};
#endif
diff --git a/src/server/game/Movement/Spline/MoveSpline.cpp b/src/server/game/Movement/Spline/MoveSpline.cpp
new file mode 100644
index 00000000000..4eaa6b57b36
--- /dev/null
+++ b/src/server/game/Movement/Spline/MoveSpline.cpp
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "MoveSpline.h"
+#include <sstream>
+#include "Log.h"
+
+namespace Movement{
+
+extern float computeFallTime(float path_length, bool isSafeFall);
+extern float computeFallElevation(float time_passed, bool isSafeFall, float start_velocy);
+extern float computeFallElevation(float time_passed);
+
+Location MoveSpline::ComputePosition() const
+{
+ ASSERT(Initialized());
+
+ float u = 1.f;
+ int32 seg_time = spline.length(point_Idx,point_Idx+1);
+ if (seg_time > 0)
+ u = (time_passed - spline.length(point_Idx)) / (float)seg_time;
+ Location c;
+ c.orientation = initialOrientation;
+ spline.evaluate_percent(point_Idx, u, c);
+
+ if (splineflags.animation)
+ ;// MoveSplineFlag::Animation disables falling or parabolic movement
+ else if (splineflags.parabolic)
+ computeParabolicElevation(c.z);
+ else if (splineflags.falling)
+ computeFallElevation(c.z);
+
+ if (splineflags.done && splineflags.isFacing())
+ {
+ if (splineflags.final_angle)
+ c.orientation = facing.angle;
+ else if (splineflags.final_point)
+ c.orientation = atan2(facing.f.y-c.y, facing.f.x-c.x);
+ //nothing to do for MoveSplineFlag::Final_Target flag
+ }
+ else
+ {
+ if (!splineflags.hasFlag(MoveSplineFlag::OrientationFixed|MoveSplineFlag::Falling))
+ {
+ Vector3 hermite;
+ spline.evaluate_derivative(point_Idx,u,hermite);
+ c.orientation = atan2(hermite.y, hermite.x);
+ }
+
+ if (splineflags.orientationInversed)
+ c.orientation = -c.orientation;
+ }
+ return c;
+}
+
+void MoveSpline::computeParabolicElevation(float& el) const
+{
+ if (time_passed > effect_start_time)
+ {
+ float t_passedf = MSToSec(time_passed - effect_start_time);
+ float t_durationf = MSToSec(Duration() - effect_start_time); //client use not modified duration here
+
+ // -a*x*x + bx + c:
+ //(dur * v3->z_acceleration * dt)/2 - (v3->z_acceleration * dt * dt)/2 + Z;
+ el += (t_durationf - t_passedf) * 0.5f * vertical_acceleration * t_passedf;
+ }
+}
+
+void MoveSpline::computeFallElevation(float& el) const
+{
+ float z_now = spline.getPoint(spline.first()).z - Movement::computeFallElevation(MSToSec(time_passed));
+ float final_z = FinalDestination().z;
+ if (z_now < final_z)
+ el = final_z;
+ else
+ el = z_now;
+}
+
+inline uint32 computeDuration(float length, float velocity)
+{
+ return SecToMS(length / velocity);
+}
+
+struct FallInitializer
+{
+ FallInitializer(float _start_elevation) : start_elevation(_start_elevation) {}
+ float start_elevation;
+ inline int32 operator()(Spline<int32>& s, int32 i)
+ {
+ return Movement::computeFallTime(start_elevation - s.getPoint(i+1).z,false) * 1000.f;
+ }
+};
+
+enum{
+ minimal_duration = 1,
+};
+
+struct CommonInitializer
+{
+ CommonInitializer(float _velocity) : velocityInv(1000.f/_velocity), time(minimal_duration) {}
+ float velocityInv;
+ int32 time;
+ inline int32 operator()(Spline<int32>& s, int32 i)
+ {
+ time += (s.SegLength(i) * velocityInv);
+ return time;
+ }
+};
+
+void MoveSpline::init_spline(const MoveSplineInitArgs& args)
+{
+ const SplineBase::EvaluationMode modes[2] = {SplineBase::ModeLinear,SplineBase::ModeCatmullrom};
+ if (args.flags.cyclic)
+ {
+ uint32 cyclic_point = 0;
+ // MoveSplineFlag::Enter_Cycle support dropped
+ //if (splineflags & SPLINEFLAG_ENTER_CYCLE)
+ //cyclic_point = 1; // shouldn't be modified, came from client
+ spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point);
+ }
+ else
+ {
+ spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()]);
+ }
+
+ // init spline timestamps
+ if (splineflags.falling)
+ {
+ FallInitializer init(spline.getPoint(spline.first()).z);
+ spline.initLengths(init);
+ }
+ else
+ {
+ CommonInitializer init(args.velocity);
+ spline.initLengths(init);
+ }
+
+ // TODO: what to do in such cases? problem is in input data (all points are at same coords)
+ if (spline.length() < minimal_duration)
+ {
+ sLog->outError("MoveSpline::init_spline: zero length spline, wrong input data?");
+ spline.set_length(spline.last(), spline.isCyclic() ? 1000 : 1);
+ }
+ point_Idx = spline.first();
+}
+
+void MoveSpline::Initialize(const MoveSplineInitArgs& args)
+{
+ splineflags = args.flags;
+ facing = args.facing;
+ m_Id = args.splineId;
+ point_Idx_offset = args.path_Idx_offset;
+ initialOrientation = args.initialOrientation;
+
+ time_passed = 0;
+ vertical_acceleration = 0.f;
+ effect_start_time = 0;
+
+ init_spline(args);
+
+ // init parabolic / animation
+ // spline initialized, duration known and i able to compute parabolic acceleration
+ if (args.flags & (MoveSplineFlag::Parabolic | MoveSplineFlag::Animation))
+ {
+ effect_start_time = Duration() * args.time_perc;
+ if (args.flags.parabolic && effect_start_time < Duration())
+ {
+ float f_duration = MSToSec(Duration() - effect_start_time);
+ vertical_acceleration = args.parabolic_amplitude * 8.f / (f_duration * f_duration);
+ }
+ }
+}
+
+MoveSpline::MoveSpline() : m_Id(0), time_passed(0),
+ vertical_acceleration(0.f), effect_start_time(0), point_Idx(0), point_Idx_offset(0), initialOrientation(0.f)
+{
+ splineflags.done = true;
+}
+
+/// ============================================================================================
+
+bool MoveSplineInitArgs::Validate() const
+{
+#define CHECK(exp) \
+ if (!(exp))\
+ {\
+ sLog->outError("MoveSplineInitArgs::Validate: expression '%s' failed", #exp);\
+ return false;\
+ }
+ CHECK(path.size() > 1);
+ CHECK(velocity > 0.f);
+ CHECK(time_perc >= 0.f && time_perc <= 1.f);
+ //CHECK(_checkPathBounds());
+ return true;
+#undef CHECK
+}
+
+// MONSTER_MOVE packet format limitation for not CatmullRom movement:
+// each vertex offset packed into 11 bytes
+bool MoveSplineInitArgs::_checkPathBounds() const
+{
+ if (!(flags & MoveSplineFlag::Mask_CatmullRom) && path.size() > 2)
+ {
+ enum{
+ MAX_OFFSET = (1 << 11) / 2,
+ };
+ Vector3 middle = (path.front()+path.back()) / 2;
+ Vector3 offset;
+ for (uint32 i = 1; i < path.size()-1; ++i)
+ {
+ offset = path[i] - middle;
+ if (fabs(offset.x) >= MAX_OFFSET || fabs(offset.y) >= MAX_OFFSET || fabs(offset.z) >= MAX_OFFSET)
+ {
+ sLog->outError("MoveSplineInitArgs::_checkPathBounds check failed");
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/// ============================================================================================
+
+MoveSpline::UpdateResult MoveSpline::_updateState(int32& ms_time_diff)
+{
+ if (Finalized())
+ {
+ ms_time_diff = 0;
+ return Result_Arrived;
+ }
+
+ UpdateResult result = Result_None;
+
+ int32 minimal_diff = std::min(ms_time_diff, segment_time_elapsed());
+ ASSERT(minimal_diff >= 0);
+ time_passed += minimal_diff;
+ ms_time_diff -= minimal_diff;
+
+ if (time_passed >= next_timestamp())
+ {
+ ++point_Idx;
+ if (point_Idx < spline.last())
+ {
+ result = Result_NextSegment;
+ }
+ else
+ {
+ if (spline.isCyclic())
+ {
+ point_Idx = spline.first();
+ time_passed = time_passed % Duration();
+ result = Result_NextSegment;
+ }
+ else
+ {
+ _Finalize();
+ ms_time_diff = 0;
+ result = Result_Arrived;
+ }
+ }
+ }
+
+ return result;
+}
+
+std::string MoveSpline::ToString() const
+{
+ std::stringstream str;
+ str << "MoveSpline" << std::endl;
+ str << "spline Id: " << GetId() << std::endl;
+ str << "flags: " << splineflags.ToString() << std::endl;
+ if (splineflags.final_angle)
+ str << "facing angle: " << facing.angle;
+ else if (splineflags.final_target)
+ str << "facing target: " << facing.target;
+ else if(splineflags.final_point)
+ str << "facing point: " << facing.f.x << " " << facing.f.y << " " << facing.f.z;
+ str << std::endl;
+ str << "time passed: " << time_passed << std::endl;
+ str << "total time: " << Duration() << std::endl;
+ str << "spline point Id: " << point_Idx << std::endl;
+ str << "path point Id: " << currentPathIdx() << std::endl;
+ str << spline.ToString();
+ return str.str();
+}
+
+void MoveSpline::_Finalize()
+{
+ splineflags.done = true;
+ point_Idx = spline.last() - 1;
+ time_passed = Duration();
+}
+
+int32 MoveSpline::currentPathIdx() const
+{
+ int32 point = point_Idx_offset + point_Idx - spline.first() + (int)Finalized();
+ if (isCyclic())
+ point = point % (spline.last()-spline.first());
+ return point;
+}
+}
diff --git a/src/server/game/Movement/Spline/MoveSpline.h b/src/server/game/Movement/Spline/MoveSpline.h
new file mode 100644
index 00000000000..4b8dbcc8ee3
--- /dev/null
+++ b/src/server/game/Movement/Spline/MoveSpline.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TRINITYSERVER_MOVEPLINE_H
+#define TRINITYSERVER_MOVEPLINE_H
+
+#include "Spline.h"
+#include "MoveSplineInitArgs.h"
+
+namespace Movement
+{
+ struct Location : public Vector3
+ {
+ Location() : orientation(0) {}
+ Location(float x, float y, float z, float o) : Vector3(x,y,z), orientation(o) {}
+ Location(const Vector3& v) : Vector3(v), orientation(0) {}
+ Location(const Vector3& v, float o) : Vector3(v), orientation(o) {}
+
+ float orientation;
+ };
+
+ // MoveSpline represents smooth catmullrom or linear curve and point that moves belong it
+ // curve can be cyclic - in this case movement will be cyclic
+ // point can have vertical acceleration motion componemt(used in fall, parabolic movement)
+ class MoveSpline
+ {
+ public:
+ typedef Spline<int32> MySpline;
+ enum UpdateResult{
+ Result_None = 0x01,
+ Result_Arrived = 0x02,
+ Result_NextCycle = 0x04,
+ Result_NextSegment = 0x08,
+ };
+ #pragma region fields
+ friend class PacketBuilder;
+ protected:
+ MySpline spline;
+
+ FacingInfo facing;
+
+ uint32 m_Id;
+
+ MoveSplineFlag splineflags;
+
+ int32 time_passed;
+ // currently duration mods are unused, but its _currently_
+ //float duration_mod;
+ //float duration_mod_next;
+ float vertical_acceleration;
+ float initialOrientation;
+ int32 effect_start_time;
+ int32 point_Idx;
+ int32 point_Idx_offset;
+
+ void init_spline(const MoveSplineInitArgs& args);
+ protected:
+
+ const MySpline::ControlArray& getPath() const { return spline.getPoints();}
+ void computeParabolicElevation(float& el) const;
+ void computeFallElevation(float& el) const;
+
+ UpdateResult _updateState(int32& ms_time_diff);
+ int32 next_timestamp() const { return spline.length(point_Idx+1);}
+ int32 segment_time_elapsed() const { return next_timestamp()-time_passed;}
+ int32 Duration() const { return spline.length();}
+ int32 timeElapsed() const { return Duration() - time_passed;}
+ int32 timePassed() const { return time_passed;}
+
+ public:
+ const MySpline& _Spline() const { return spline;}
+ int32 _currentSplineIdx() const { return point_Idx;}
+ void _Finalize();
+ void _Interrupt() { splineflags.done = true;}
+
+ #pragma endregion
+ public:
+
+ void Initialize(const MoveSplineInitArgs&);
+ bool Initialized() const { return !spline.empty();}
+
+ explicit MoveSpline();
+
+ template<class UpdateHandler>
+ void updateState(int32 difftime, UpdateHandler& handler)
+ {
+ ASSERT(Initialized());
+ do
+ handler(_updateState(difftime));
+ while(difftime > 0);
+ }
+
+ void updateState(int32 difftime)
+ {
+ ASSERT(Initialized());
+ do _updateState(difftime);
+ while(difftime > 0);
+ }
+
+ Location ComputePosition() const;
+
+ uint32 GetId() const { return m_Id;}
+ bool Finalized() const { return splineflags.done; }
+ bool isCyclic() const { return splineflags.cyclic;}
+ const Vector3 FinalDestination() const { return Initialized() ? spline.getPoint(spline.last()) : Vector3();}
+ const Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx+1) : Vector3();}
+ int32 currentPathIdx() const;
+
+ std::string ToString() const;
+ };
+}
+#endif // TRINITYSERVER_MOVEPLINE_H
diff --git a/src/server/game/Movement/Spline/MoveSplineFlag.h b/src/server/game/Movement/Spline/MoveSplineFlag.h
new file mode 100644
index 00000000000..de91f63c30a
--- /dev/null
+++ b/src/server/game/Movement/Spline/MoveSplineFlag.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TRINITYSERVER_MOVESPLINEFLAG_H
+#define TRINITYSERVER_MOVESPLINEFLAG_H
+#include "MovementTypedefs.h"
+
+#include <string>
+
+namespace Movement
+{
+#if defined( __GNUC__ )
+#pragma pack(1)
+#else
+#pragma pack(push,1)
+#endif
+
+ class MoveSplineFlag
+ {
+ public:
+ enum eFlags{
+ None = 0x00000000,
+ // x00-xFF(first byte) used as animation Ids storage in pair with Animation flag
+ Done = 0x00000100,
+ Falling = 0x00000200, // Affects elevation computation, can't be combined with Parabolic flag
+ No_Spline = 0x00000400,
+ Parabolic = 0x00000800, // Affects elevation computation, can't be combined with Falling flag
+ Walkmode = 0x00001000,
+ Flying = 0x00002000, // Smooth movement(Catmullrom interpolation mode), flying animation
+ OrientationFixed = 0x00004000, // Model orientation fixed
+ Final_Point = 0x00008000,
+ Final_Target = 0x00010000,
+ Final_Angle = 0x00020000,
+ Catmullrom = 0x00040000, // Used Catmullrom interpolation mode
+ Cyclic = 0x00080000, // Movement by cycled spline
+ Enter_Cycle = 0x00100000, // Everytimes appears with cyclic flag in monster move packet, erases first spline vertex after first cycle done
+ Animation = 0x00200000, // Plays animation after some time passed
+ Frozen = 0x00400000, // Will never arrive
+ Unknown5 = 0x00800000,
+ Unknown6 = 0x01000000,
+ Unknown7 = 0x02000000,
+ Unknown8 = 0x04000000,
+ OrientationInversed = 0x08000000,
+ Unknown10 = 0x10000000,
+ Unknown11 = 0x20000000,
+ Unknown12 = 0x40000000,
+ Unknown13 = 0x80000000,
+
+ // Masks
+ Mask_Final_Facing = Final_Point | Final_Target | Final_Angle,
+ // animation ids stored here, see AnimType enum, used with Animation flag
+ Mask_Animations = 0xFF,
+ // flags that shouldn't be appended into SMSG_MONSTER_MOVE\SMSG_MONSTER_MOVE_TRANSPORT packet, should be more probably
+ Mask_No_Monster_Move = Mask_Final_Facing | Mask_Animations | Done,
+ // CatmullRom interpolation mode used
+ Mask_CatmullRom = Flying | Catmullrom,
+ // Unused, not suported flags
+ Mask_Unused = No_Spline|Enter_Cycle|Frozen|Unknown5|Unknown6|Unknown7|Unknown8|Unknown10|Unknown11|Unknown12|Unknown13,
+ };
+
+ inline uint32& raw() { return (uint32&)*this;}
+ inline const uint32& raw() const { return (const uint32&)*this;}
+
+ MoveSplineFlag() { raw() = 0; }
+ MoveSplineFlag(uint32 f) { raw() = f; }
+ MoveSplineFlag(const MoveSplineFlag& f) { raw() = f.raw(); }
+
+ // Constant interface
+
+ bool isSmooth() const { return raw() & Mask_CatmullRom;}
+ bool isLinear() const { return !isSmooth();}
+ bool isFacing() const { return raw() & Mask_Final_Facing;}
+
+ uint8 getAnimationId() const { return animId;}
+ bool hasAllFlags(uint32 f) const { return (raw() & f) == f;}
+ bool hasFlag(uint32 f) const { return (raw() & f) != 0;}
+ uint32 operator & (uint32 f) const { return (raw() & f);}
+ uint32 operator | (uint32 f) const { return (raw() | f);}
+ std::string ToString() const;
+
+ // Not constant interface
+
+ void operator &= (uint32 f) { raw() &= f;}
+ void operator |= (uint32 f) { raw() |= f;}
+
+ void EnableAnimation(uint8 anim) { raw() = raw() & ~(Mask_Animations|Falling|Parabolic) | Animation|anim;}
+ void EnableParabolic() { raw() = raw() & ~(Mask_Animations|Falling|Animation) | Parabolic;}
+ void EnableFalling() { raw() = raw() & ~(Mask_Animations|Parabolic|Animation) | Falling;}
+ void EnableFlying() { raw() = raw() & ~Catmullrom | Flying; }
+ void EnableCatmullRom() { raw() = raw() & ~Flying | Catmullrom; }
+ void EnableFacingPoint() { raw() = raw() & ~Mask_Final_Facing | Final_Point;}
+ void EnableFacingAngle() { raw() = raw() & ~Mask_Final_Facing | Final_Angle;}
+ void EnableFacingTarget() { raw() = raw() & ~Mask_Final_Facing | Final_Target;}
+
+ uint8 animId : 8;
+ bool done : 1;
+ bool falling : 1;
+ bool no_spline : 1;
+ bool parabolic : 1;
+ bool walkmode : 1;
+ bool flying : 1;
+ bool orientationFixed : 1;
+ bool final_point : 1;
+ bool final_target : 1;
+ bool final_angle : 1;
+ bool catmullrom : 1;
+ bool cyclic : 1;
+ bool enter_cycle : 1;
+ bool animation : 1;
+ bool frozen : 1;
+ bool unknown5 : 1;
+ bool unknown6 : 1;
+ bool unknown7 : 1;
+ bool unknown8 : 1;
+ bool orientationInversed : 1;
+ bool unknown10 : 1;
+ bool unknown11 : 1;
+ bool unknown12 : 1;
+ bool unknown13 : 1;
+ };
+#if defined( __GNUC__ )
+#pragma pack()
+#else
+#pragma pack(pop)
+#endif
+}
+
+#endif // TRINITYSERVER_MOVESPLINEFLAG_H
diff --git a/src/server/game/Movement/Spline/MoveSplineInit.cpp b/src/server/game/Movement/Spline/MoveSplineInit.cpp
new file mode 100644
index 00000000000..b5ae923dc32
--- /dev/null
+++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "MoveSplineInit.h"
+#include "MoveSpline.h"
+#include "MovementPacketBuilder.h"
+#include "Unit.h"
+
+namespace Movement
+{
+ UnitMoveType SelectSpeedType(uint32 moveFlags)
+ {
+ if (moveFlags & MOVEMENTFLAG_FLYING)
+ {
+ if ( moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.flight >= speed_obj.flight_back*/ )
+ return MOVE_FLIGHT_BACK;
+ else
+ return MOVE_FLIGHT;
+ }
+ else if (moveFlags & MOVEMENTFLAG_SWIMMING)
+ {
+ if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.swim >= speed_obj.swim_back*/)
+ return MOVE_SWIM_BACK;
+ else
+ return MOVE_SWIM;
+ }
+ else if (moveFlags & MOVEMENTFLAG_WALKING)
+ {
+ //if ( speed_obj.run > speed_obj.walk )
+ return MOVE_WALK;
+ }
+ else if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.run >= speed_obj.run_back*/)
+ return MOVE_RUN_BACK;
+
+ return MOVE_RUN;
+ }
+
+ void MoveSplineInit::Launch()
+ {
+ MoveSpline& move_spline = *unit.movespline;
+
+ Location real_position(unit.GetPositionX(),unit.GetPositionY(),unit.GetPositionZ(),unit.GetOrientation());
+ // there is a big chane that current position is unknown if current state is not finalized, need compute it
+ // this also allows calculate spline position and update map position in much greater intervals
+ if (!move_spline.Finalized())
+ real_position = move_spline.ComputePosition();
+
+ if (args.path.empty())
+ {
+ // should i do the things that user should do?
+ MoveTo(real_position);
+ }
+
+ // corrent first vertex
+ args.path[0] = real_position;
+ args.initialOrientation = real_position.orientation;
+
+ uint32 moveFlags = unit.m_movementInfo.GetMovementFlags();
+ if (args.flags.walkmode)
+ moveFlags |= MOVEMENTFLAG_WALKING;
+ else
+ moveFlags &= ~MOVEMENTFLAG_WALKING;
+
+ moveFlags |= (MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD);
+
+ if (args.velocity == 0.f)
+ args.velocity = unit.GetSpeed(SelectSpeedType(moveFlags));
+
+ if (!args.Validate())
+ return;
+
+ if (moveFlags & MOVEMENTFLAG_ROOT)
+ moveFlags &= ~MOVEMENTFLAG_MASK_MOVING;
+
+ unit.m_movementInfo.SetMovementFlags((MovementFlags)moveFlags);
+ move_spline.Initialize(args);
+
+ WorldPacket data(SMSG_MONSTER_MOVE, 64);
+ data.append(unit.GetPackGUID());
+ PacketBuilder::WriteMonsterMove(move_spline, data);
+ unit.SendMessageToSet(&data,true);
+ }
+
+ MoveSplineInit::MoveSplineInit(Unit& m) : unit(m)
+ {
+ // mix existing state into new
+ args.flags.walkmode = unit.m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING);
+ args.flags.flying = unit.m_movementInfo.HasMovementFlag((MovementFlags)(MOVEMENTFLAG_FLYING|MOVEMENTFLAG_LEVITATING));
+ }
+
+ void MoveSplineInit::SetFacing(const Unit * target)
+ {
+ args.flags.EnableFacingTarget();
+ //args.facing.target = target->GetObjectGuid().GetRawValue();
+ args.facing.target = target->GetUInt64Value(OBJECT_FIELD_GUID);
+ }
+
+ void MoveSplineInit::SetFacing(float angle)
+ {
+ args.facing.angle = G3D::wrap(angle, 0.f, (float)G3D::twoPi());
+ args.flags.EnableFacingAngle();
+ }
+}
diff --git a/src/server/game/Movement/Spline/MoveSplineInit.h b/src/server/game/Movement/Spline/MoveSplineInit.h
new file mode 100644
index 00000000000..7ef6cd7a120
--- /dev/null
+++ b/src/server/game/Movement/Spline/MoveSplineInit.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TRINITYSERVER_MOVESPLINEINIT_H
+#define TRINITYSERVER_MOVESPLINEINIT_H
+
+#include "MoveSplineInitArgs.h"
+
+class Unit;
+
+namespace Movement
+{
+ enum AnimType
+ {
+ ToGround = 0, // 460 = ToGround, index of AnimationData.dbc
+ FlyToFly = 1, // 461 = FlyToFly?
+ ToFly = 2, // 458 = ToFly
+ FlyToGround = 3, // 463 = FlyToGround
+ };
+
+ /* Initializes and launches spline movement
+ */
+ class MoveSplineInit
+ {
+ public:
+
+ explicit MoveSplineInit(Unit& m);
+
+ /* Final pass of initialization that launches spline movement.
+ */
+ void Launch();
+
+ /* Adds movement by parabolic trajectory
+ * @param amplitude - the maximum height of parabola, value could be negative and positive
+ * @param start_time - delay between movement starting time and beginning to move by parabolic trajectory
+ * can't be combined with final animation
+ */
+ void SetParabolic(float amplitude, float start_time);
+ /* Plays animation after movement done
+ * can't be combined with parabolic movement
+ */
+ void SetAnimation(AnimType anim);
+
+ /* Adds final facing animation
+ * sets unit's facing to specified point/angle after all path done
+ * you can have only one final facing: previous will be overriden
+ */
+ void SetFacing(float angle);
+ void SetFacing(Vector3 const& point);
+ void SetFacing(const Unit * target);
+
+ /* Initializes movement by path
+ * @param path - array of points, shouldn't be empty
+ * @param pointId - Id of fisrt point of the path. Example: when third path point will be done it will notify that pointId + 3 done
+ */
+ void MovebyPath(const PointsArray& path, int32 pointId = 0);
+
+ /* Initializes simple A to B mition, A is current unit's position, B is destination
+ */
+ void MoveTo(const Vector3& destination);
+ void MoveTo(float x, float y, float z);
+
+ /* Sets Id of fisrt point of the path. When N-th path point will be done ILisener will notify that pointId + N done
+ * Needed for waypoint movement where path splitten into parts
+ */
+ void SetFirstPointId(int32 pointId) { args.path_Idx_offset = pointId; }
+
+ /* Enables CatmullRom spline interpolation mode(makes path smooth)
+ * if not enabled linear spline mode will be choosen. Disabled by default
+ */
+ void SetSmooth();
+ /* Enables CatmullRom spline interpolation mode, enables flying animation. Disabled by default
+ */
+ void SetFly();
+ /* Enables walk mode. Disabled by default
+ */
+ void SetWalk(bool enable);
+ /* Makes movement cyclic. Disabled by default
+ */
+ void SetCyclic();
+ /* Enables falling mode. Disabled by default
+ */
+ void SetFall();
+ /* Inverses unit model orientation. Disabled by default
+ */
+ void SetOrientationInversed();
+ /* Fixes unit's model rotation. Disabled by default
+ */
+ void SetOrientationFixed(bool enable);
+
+ /* Sets the velocity (in case you want to have custom movement velocity)
+ * if no set, speed will be selected based on unit's speeds and current movement mode
+ * Has no effect if falling mode enabled
+ * velocity shouldn't be negative
+ */
+ void SetVelocity(float velocity);
+
+ PointsArray& Path() { return args.path; }
+
+ protected:
+
+ MoveSplineInitArgs args;
+ Unit& unit;
+ };
+
+ inline void MoveSplineInit::SetFly() { args.flags.EnableFlying();}
+ inline void MoveSplineInit::SetWalk(bool enable) { args.flags.walkmode = enable;}
+ inline void MoveSplineInit::SetSmooth() { args.flags.EnableCatmullRom();}
+ inline void MoveSplineInit::SetCyclic() { args.flags.cyclic = true;}
+ inline void MoveSplineInit::SetFall() { args.flags.EnableFalling();}
+ inline void MoveSplineInit::SetVelocity(float vel){ args.velocity = vel;}
+ inline void MoveSplineInit::SetOrientationInversed() { args.flags.orientationInversed = true;}
+ inline void MoveSplineInit::SetOrientationFixed(bool enable) { args.flags.orientationFixed = enable;}
+
+ inline void MoveSplineInit::MovebyPath(const PointsArray& controls, int32 path_offset)
+ {
+ args.path_Idx_offset = path_offset;
+ args.path.assign(controls.begin(),controls.end());
+ }
+
+ inline void MoveSplineInit::MoveTo(float x, float y, float z)
+ {
+ Vector3 v(x,y,z);
+ MoveTo(v);
+ }
+
+ inline void MoveSplineInit::MoveTo(const Vector3& dest)
+ {
+ args.path_Idx_offset = 0;
+ args.path.resize(2);
+ args.path[1] = dest;
+ }
+
+ inline void MoveSplineInit::SetParabolic(float amplitude, float time_shift)
+ {
+ args.time_perc = time_shift;
+ args.parabolic_amplitude = amplitude;
+ args.flags.EnableParabolic();
+ }
+
+ inline void MoveSplineInit::SetAnimation(AnimType anim)
+ {
+ args.time_perc = 0.f;
+ args.flags.EnableAnimation((uint8)anim);
+ }
+
+ inline void MoveSplineInit::SetFacing(Vector3 const& spot)
+ {
+ args.facing.f.x = spot.x;
+ args.facing.f.y = spot.y;
+ args.facing.f.z = spot.z;
+ args.flags.EnableFacingPoint();
+ }
+}
+#endif // TRINITYSERVER_MOVESPLINEINIT_H
diff --git a/src/server/game/Movement/Spline/MoveSplineInitArgs.h b/src/server/game/Movement/Spline/MoveSplineInitArgs.h
new file mode 100644
index 00000000000..26fbbdd0fcc
--- /dev/null
+++ b/src/server/game/Movement/Spline/MoveSplineInitArgs.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TRINITYSERVER_MOVESPLINEINIT_ARGS_H
+#define TRINITYSERVER_MOVESPLINEINIT_ARGS_H
+
+#include "MoveSplineFlag.h"
+#include <G3D/Vector3.h>
+
+namespace Movement
+{
+ typedef std::vector<Vector3> PointsArray;
+
+ union FacingInfo
+ {
+ struct{
+ float x,y,z;
+ }f;
+ uint64 target;
+ float angle;
+
+ FacingInfo(float o) : angle(o) {}
+ FacingInfo(uint64 t) : target(t) {}
+ FacingInfo() {}
+ };
+
+ struct MoveSplineInitArgs
+ {
+ MoveSplineInitArgs(size_t path_capacity = 16) : path_Idx_offset(0),
+ velocity(0.f), parabolic_amplitude(0.f), time_perc(0.f), splineId(0), initialOrientation(0.f)
+ {
+ path.reserve(path_capacity);
+ }
+
+ PointsArray path;
+ FacingInfo facing;
+ MoveSplineFlag flags;
+ int32 path_Idx_offset;
+ float velocity;
+ float parabolic_amplitude;
+ float time_perc;
+ uint32 splineId;
+ float initialOrientation;
+
+ /** Returns true to show that the arguments were configured correctly and MoveSpline initialization will succeed. */
+ bool Validate() const;
+ private:
+ bool _checkPathBounds() const;
+ };
+}
+
+#endif // TRINITYSERVER_MOVESPLINEINIT_ARGS_H
diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp
new file mode 100644
index 00000000000..73fdbf4c2f6
--- /dev/null
+++ b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "MovementPacketBuilder.h"
+#include "MoveSpline.h"
+#include "WorldPacket.h"
+
+namespace Movement
+{
+ inline void operator << (ByteBuffer& b, const Vector3& v)
+ {
+ b << v.x << v.y << v.z;
+ }
+
+ inline void operator >> (ByteBuffer& b, Vector3& v)
+ {
+ b >> v.x >> v.y >> v.z;
+ }
+
+ enum MonsterMoveType
+ {
+ MonsterMoveNormal = 0,
+ MonsterMoveStop = 1,
+ MonsterMoveFacingSpot = 2,
+ MonsterMoveFacingTarget = 3,
+ MonsterMoveFacingAngle = 4
+ };
+
+ void PacketBuilder::WriteCommonMonsterMovePart(const MoveSpline& move_spline, WorldPacket& data)
+ {
+ MoveSplineFlag splineflags = move_spline.splineflags;
+ /*if (mov.IsBoarded())
+ {
+ data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT);
+ data << mov.GetTransport()->Owner.GetPackGUID();
+ data << int8(mov.m_unused.transport_seat);
+ }*/
+
+ data << uint8(0);
+ data << move_spline.spline.getPoint(move_spline.spline.first());
+ data << move_spline.GetId();
+
+ switch(splineflags & MoveSplineFlag::Mask_Final_Facing)
+ {
+ default:
+ data << uint8(MonsterMoveNormal);
+ break;
+ case MoveSplineFlag::Final_Target:
+ data << uint8(MonsterMoveFacingTarget);
+ data << move_spline.facing.target;
+ break;
+ case MoveSplineFlag::Final_Angle:
+ data << uint8(MonsterMoveFacingAngle);
+ data << move_spline.facing.angle;
+ break;
+ case MoveSplineFlag::Final_Point:
+ data << uint8(MonsterMoveFacingSpot);
+ data << move_spline.facing.f.x << move_spline.facing.f.y << move_spline.facing.f.z;
+ break;
+ }
+
+ // add fake Enter_Cycle flag - needed for client-side cyclic movement (client will erase first spline vertex after first cycle done)
+ splineflags.enter_cycle = move_spline.isCyclic();
+ data << uint32(splineflags & ~MoveSplineFlag::Mask_No_Monster_Move);
+
+ if (splineflags.animation)
+ {
+ data << splineflags.getAnimationId();
+ data << move_spline.effect_start_time;
+ }
+
+ data << move_spline.Duration();
+
+ if (splineflags.parabolic)
+ {
+ data << move_spline.vertical_acceleration;
+ data << move_spline.effect_start_time;
+ }
+ }
+
+ void WriteLinearPath(const Spline<int32>& spline, ByteBuffer& data)
+ {
+ uint32 last_idx = spline.getPointCount() - 3;
+ const Vector3 * real_path = &spline.getPoint(1);
+
+ data << last_idx;
+ data << real_path[last_idx]; // destination
+ if (last_idx > 1)
+ {
+ Vector3 middle = (real_path[0] + real_path[last_idx]) / 2.f;
+ Vector3 offset;
+ // first and last points already appended
+ for(uint32 i = 1; i < last_idx; ++i)
+ {
+ offset = middle - real_path[i];
+ data.appendPackXYZ(offset.x, offset.y, offset.z);
+ }
+ }
+ }
+
+ void WriteCatmullRomPath(const Spline<int32>& spline, ByteBuffer& data)
+ {
+ uint32 count = spline.getPointCount() - 3;
+ data << count;
+ data.append<Vector3>(&spline.getPoint(2), count);
+ }
+
+ void WriteCatmullRomCyclicPath(const Spline<int32>& spline, ByteBuffer& data)
+ {
+ uint32 count = spline.getPointCount() - 3;
+ data << uint32(count + 1);
+ data << spline.getPoint(1); // fake point, client will erase it from the spline after first cycle done
+ data.append<Vector3>(&spline.getPoint(1), count);
+ }
+
+ void PacketBuilder::WriteMonsterMove(const MoveSpline& move_spline, WorldPacket& data)
+ {
+ WriteCommonMonsterMovePart(move_spline, data);
+
+ const Spline<int32>& spline = move_spline.spline;
+ MoveSplineFlag splineflags = move_spline.splineflags;
+ if (splineflags & MoveSplineFlag::Mask_CatmullRom)
+ {
+ if (splineflags.cyclic)
+ WriteCatmullRomCyclicPath(spline, data);
+ else
+ WriteCatmullRomPath(spline, data);
+ }
+ else
+ WriteLinearPath(spline, data);
+ }
+
+ void PacketBuilder::WriteCreate(const MoveSpline& move_spline, ByteBuffer& data)
+ {
+ //WriteClientStatus(mov,data);
+ //data.append<float>(&mov.m_float_values[SpeedWalk], SpeedMaxCount);
+ //if (mov.SplineEnabled())
+ {
+ MoveSplineFlag splineFlags = move_spline.splineflags;
+
+ data << splineFlags.raw();
+
+ if (splineFlags.final_angle)
+ {
+ data << move_spline.facing.angle;
+ }
+ else if (splineFlags.final_target)
+ {
+ data << move_spline.facing.target;
+ }
+ else if(splineFlags.final_point)
+ {
+ data << move_spline.facing.f.x << move_spline.facing.f.y << move_spline.facing.f.z;
+ }
+
+ data << move_spline.timePassed();
+ data << move_spline.Duration();
+ data << move_spline.GetId();
+
+ data << float(1.f); // splineInfo.duration_mod; added in 3.1
+ data << float(1.f); // splineInfo.duration_mod_next; added in 3.1
+
+ data << move_spline.vertical_acceleration; // added in 3.1
+ data << move_spline.effect_start_time; // added in 3.1
+
+ uint32 nodes = move_spline.getPath().size();
+ data << nodes;
+ data.append<Vector3>(&move_spline.getPath()[0], nodes);
+ data << uint8(move_spline.spline.mode()); // added in 3.1
+ data << (move_spline.isCyclic() ? Vector3::zero() : move_spline.FinalDestination());
+ }
+ }
+}
diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.h b/src/server/game/Movement/Spline/MovementPacketBuilder.h
new file mode 100644
index 00000000000..92a414e9b3b
--- /dev/null
+++ b/src/server/game/Movement/Spline/MovementPacketBuilder.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TRINITYSERVER_PACKET_BUILDER_H
+#define TRINITYSERVER_PACKET_BUILDER_H
+
+class ByteBuffer;
+class WorldPacket;
+
+namespace Movement
+{
+ class MoveSpline;
+ class PacketBuilder
+ {
+ static void WriteCommonMonsterMovePart(const MoveSpline& mov, WorldPacket& data);
+ public:
+
+ static void WriteMonsterMove(const MoveSpline& mov, WorldPacket& data);
+ static void WriteCreate(const MoveSpline& mov, ByteBuffer& data);
+ };
+}
+#endif // TRINITYSERVER_PACKET_BUILDER_H
diff --git a/src/server/game/Movement/Spline/MovementTypedefs.h b/src/server/game/Movement/Spline/MovementTypedefs.h
new file mode 100644
index 00000000000..01c8a5b7e7b
--- /dev/null
+++ b/src/server/game/Movement/Spline/MovementTypedefs.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TRINITYSERVER_TYPEDEFS_H
+#define TRINITYSERVER_TYPEDEFS_H
+
+#include "Common.h"
+
+namespace G3D
+{
+ class Vector2;
+ class Vector3;
+ class Vector4;
+}
+
+namespace Movement
+{
+ using G3D::Vector2;
+ using G3D::Vector3;
+ using G3D::Vector4;
+
+ inline uint32 SecToMS(float sec)
+ {
+ return static_cast<uint32>(sec * 1000.f);
+ }
+
+ inline float MSToSec(uint32 ms)
+ {
+ return ms / 1000.f;
+ }
+
+#ifndef static_assert
+ #define CONCAT(x, y) CONCAT1 (x, y)
+ #define CONCAT1(x, y) x##y
+ #define static_assert(expr, msg) typedef char CONCAT(static_assert_failed_at_line_, __LINE__) [(expr) ? 1 : -1]
+#endif
+
+ template<class T, T limit>
+ class counter
+ {
+ public:
+ counter() { init();}
+
+ void Increase()
+ {
+ if (m_counter == limit)
+ init();
+ else
+ ++m_counter;
+ }
+
+ T NewId() { Increase(); return m_counter;}
+ T getCurrent() const { return m_counter;}
+
+ private:
+ void init() { m_counter = 0; }
+ T m_counter;
+ };
+
+ typedef counter<uint32, 0xFFFFFFFF> UInt32Counter;
+
+ extern double gravity;
+ extern float computeFallElevation(float t_passed, bool isSafeFall, float start_velocity);
+}
+
+#endif // TRINITYSERVER_TYPEDEFS_H
diff --git a/src/server/game/Movement/Spline/MovementUtil.cpp b/src/server/game/Movement/Spline/MovementUtil.cpp
new file mode 100644
index 00000000000..f0ed01c4676
--- /dev/null
+++ b/src/server/game/Movement/Spline/MovementUtil.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "MoveSplineFlag.h"
+#include <math.h>
+#include <string>
+
+namespace Movement
+{
+ double gravity = 19.29110527038574;
+
+ /// Velocity bounds that makes fall speed limited
+ float terminalVelocity = 60.148003f;
+ float terminalSavefallVelocity = 7.f;
+
+ const float terminal_length = float(terminalVelocity * terminalVelocity) / (2.f * gravity);
+ const float terminal_savefall_length = (terminalSavefallVelocity * terminalSavefallVelocity) / (2.f * gravity);
+ const float terminalFallTime = float(terminalVelocity/gravity); // the time that needed to reach terminalVelocity
+
+ float computeFallTime(float path_length, bool isSafeFall)
+ {
+ if (path_length < 0.f)
+ return 0.f;
+
+ float time;
+ if ( isSafeFall )
+ {
+ if (path_length >= terminal_savefall_length)
+ time = (path_length - terminal_savefall_length)/terminalSavefallVelocity + terminalSavefallVelocity/gravity;
+ else
+ time = sqrtf(2.f * path_length/gravity);
+ }
+ else
+ {
+ if (path_length >= terminal_length)
+ time = (path_length - terminal_length)/terminalVelocity + terminalFallTime;
+ else
+ time = sqrtf(2.f * path_length/gravity);
+ }
+
+ return time;
+ }
+
+ float computeFallElevation(float t_passed, bool isSafeFall, float start_velocity)
+ {
+ float termVel;
+ float result;
+
+ if ( isSafeFall )
+ termVel = terminalSavefallVelocity;
+ else
+ termVel = terminalVelocity;
+
+ if ( start_velocity > termVel )
+ start_velocity = termVel;
+
+ float terminal_time = terminalFallTime - start_velocity / gravity; // the time that needed to reach terminalVelocity
+
+ if ( t_passed > terminal_time )
+ {
+ result = terminalVelocity*(t_passed - terminal_time) +
+ start_velocity*terminal_time + gravity*terminal_time*terminal_time*0.5f;
+ }
+ else
+ result = t_passed * (start_velocity + t_passed * gravity * 0.5f);
+
+ return result;
+ }
+
+ float computeFallElevation(float t_passed)
+ {
+ float result;
+
+ if (t_passed > terminalFallTime)
+ {
+ //result = terminalVelocity * (t_passed - terminal_time) + gravity*terminal_time*terminal_time*0.5f;
+ // simplified view:
+ result = terminalVelocity * (t_passed - terminalFallTime) + terminal_length;
+ }
+ else
+ result = t_passed * t_passed * gravity * 0.5f;
+
+ return result;
+ }
+
+ #define STR(x) #x
+
+ const char * g_MovementFlag_names[]=
+ {
+ STR(Forward ),// 0x00000001,
+ STR(Backward ),// 0x00000002,
+ STR(Strafe_Left ),// 0x00000004,
+ STR(Strafe_Right ),// 0x00000008,
+ STR(Turn_Left ),// 0x00000010,
+ STR(Turn_Right ),// 0x00000020,
+ STR(Pitch_Up ),// 0x00000040,
+ STR(Pitch_Down ),// 0x00000080,
+
+ STR(Walk ),// 0x00000100, // Walking
+ STR(Ontransport ),// 0x00000200,
+ STR(Levitation ),// 0x00000400,
+ STR(Root ),// 0x00000800,
+ STR(Falling ),// 0x00001000,
+ STR(Fallingfar ),// 0x00002000,
+ STR(Pendingstop ),// 0x00004000,
+ STR(PendingSTRafestop ),// 0x00008000,
+ STR(Pendingforward ),// 0x00010000,
+ STR(Pendingbackward ),// 0x00020000,
+ STR(PendingSTRafeleft ),// 0x00040000,
+ STR(PendingSTRaferight ),// 0x00080000,
+ STR(Pendingroot ),// 0x00100000,
+ STR(Swimming ),// 0x00200000, // Appears With Fly Flag Also
+ STR(Ascending ),// 0x00400000, // Swim Up Also
+ STR(Descending ),// 0x00800000, // Swim Down Also
+ STR(Can_Fly ),// 0x01000000, // Can Fly In 3.3?
+ STR(Flying ),// 0x02000000, // Actual Flying Mode
+ STR(Spline_Elevation ),// 0x04000000, // Used For Flight Paths
+ STR(Spline_Enabled ),// 0x08000000, // Used For Flight Paths
+ STR(Waterwalking ),// 0x10000000, // Prevent Unit From Falling Through Water
+ STR(Safe_Fall ),// 0x20000000, // Active Rogue Safe Fall Spell (Passive)
+ STR(Hover ),// 0x40000000
+ STR(Unknown13 ),// 0x80000000
+ STR(Unk1 ),
+ STR(Unk2 ),
+ STR(Unk3 ),
+ STR(Fullspeedturning ),
+ STR(Fullspeedpitching ),
+ STR(Allow_Pitching ),
+ STR(Unk4 ),
+ STR(Unk5 ),
+ STR(Unk6 ),
+ STR(Unk7 ),
+ STR(Interp_Move ),
+ STR(Interp_Turning ),
+ STR(Interp_Pitching ),
+ STR(Unk8 ),
+ STR(Unk9 ),
+ STR(Unk10 ),
+ };
+
+ const char * g_SplineFlag_names[32]=
+ {
+ STR(AnimBit1 ),// 0x00000001,
+ STR(AnimBit2 ),// 0x00000002,
+ STR(AnimBit3 ),// 0x00000004,
+ STR(AnimBit4 ),// 0x00000008,
+ STR(AnimBit5 ),// 0x00000010,
+ STR(AnimBit6 ),// 0x00000020,
+ STR(AnimBit7 ),// 0x00000040,
+ STR(AnimBit8 ),// 0x00000080,
+ STR(Done ),// 0x00000100,
+ STR(Falling ),// 0x00000200, // Not Compartible With Trajectory Movement
+ STR(No_Spline ),// 0x00000400,
+ STR(Trajectory ),// 0x00000800, // Not Compartible With Fall Movement
+ STR(Walkmode ),// 0x00001000,
+ STR(Flying ),// 0x00002000, // Smooth Movement(Catmullrom Interpolation Mode), Flying Animation
+ STR(Knockback ),// 0x00004000, // Model Orientation Fixed
+ STR(Final_Point ),// 0x00008000,
+ STR(Final_Target ),// 0x00010000,
+ STR(Final_Angle ),// 0x00020000,
+ STR(Catmullrom ),// 0x00040000, // Used Catmullrom Interpolation Mode
+ STR(Cyclic ),// 0x00080000, // Movement By Cycled Spline
+ STR(Enter_Cycle ),// 0x00100000, // Everytime Appears With Cyclic Flag In Monster Move Packet
+ STR(Animation ),// 0x00200000, // Animationid (0...3), Uint32 Time, Not Compartible With Trajectory And Fall Movement
+ STR(Unknown4 ),// 0x00400000, // Disables Movement By Path
+ STR(Unknown5 ),// 0x00800000,
+ STR(Unknown6 ),// 0x01000000,
+ STR(Unknown7 ),// 0x02000000,
+ STR(Unknown8 ),// 0x04000000,
+ STR(OrientationInversed ),// 0x08000000, // Appears With Runmode Flag, Nodes ),// 1, Handles Orientation
+ STR(Unknown10 ),// 0x10000000,
+ STR(Unknown11 ),// 0x20000000,
+ STR(Unknown12 ),// 0x40000000,
+ STR(Unknown13 ),// 0x80000000,
+ };
+
+ template<class Flags, int N>
+ void print_flags(Flags t, const char* (&names)[N], std::string& str)
+ {
+ for (int i = 0; i < N; ++i)
+ {
+ if ((t & (Flags)(1 << i)) && names[i] != NULL)
+ str.append(" ").append(names[i]);
+ }
+ }
+
+ std::string MoveSplineFlag::ToString() const
+ {
+ std::string str;
+ print_flags(raw(),g_SplineFlag_names,str);
+ return str;
+ }
+}
diff --git a/src/server/game/Movement/Spline/Spline.cpp b/src/server/game/Movement/Spline/Spline.cpp
new file mode 100644
index 00000000000..14c1bd0c117
--- /dev/null
+++ b/src/server/game/Movement/Spline/Spline.cpp
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Spline.h"
+#include <sstream>
+#include <G3D/Matrix4.h>
+
+namespace Movement{
+
+SplineBase::EvaluationMethtod SplineBase::evaluators[SplineBase::ModesEnd] =
+{
+ &SplineBase::EvaluateLinear,
+ &SplineBase::EvaluateCatmullRom,
+ &SplineBase::EvaluateBezier3,
+ (EvaluationMethtod)&SplineBase::UninitializedSpline,
+};
+
+SplineBase::EvaluationMethtod SplineBase::derivative_evaluators[SplineBase::ModesEnd] =
+{
+ &SplineBase::EvaluateDerivativeLinear,
+ &SplineBase::EvaluateDerivativeCatmullRom,
+ &SplineBase::EvaluateDerivativeBezier3,
+ (EvaluationMethtod)&SplineBase::UninitializedSpline,
+};
+
+SplineBase::SegLenghtMethtod SplineBase::seglengths[SplineBase::ModesEnd] =
+{
+ &SplineBase::SegLengthLinear,
+ &SplineBase::SegLengthCatmullRom,
+ &SplineBase::SegLengthBezier3,
+ (SegLenghtMethtod)&SplineBase::UninitializedSpline,
+};
+
+SplineBase::InitMethtod SplineBase::initializers[SplineBase::ModesEnd] =
+{
+ //&SplineBase::InitLinear,
+ &SplineBase::InitCatmullRom, // we should use catmullrom initializer even for linear mode! (client's internal structure limitation)
+ &SplineBase::InitCatmullRom,
+ &SplineBase::InitBezier3,
+ (InitMethtod)&SplineBase::UninitializedSpline,
+};
+
+///////////
+#pragma region evaluation methtods
+
+using G3D::Matrix4;
+static const Matrix4 s_catmullRomCoeffs(
+ -0.5f, 1.5f,-1.5f, 0.5f,
+ 1.f, -2.5f, 2.f, -0.5f,
+ -0.5f, 0.f, 0.5f, 0.f,
+ 0.f, 1.f, 0.f, 0.f);
+
+static const Matrix4 s_Bezier3Coeffs(
+ -1.f, 3.f, -3.f, 1.f,
+ 3.f, -6.f, 3.f, 0.f,
+ -3.f, 3.f, 0.f, 0.f,
+ 1.f, 0.f, 0.f, 0.f);
+
+/* classic view:
+inline void C_Evaluate(const Vector3 *vertice, float t, const float (&matrix)[4][4], Vector3 &position)
+{
+ Vector3 tvec(t*t*t, t*t, t);
+ int i = 0;
+ double c;
+ double x = 0, y = 0, z = 0;
+ while ( i < 4 )
+ {
+ c = matrix[0][i]*tvec.x + matrix[1][i]*tvec.y + matrix[2][i]*tvec.z + matrix[3][i];
+
+ x += c * vertice->x;
+ y += c * vertice->y;
+ z += c * vertice->z;
+
+ ++i;
+ ++vertice;
+ }
+
+ position.x = x;
+ position.y = y;
+ position.z = z;
+}*/
+
+inline void C_Evaluate(const Vector3 *vertice, float t, const Matrix4& matr, Vector3 &result)
+{
+ Vector4 tvec(t*t*t, t*t, t, 1.f);
+ Vector4 weights(tvec * matr);
+
+ result = vertice[0] * weights[0] + vertice[1] * weights[1]
+ + vertice[2] * weights[2] + vertice[3] * weights[3];
+}
+
+inline void C_Evaluate_Derivative(const Vector3 *vertice, float t, const Matrix4& matr, Vector3 &result)
+{
+ Vector4 tvec(3.f*t*t, 2.f*t, 1.f, 0.f);
+ Vector4 weights(tvec * matr);
+
+ result = vertice[0] * weights[0] + vertice[1] * weights[1]
+ + vertice[2] * weights[2] + vertice[3] * weights[3];
+}
+
+void SplineBase::EvaluateLinear(index_type index, float u, Vector3& result) const
+{
+ ASSERT(index >= index_lo && index < index_hi);
+ result = points[index] + (points[index+1] - points[index]) * u;
+}
+
+void SplineBase::EvaluateCatmullRom( index_type index, float t, Vector3& result) const
+{
+ ASSERT(index >= index_lo && index < index_hi);
+ C_Evaluate(&points[index - 1], t, s_catmullRomCoeffs, result);
+}
+
+void SplineBase::EvaluateBezier3(index_type index, float t, Vector3& result) const
+{
+ index *= 3u;
+ ASSERT(index >= index_lo && index < index_hi);
+ C_Evaluate(&points[index], t, s_Bezier3Coeffs, result);
+}
+
+void SplineBase::EvaluateDerivativeLinear(index_type index, float, Vector3& result) const
+{
+ ASSERT(index >= index_lo && index < index_hi);
+ result = points[index+1] - points[index];
+}
+
+void SplineBase::EvaluateDerivativeCatmullRom(index_type index, float t, Vector3& result) const
+{
+ ASSERT(index >= index_lo && index < index_hi);
+ C_Evaluate_Derivative(&points[index - 1], t, s_catmullRomCoeffs, result);
+}
+
+void SplineBase::EvaluateDerivativeBezier3(index_type index, float t, Vector3& result) const
+{
+ index *= 3u;
+ ASSERT(index >= index_lo && index < index_hi);
+ C_Evaluate_Derivative(&points[index], t, s_Bezier3Coeffs, result);
+}
+
+float SplineBase::SegLengthLinear(index_type index) const
+{
+ ASSERT(index >= index_lo && index < index_hi);
+ return (points[index] - points[index+1]).length();
+}
+
+float SplineBase::SegLengthCatmullRom( index_type index ) const
+{
+ ASSERT(index >= index_lo && index < index_hi);
+
+ Vector3 curPos, nextPos;
+ const Vector3 * p = &points[index - 1];
+ curPos = nextPos = p[1];
+
+ index_type i = 1;
+ double length = 0;
+ while (i <= STEPS_PER_SEGMENT)
+ {
+ C_Evaluate(p, float(i) / float(STEPS_PER_SEGMENT), s_catmullRomCoeffs, nextPos);
+ length += (nextPos - curPos).length();
+ curPos = nextPos;
+ ++i;
+ }
+ return length;
+}
+
+float SplineBase::SegLengthBezier3(index_type index) const
+{
+ index *= 3u;
+ ASSERT(index >= index_lo && index < index_hi);
+
+ Vector3 curPos, nextPos;
+ const Vector3 * p = &points[index];
+
+ C_Evaluate(p, 0.f, s_Bezier3Coeffs, nextPos);
+ curPos = nextPos;
+
+ index_type i = 1;
+ double length = 0;
+ while (i <= STEPS_PER_SEGMENT)
+ {
+ C_Evaluate(p, float(i) / float(STEPS_PER_SEGMENT), s_Bezier3Coeffs, nextPos);
+ length += (nextPos - curPos).length();
+ curPos = nextPos;
+ ++i;
+ }
+ return length;
+}
+#pragma endregion
+
+void SplineBase::init_spline(const Vector3 * controls, index_type count, EvaluationMode m)
+{
+ m_mode = m;
+ cyclic = false;
+
+ (this->*initializers[m_mode])(controls, count, cyclic, 0);
+}
+
+void SplineBase::init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point)
+{
+ m_mode = m;
+ cyclic = true;
+
+ (this->*initializers[m_mode])(controls, count, cyclic, cyclic_point);
+}
+
+void SplineBase::InitLinear(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point)
+{
+ ASSERT(count >= 2);
+ const int real_size = count + 1;
+
+ points.resize(real_size);
+
+ memcpy(&points[0],controls, sizeof(Vector3) * count);
+
+ // first and last two indexes are space for special 'virtual points'
+ // these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work
+ if (cyclic)
+ points[count] = controls[cyclic_point];
+ else
+ points[count] = controls[count-1];
+
+ index_lo = 0;
+ index_hi = cyclic ? count : (count - 1);
+}
+
+void SplineBase::InitCatmullRom(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point)
+{
+ const int real_size = count + (cyclic ? (1+2) : (1+1));
+
+ points.resize(real_size);
+
+ int lo_index = 1;
+ int high_index = lo_index + count - 1;
+
+ memcpy(&points[lo_index],controls, sizeof(Vector3) * count);
+
+ // first and last two indexes are space for special 'virtual points'
+ // these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work
+ if (cyclic)
+ {
+ if (cyclic_point == 0)
+ points[0] = controls[count-1];
+ else
+ points[0] = controls[0].lerp(controls[1], -1);
+
+ points[high_index+1] = controls[cyclic_point];
+ points[high_index+2] = controls[cyclic_point+1];
+ }
+ else
+ {
+ points[0] = controls[0].lerp(controls[1], -1);
+ points[high_index+1] = controls[count-1];
+ }
+
+ index_lo = lo_index;
+ index_hi = high_index + (cyclic ? 1 : 0);
+}
+
+void SplineBase::InitBezier3(const Vector3* controls, index_type count, bool /*cyclic*/, index_type /*cyclic_point*/)
+{
+ index_type c = count / 3u * 3u;
+ index_type t = c / 3u;
+
+ points.resize(c);
+ memcpy(&points[0],controls, sizeof(Vector3) * c);
+
+ index_lo = 0;
+ index_hi = t-1;
+ //mov_assert(points.size() % 3 == 0);
+}
+
+void SplineBase::clear()
+{
+ index_lo = 0;
+ index_hi = 0;
+ points.clear();
+}
+
+std::string SplineBase::ToString() const
+{
+ std::stringstream str;
+ const char * mode_str[ModesEnd] = {"Linear", "CatmullRom", "Bezier3", "Uninitialized"};
+
+ index_type count = this->points.size();
+ str << "mode: " << mode_str[mode()] << std::endl;
+ str << "points count: " << count << std::endl;
+ for (index_type i = 0; i < count; ++i)
+ str << "point " << i << " : " << points[i].toString() << std::endl;
+
+ return str.str();
+}
+
+}
diff --git a/src/server/game/Movement/Spline/Spline.h b/src/server/game/Movement/Spline/Spline.h
new file mode 100644
index 00000000000..28876b220d4
--- /dev/null
+++ b/src/server/game/Movement/Spline/Spline.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TRINITYSERVER_SPLINE_H
+#define TRINITYSERVER_SPLINE_H
+
+#include "MovementTypedefs.h"
+#include <G3D/Vector3.h>
+
+namespace Movement {
+
+class SplineBase
+{
+public:
+ typedef int index_type;
+ typedef std::vector<Vector3> ControlArray;
+
+ enum EvaluationMode
+ {
+ ModeLinear,
+ ModeCatmullrom,
+ ModeBezier3_Unused,
+ UninitializedMode,
+ ModesEnd
+ };
+
+ #pragma region fields
+protected:
+ ControlArray points;
+
+ index_type index_lo;
+ index_type index_hi;
+
+ uint8 m_mode;
+ bool cyclic;
+
+ enum{
+ // could be modified, affects segment length evaluation precision
+ // lesser value saves more performance in cost of lover precision
+ // minimal value is 1
+ // client's value is 20, blizzs use 2-3 steps to compute length
+ STEPS_PER_SEGMENT = 3,
+ };
+ static_assert(STEPS_PER_SEGMENT > 0, "shouldn't be lesser than 1");
+
+protected:
+ void EvaluateLinear(index_type, float, Vector3&) const;
+ void EvaluateCatmullRom(index_type, float, Vector3&) const;
+ void EvaluateBezier3(index_type, float, Vector3&) const;
+ typedef void (SplineBase::*EvaluationMethtod)(index_type,float,Vector3&) const;
+ static EvaluationMethtod evaluators[ModesEnd];
+
+ void EvaluateDerivativeLinear(index_type, float, Vector3&) const;
+ void EvaluateDerivativeCatmullRom(index_type, float, Vector3&) const;
+ void EvaluateDerivativeBezier3(index_type, float, Vector3&) const;
+ static EvaluationMethtod derivative_evaluators[ModesEnd];
+
+ float SegLengthLinear(index_type) const;
+ float SegLengthCatmullRom(index_type) const;
+ float SegLengthBezier3(index_type) const;
+ typedef float (SplineBase::*SegLenghtMethtod)(index_type) const;
+ static SegLenghtMethtod seglengths[ModesEnd];
+
+ void InitLinear(const Vector3*, index_type, bool, index_type);
+ void InitCatmullRom(const Vector3*, index_type, bool, index_type);
+ void InitBezier3(const Vector3*, index_type, bool, index_type);
+ typedef void (SplineBase::*InitMethtod)(const Vector3*, index_type, bool, index_type);
+ static InitMethtod initializers[ModesEnd];
+
+ void UninitializedSpline() const { ASSERT(false);}
+
+ #pragma endregion
+public:
+
+ explicit SplineBase() : m_mode(UninitializedMode), index_lo(0), index_hi(0), cyclic(false) {}
+
+ /** Caclulates the position for given segment Idx, and percent of segment length t
+ @param t - percent of segment length, assumes that t in range [0, 1]
+ @param Idx - spline segment index, should be in range [first, last)
+ */
+ void evaluate_percent(index_type Idx, float u, Vector3& c) const {(this->*evaluators[m_mode])(Idx,u,c);}
+
+ /** Caclulates derivation in index Idx, and percent of segment length t
+ @param Idx - spline segment index, should be in range [first, last)
+ @param t - percent of spline segment length, assumes that t in range [0, 1]
+ */
+ void evaluate_derivative(index_type Idx, float u, Vector3& hermite) const {(this->*derivative_evaluators[m_mode])(Idx,u,hermite);}
+
+ /** Bounds for spline indexes. All indexes should be in range [first, last). */
+ index_type first() const { return index_lo;}
+ index_type last() const { return index_hi;}
+
+ bool empty() const { return index_lo == index_hi;}
+ EvaluationMode mode() const { return (EvaluationMode)m_mode;}
+ bool isCyclic() const { return cyclic;}
+
+ const ControlArray& getPoints() const { return points;}
+ index_type getPointCount() const { return points.size();}
+ const Vector3& getPoint(index_type i) const { return points[i];}
+
+ /** Initializes spline. Don't call other methods while spline not initialized. */
+ void init_spline(const Vector3 * controls, index_type count, EvaluationMode m);
+ void init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point);
+
+ /** As i can see there are a lot of ways how spline can be initialized
+ would be no harm to have some custom initializers. */
+ template<class Init> inline void init_spline(Init& initializer)
+ {
+ initializer(m_mode,cyclic,points,index_lo,index_hi);
+ }
+
+ void clear();
+
+ /** Calculates distance between [i; i+1] points, assumes that index i is in bounds. */
+ float SegLength(index_type i) const { return (this->*seglengths[m_mode])(i);}
+
+ std::string ToString() const;
+};
+
+template<typename length_type>
+class Spline : public SplineBase
+{
+public:
+ typedef length_type LengthType;
+ typedef std::vector<length_type> LengthArray;
+ #pragma region fields
+protected:
+
+ LengthArray lengths;
+
+ index_type computeIndexInBounds(length_type length) const;
+ #pragma endregion
+public:
+
+ explicit Spline(){}
+
+ /** Calculates the position for given t
+ @param t - percent of spline's length, assumes that t in range [0, 1]. */
+ void evaluate_percent(float t, Vector3 & c) const;
+
+ /** Calculates derivation for given t
+ @param t - percent of spline's length, assumes that t in range [0, 1]. */
+ void evaluate_derivative(float t, Vector3& hermite) const;
+
+ /** Calculates the position for given segment Idx, and percent of segment length t
+ @param t = partial_segment_length / whole_segment_length
+ @param Idx - spline segment index, should be in range [first, last). */
+ void evaluate_percent(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_percent(Idx,u,c);}
+
+ /** Caclulates derivation for index Idx, and percent of segment length t
+ @param Idx - spline segment index, should be in range [first, last)
+ @param t - percent of spline segment length, assumes that t in range [0, 1]. */
+ void evaluate_derivative(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_derivative(Idx,u,c);}
+
+ // Assumes that t in range [0, 1]
+ index_type computeIndexInBounds(float t) const;
+ void computeIndex(float t, index_type& out_idx, float& out_u) const;
+
+ /** Initializes spline. Don't call other methods while spline not initialized. */
+ void init_spline(const Vector3 * controls, index_type count, EvaluationMode m) { SplineBase::init_spline(controls,count,m);}
+ void init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point) { SplineBase::init_cyclic_spline(controls,count,m,cyclic_point);}
+
+ /** Initializes lengths with SplineBase::SegLength method. */
+ void initLengths();
+
+ /** Initializes lengths in some custom way
+ Note that value returned by cacher must be greater or equal to previous value. */
+ template<class T> inline void initLengths(T& cacher)
+ {
+ index_type i = index_lo;
+ lengths.resize(index_hi+1);
+ length_type prev_length = 0, new_length = 0;
+ while(i < index_hi)
+ {
+ new_length = cacher(*this, i);
+ lengths[++i] = new_length;
+
+ ASSERT(prev_length <= new_length);
+ prev_length = new_length;
+ }
+ }
+
+ /** Returns length of the whole spline. */
+ length_type length() const { return lengths[index_hi];}
+ /** Returns length between given nodes. */
+ length_type length(index_type first, index_type last) const { return lengths[last]-lengths[first];}
+ length_type length(index_type Idx) const { return lengths[Idx];}
+
+ void set_length(index_type i, length_type length) { lengths[i] = length;}
+ void clear();
+};
+
+}
+
+#include "SplineImpl.h"
+
+#endif // TRINITYSERVER_SPLINE_H
diff --git a/src/server/game/Movement/Spline/SplineImpl.h b/src/server/game/Movement/Spline/SplineImpl.h
new file mode 100644
index 00000000000..eded2d8c903
--- /dev/null
+++ b/src/server/game/Movement/Spline/SplineImpl.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+namespace Movement
+{
+template<typename length_type> void Spline<length_type>::evaluate_percent( float t, Vector3 & c ) const
+{
+ index_type Index;
+ float u;
+ computeIndex(t, Index, u);
+ evaluate_percent(Index, u, c);
+}
+
+template<typename length_type> void Spline<length_type>::evaluate_derivative(float t, Vector3& hermite) const
+{
+ index_type Index;
+ float u;
+ computeIndex(t, Index, u);
+ evaluate_derivative(Index, u, hermite);
+}
+
+template<typename length_type> SplineBase::index_type Spline<length_type>::computeIndexInBounds(length_type length_) const
+{
+// Temporary disabled: causes infinite loop with t = 1.f
+/*
+ index_type hi = index_hi;
+ index_type lo = index_lo;
+
+ index_type i = lo + (float)(hi - lo) * t;
+
+ while ((lengths[i] > length) || (lengths[i + 1] <= length))
+ {
+ if (lengths[i] > length)
+ hi = i - 1; // too big
+ else if (lengths[i + 1] <= length)
+ lo = i + 1; // too small
+
+ i = (hi + lo) / 2;
+ }*/
+
+ index_type i = index_lo;
+ index_type N = index_hi;
+ while (i+1 < N && lengths[i+1] < length_)
+ ++i;
+
+ return i;
+}
+
+template<typename length_type> void Spline<length_type>::computeIndex(float t, index_type& index, float& u) const
+{
+ ASSERT(t >= 0.f && t <= 1.f);
+ length_type length_ = t * length();
+ index = computeIndexInBounds(length_);
+ ASSERT(index < index_hi);
+ u = (length_ - length(index)) / (float)length(index, index+1);
+}
+
+template<typename length_type> SplineBase::index_type Spline<length_type>::computeIndexInBounds( float t ) const
+{
+ ASSERT(t >= 0.f && t <= 1.f);
+ return computeIndexInBounds(t * length());
+}
+
+template<typename length_type> void Spline<length_type>::initLengths()
+{
+ index_type i = index_lo;
+ length_type length = 0;
+ lengths.resize(index_hi+1);
+ while(i < index_hi )
+ {
+ length += SegLength(i);
+ lengths[++i] = length;
+ }
+}
+
+template<typename length_type> void Spline<length_type>::clear()
+{
+ SplineBase::clear();
+ lengths.clear();
+}
+
+}
diff --git a/src/server/game/Movement/Traveller.h b/src/server/game/Movement/Traveller.h
deleted file mode 100755
index 641278ee37a..00000000000
--- a/src/server/game/Movement/Traveller.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TRINITY_TRAVELLER_H
-#define TRINITY_TRAVELLER_H
-
-#include "Creature.h"
-#include "Player.h"
-#include <cassert>
-
-/** Traveller is a wrapper for units (creatures or players) that
- * travel from point A to point B using the destination holder.
- */
-#define PLAYER_FLIGHT_SPEED 32.0f
-
-template<class T>
-struct Traveller
-{
- T &i_traveller;
- Traveller(T &t) : i_traveller(t) {}
- Traveller(const Traveller &obj) : i_traveller(obj) {}
- Traveller& operator=(const Traveller &obj)
- {
- this.i_traveller = obj.i_traveller;
- return *this;
- }
-
- operator T&(void) { return i_traveller; }
- operator const T&(void) { return i_traveller; }
- float GetPositionX() const { return i_traveller.GetPositionX(); }
- float GetPositionY() const { return i_traveller.GetPositionY(); }
- float GetPositionZ() const { return i_traveller.GetPositionZ(); }
- T& GetTraveller(void) { return i_traveller; }
-
- float Speed(void) { ASSERT(false); return 0.0f; }
- float GetMoveDestinationTo(float x, float y, float z);
- uint32 GetTotalTrevelTimeTo(float x, float y, float z);
-
- void Relocation(float x, float y, float z, float orientation) {}
- void Relocation(float x, float y, float z) { Relocation(x, y, z, i_traveller.GetOrientation()); }
- void MoveTo(float x, float y, float z, uint32 t) {}
-};
-
-template<class T>
-inline uint32 Traveller<T>::GetTotalTrevelTimeTo(float x, float y, float z)
-{
- float dist = GetMoveDestinationTo(x, y, z);
- float speed = Speed();
- if (speed < 0.0f)
- return 0xfffffffe; // almost infinity-unit should stop
- else
- speed *= 0.001f; // speed is in seconds so convert from second to millisecond
- return static_cast<uint32>(dist/speed);
-}
-
-// specialization for creatures
-template<>
-inline float Traveller<Creature>::Speed()
-{
- if (i_traveller.HasUnitState(UNIT_STAT_CHARGING))
- return i_traveller.m_TempSpeed;
- else if (i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_WALKING))
- return i_traveller.GetSpeed(MOVE_WALK);
- else if (i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_FLYING))
- return i_traveller.GetSpeed(MOVE_FLIGHT);
- else
- return i_traveller.GetSpeed(MOVE_RUN);
-}
-
-template<>
-inline void Traveller<Creature>::Relocation(float x, float y, float z, float orientation)
-{
- i_traveller.UpdatePosition(x, y, z, orientation);
-}
-
-template<>
-inline float Traveller<Creature>::GetMoveDestinationTo(float x, float y, float z)
-{
- float dx = x - GetPositionX();
- float dy = y - GetPositionY();
- float dz = z - GetPositionZ();
-
- //if (i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_FLYING))
- return sqrt((dx*dx) + (dy*dy) + (dz*dz));
- //else //Walking on the ground
- // return sqrt((dx*dx) + (dy*dy));
-}
-
-template<>
-inline void Traveller<Creature>::MoveTo(float x, float y, float z, uint32 t)
-{
- //i_traveller.AI_SendMoveToPacket(x, y, z, t, i_traveller.GetUnitMovementFlags(), 0);
- i_traveller.SendMonsterMove(x, y, z, t);
-}
-
-// specialization for players
-template<>
-inline float Traveller<Player>::Speed()
-{
- if (i_traveller.HasUnitState(UNIT_STAT_CHARGING))
- return i_traveller.m_TempSpeed;
- else if (i_traveller.isInFlight())
- return PLAYER_FLIGHT_SPEED;
- else
- return i_traveller.GetSpeed(i_traveller.m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING) ? MOVE_WALK : MOVE_RUN);
-}
-
-template<>
-inline float Traveller<Player>::GetMoveDestinationTo(float x, float y, float z)
-{
- float dx = x - GetPositionX();
- float dy = y - GetPositionY();
- float dz = z - GetPositionZ();
-
- //if (i_traveller.isInFlight())
- return sqrt((dx*dx) + (dy*dy) + (dz*dz));
- //else //Walking on the ground
- // return sqrt((dx*dx) + (dy*dy));
-}
-
-template<>
-inline void Traveller<Player>::Relocation(float x, float y, float z, float orientation)
-{
- i_traveller.UpdatePosition(x, y, z, orientation);
-}
-
-template<>
-inline void Traveller<Player>::MoveTo(float x, float y, float z, uint32 t)
-{
- //Only send MOVEMENTFLAG_WALKING, client has strange issues with other move flags
- i_traveller.SendMonsterMove(x, y, z, t);
-}
-
-typedef Traveller<Creature> CreatureTraveller;
-typedef Traveller<Player> PlayerTraveller;
-#endif
-
diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h
index 2cca2506f4a..0edd44328f1 100755
--- a/src/server/game/Quests/QuestDef.h
+++ b/src/server/game/Quests/QuestDef.h
@@ -271,7 +271,7 @@ class Quest
uint32 GetQuestTurnInPortrait() const { return QuestTurnInPortrait; }
bool IsDaily() const { return Flags & QUEST_FLAGS_DAILY; }
bool IsWeekly() const { return Flags & QUEST_FLAGS_WEEKLY; }
- bool IsSeasonal() const { return ZoneOrSort == -QUEST_SORT_SEASONAL; }
+ bool IsSeasonal() const { return (ZoneOrSort == -QUEST_SORT_SEASONAL || ZoneOrSort == -QUEST_SORT_SPECIAL || ZoneOrSort == -QUEST_SORT_LUNAR_FESTIVAL || ZoneOrSort == -QUEST_SORT_MIDSUMMER || ZoneOrSort == -QUEST_SORT_BREWFEST || ZoneOrSort == -QUEST_SORT_LOVE_IS_IN_THE_AIR || ZoneOrSort == -QUEST_SORT_NOBLEGARDEN); }
bool IsDailyOrWeekly() const { return Flags & (QUEST_FLAGS_DAILY | QUEST_FLAGS_WEEKLY); }
bool IsAutoAccept() const { return Flags & QUEST_FLAGS_AUTO_ACCEPT; }
bool IsRaidQuest() const { return Type == QUEST_TYPE_RAID || Type == QUEST_TYPE_RAID_10 || Type == QUEST_TYPE_RAID_25; }
diff --git a/src/server/game/Scripting/MapScripts.cpp b/src/server/game/Scripting/MapScripts.cpp
index 71195538256..7757e1a1a35 100755
--- a/src/server/game/Scripting/MapScripts.cpp
+++ b/src/server/game/Scripting/MapScripts.cpp
@@ -475,8 +475,14 @@ void Map::ScriptsProcess()
// Source or target must be Creature.
if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
- cSource->SendMonsterMoveWithSpeed(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, step.script->MoveTo.TravelTime);
- cSource->GetMap()->CreatureRelocation(cSource, step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, 0);
+ Unit * unit = (Unit*)cSource;
+ if (step.script->MoveTo.TravelTime != 0)
+ {
+ float speed = unit->GetDistance(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ) / ((float)step.script->MoveTo.TravelTime * 0.001f);
+ unit->MonsterMoveWithSpeed(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, speed);
+ }
+ else
+ unit->NearTeleportTo(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, unit->GetOrientation());
}
break;
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index 6322151e792..c46721db6cd 100755
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -570,6 +570,7 @@ void AddSC_the_eye();
void AddSC_boss_gatewatcher_iron_hand(); //TK The Mechanar
void AddSC_boss_nethermancer_sepethrea();
void AddSC_boss_pathaleon_the_calculator();
+void AddSC_boss_mechano_lord_capacitus();
void AddSC_instance_mechanar();
void AddSC_blades_edge_mountains();
@@ -1030,6 +1031,7 @@ void AddOutlandScripts()
AddSC_boss_gatewatcher_iron_hand(); //TK The Mechanar
AddSC_boss_nethermancer_sepethrea();
AddSC_boss_pathaleon_the_calculator();
+ AddSC_boss_mechano_lord_capacitus();
AddSC_instance_mechanar();
AddSC_blades_edge_mountains();
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 84ccc3e574b..978f33c88aa 100755
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -96,7 +96,7 @@ m_playerRecentlyLogout(false), m_playerSave(false),
m_sessionDbcLocale(sWorld->GetAvailableDbcLocale(locale)),
m_sessionDbLocaleIndex(locale),
m_latency(0), m_TutorialsChanged(false), recruiterId(recruiter),
-isRecruiter(isARecruiter)
+isRecruiter(isARecruiter), timeLastWhoCommand(0)
{
if (sock)
{
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index ff07164e7b2..d4cf3119257 100755
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -964,6 +964,7 @@ class WorldSession
uint32 recruiterId;
bool isRecruiter;
ACE_Based::LockedQueue<WorldPacket*, ACE_Thread_Mutex> _recvQueue;
+ time_t timeLastWhoCommand;
};
#endif
/// @}
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index c1fcfc6d244..2c28eb4216c 100755
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -4789,11 +4789,7 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
break;
case 46361: // Reinforced Net
if (caster)
- {
- float currentGroundLevel = target->GetBaseMap()->GetHeight(target->GetPositionX(), target->GetPositionY(), MAX_HEIGHT);
- if (target->GetPositionZ() > currentGroundLevel)
- target->GetMotionMaster()->MoveFall(currentGroundLevel);
- }
+ target->GetMotionMaster()->MoveFall();
break;
case 49028:
if (caster)
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index aac93ad78a3..a577a8678ea 100755
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -1978,6 +1978,13 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI
if (!sSpellMgr->CanSpellTriggerProcOnEvent(*procEntry, eventInfo))
return false;
+ // TODO:
+ // - do checks using conditions table for eventInfo->GetActor() and eventInfo->GetActionTarget()
+ // - add DoCheckProc() AuraScript hook
+ // to allow additional requirements for procs
+ // this is needed because this is the last moment in which you can prevent aura charge drop on proc
+ // and possibly a way to prevent default checks (if there're going to be any)
+
// Check if current equipment meets aura requirements
// do that only for passive spells
// TODO: this needs to be unified for all kinds of auras
@@ -2038,11 +2045,14 @@ float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& event
void Aura::TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
- // TODO: script hooks here (allowing prevention of selected effects)
+ // TODO: OnProc hook here
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (aurApp->HasEffect(i))
+ // TODO: OnEffectProc hook here (allowing prevention of selected effects)
GetEffect(i)->HandleProc(aurApp, eventInfo);
- // TODO: script hooks here
+ // TODO: AfterEffectProc hook here
+
+ // TODO: AfterProc hook here
// Remove aura if we've used last charge to proc
if (IsUsingCharges() && !GetCharges())
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index 8c9cde37c15..de743eb2991 100755
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -186,6 +186,9 @@ class Aura
bool CanStackWith(Aura const* existingAura) const;
// Proc system
+ // this subsystem is not yet in use - the core of it is functional, but still some research has to be done
+ // and some dependant problems fixed before it can replace old proc system (for example cooldown handling)
+ // currently proc system functionality is implemented in Unit::ProcDamageAndSpell
bool IsProcOnCooldown() const;
void AddProcCooldown(uint32 msec);
bool IsUsingCharges() const { return m_isUsingCharges; }
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index e8872deb152..a36bd7361b4 100755
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -3858,6 +3858,9 @@ void Spell::SendSpellGo()
castFlags |= CAST_FLAG_UNKNOWN_19; // same as in SMSG_SPELL_START
}
+ if (m_targets.HasTraj())
+ castFlags |= CAST_FLAG_ADJUST_MISSILE;
+
WorldPacket data(SMSG_SPELL_GO, 50); // guess size
if (m_CastItem)
@@ -3897,8 +3900,8 @@ void Spell::SendSpellGo()
if (castFlags & CAST_FLAG_ADJUST_MISSILE)
{
- data << float(0);
- data << uint32(0);
+ data << m_targets.GetElevation();
+ data << uint32(m_delayMoment);
}
if (castFlags & CAST_FLAG_PROJECTILE)
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index d932b536a78..cd4f2324d9b 100755
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -346,38 +346,6 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
switch (m_spellInfo->Id) // better way to check unknown
{
- // Positive/Negative Charge
- case 28062:
- case 28085:
- case 39090:
- case 39093:
- if (!m_triggeredByAuraSpell)
- break;
- if (unitTarget == m_caster)
- {
- uint8 count = 0;
- for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
- if (ihit->targetGUID != m_caster->GetGUID())
- if (Player* target = ObjectAccessor::GetPlayer(*m_caster, ihit->targetGUID))
- if (target->HasAura(m_triggeredByAuraSpell->Id))
- ++count;
- if (count)
- {
- uint32 spellId = 0;
- switch (m_spellInfo->Id)
- {
- case 28062: spellId = 29659; break;
- case 28085: spellId = 29660; break;
- case 39090: spellId = 39089; break;
- case 39093: spellId = 39092; break;
- }
- m_caster->SetAuraStack(spellId, m_caster, count);
- }
- }
-
- if (unitTarget->HasAura(m_triggeredByAuraSpell->Id))
- damage = 0;
- break;
// Consumption
case 28865:
damage = (((InstanceMap*)m_caster->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY ? 2750 : 4250);
@@ -2795,7 +2763,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
{
case GAMEOBJECT_TYPE_DOOR:
case GAMEOBJECT_TYPE_BUTTON:
- gameObjTarget->UseDoorOrButton();
+ gameObjTarget->UseDoorOrButton(0, false, player);
player->GetMap()->ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
return;
@@ -3408,22 +3376,11 @@ void Spell::EffectDistract(SpellEffIndex /*effIndex*/)
if (unitTarget->HasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING))
return;
- float angle = unitTarget->GetAngle(m_targets.GetDst());
+ unitTarget->SetFacingTo(unitTarget->GetAngle(m_targets.GetDst()));
+ unitTarget->ClearUnitState(UNIT_STAT_MOVING);
- if (unitTarget->GetTypeId() == TYPEID_PLAYER)
- {
- // For players just turn them
- unitTarget->ToPlayer()->UpdatePosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
- //unitTarget->ToPlayer()->SendTeleportAckPacket(); TODO!
- }
- else
- {
- // Set creature Distracted, Stop it, And turn it
- unitTarget->SetOrientation(angle);
- unitTarget->StopMoving();
+ if (unitTarget->GetTypeId() == TYPEID_UNIT)
unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS);
- unitTarget->SendMovementFlagUpdate();
- }
}
void Spell::EffectPickPocket(SpellEffIndex /*effIndex*/)
@@ -5608,6 +5565,7 @@ void Spell::EffectDuel(SpellEffIndex effIndex)
duel->opponent = target;
duel->startTime = 0;
duel->startTimer = 0;
+ duel->isMounted = (GetSpellInfo()->Id == 62875); // Mounted Duel
caster->duel = duel;
DuelInfo* duel2 = new DuelInfo;
@@ -5615,6 +5573,7 @@ void Spell::EffectDuel(SpellEffIndex effIndex)
duel2->opponent = caster;
duel2->startTime = 0;
duel2->startTimer = 0;
+ duel2->isMounted = (GetSpellInfo()->Id == 62875); // Mounted Duel
target->duel = duel2;
caster->SetUInt64Value(PLAYER_DUEL_ARBITER, pGameObj->GetGUID());
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 2e2199db794..a5bea319fee 100755
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -2889,6 +2889,22 @@ void SpellMgr::LoadSpellCustomAttr()
case 69293: // Wing Buffet
case 74439: // Machine Gun
case 63278: // Mark of the Faceless (General Vezax)
+ case 62544: // Thrust (Argent Tournament)
+ case 64588: // Thrust (Argent Tournament)
+ case 66479: // Thrust (Argent Tournament)
+ case 68505: // Thrust (Argent Tournament)
+ case 62626: // Break-Shield (Argent Tournament, Player)
+ case 64590: // Break-Shield (Argent Tournament, Player)
+ case 64342: // Break-Shield (Argent Tournament, NPC)
+ case 64686: // Break-Shield (Argent Tournament, NPC)
+ case 65147: // Break-Shield (Argent Tournament, NPC)
+ case 68504: // Break-Shield (Argent Tournament, NPC)
+ case 62874: // Charge (Argent Tournament, Player)
+ case 68498: // Charge (Argent Tournament, Player)
+ case 64591: // Charge (Argent Tournament, Player)
+ case 63003: // Charge (Argent Tournament, NPC)
+ case 63010: // Charge (Argent Tournament, NPC)
+ case 68321: // Charge (Argent Tournament, NPC)
case 72255: // Mark of the Fallen Champion (Deathbringer Saurfang)
case 72444: // Mark of the Fallen Champion (Deathbringer Saurfang)
case 72445: // Mark of the Fallen Champion (Deathbringer Saurfang)
@@ -2972,6 +2988,7 @@ void SpellMgr::LoadDbcDataCorrections()
spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ENEMY;
spellInfo->EffectImplicitTargetB[0] = 0;
break;
+ case 63665: // Charge (Argent Tournament emote on riders)
case 31447: // Mark of Kaz'rogal (needs target selection script)
case 31298: // Sleep (needs target selection script)
case 51904: // Summon Ghouls On Scarlet Crusade (this should use conditions table, script for this spell needs to be fixed)
@@ -3041,6 +3058,7 @@ void SpellMgr::LoadDbcDataCorrections()
case 42611: // Shoot
case 61588: // Blazing Harpoon
case 52479: // Gift of the Harvester
+ case 48246: // Ball of Flame
spellInfo->MaxAffectedTargets = 1;
break;
case 41376: // Spite
@@ -3383,6 +3401,7 @@ void SpellMgr::LoadDbcDataCorrections()
spellInfo->AreaGroupId = 0; // originally, these require area 4522, which is... outside of Icecrown Citadel
break;
case 70602: // Corruption
+ case 48278: // Paralyze
spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
break;
case 70715: // Column of Frost (visual marker)