diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp index 25e513c532..67e2e39d6f 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.cpp +++ b/src/server/game/Entities/Creature/CreatureGroups.cpp @@ -225,13 +225,15 @@ void CreatureGroup::FormationReset(bool dismiss) m_Formed = !dismiss; } -void CreatureGroup::LeaderMoveTo(float x, float y, float z) +void CreatureGroup::LeaderMoveTo(Position destination, uint32 id /*= 0*/, uint32 moveType /*= 0*/, bool orientation /*= false*/) { //! To do: This should probably get its own movement generator or use WaypointMovementGenerator. //! If the leader's path is known, member's path can be plotted as well using formation offsets. if (!m_leader) return; + float x = destination.GetPositionX(), y = destination.GetPositionY(), z = destination.GetPositionZ(); + float pathangle = std::atan2(m_leader->GetPositionY() - y, m_leader->GetPositionX() - x); for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) @@ -257,12 +259,9 @@ void CreatureGroup::LeaderMoveTo(float x, float y, float z) if (!member->IsFlying()) member->UpdateGroundPositionZ(dx, dy, dz); - if (member->IsWithinDist(m_leader, dist + MAX_DESYNC)) - member->SetUnitMovementFlags(m_leader->GetUnitMovementFlags()); - else - member->SetWalk(false); + Position point(dx, dy, dz, destination.GetOrientation()); - member->GetMotionMaster()->MovePoint(0, dx, dy, dz); + member->GetMotionMaster()->MoveFormation(id, point, moveType, !member->IsWithinDist(m_leader, dist + MAX_DESYNC), orientation); member->SetHomePosition(dx, dy, dz, pathangle); } } diff --git a/src/server/game/Entities/Creature/CreatureGroups.h b/src/server/game/Entities/Creature/CreatureGroups.h index f49dfcbdfa..57ab5c900f 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.h +++ b/src/server/game/Entities/Creature/CreatureGroups.h @@ -88,7 +88,7 @@ class TC_GAME_API CreatureGroup void RemoveMember(Creature* member); void FormationReset(bool dismiss); - void LeaderMoveTo(float x, float y, float z); + void LeaderMoveTo(Position destination, uint32 id = 0, uint32 moveType = 0, bool orientation = false); void MemberAttackStart(Creature* member, Unit* target); }; diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 1e8c8f2174..866920a8ba 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -33,6 +33,7 @@ #include "WaypointMovementGenerator.h" #include "RandomMovementGenerator.h" #include "SplineChainMovementGenerator.h" +#include "FormationMovementGenerator.h" #include "MoveSpline.h" #include "MoveSplineInit.h" @@ -692,6 +693,15 @@ void MotionMaster::MoveRotate(uint32 time, RotateDirection direction) Mutate(new RotateMovementGenerator(time, direction), MOTION_SLOT_ACTIVE); } +void MotionMaster::MoveFormation(uint32 id, Position destination, uint32 moveType, bool forceRun /*= false*/, bool forceOrientation /*= false*/) +{ + if (_owner->GetTypeId() == TYPEID_UNIT) + { + TC_LOG_DEBUG("misc", "MotionMaster::MoveFormation: creature (GUID: %u) targeted point (Id: %u X: %f Y: %f Z: %f).", _owner->GetGUID().GetCounter(), id, destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ()); + Mutate(new FormationMovementGenerator(id, destination, moveType, forceRun, forceOrientation), MOTION_SLOT_ACTIVE); + } +} + /******************** Private methods ********************/ void MotionMaster::pop() diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index a5a110eeab..c7faaabceb 100644 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -57,6 +57,7 @@ enum MovementGeneratorType : uint8 ROTATE_MOTION_TYPE = 15, EFFECT_MOTION_TYPE = 16, SPLINE_CHAIN_MOTION_TYPE = 17, // SplineChainMovementGenerator.h + FORMATION_MOTION_TYPE = 18, // FormationMovementGenerator.h MAX_MOTION_TYPE // limit }; @@ -163,6 +164,7 @@ class TC_GAME_API MotionMaster void MovePath(uint32 path_id, bool repeatable); void MoveRotate(uint32 time, RotateDirection direction); + void MoveFormation(uint32 id, Position destination, uint32 moveType, bool forceRun = false, bool forceOrientation = false); private: typedef std::vector MovementList; diff --git a/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.cpp new file mode 100644 index 0000000000..f95260b6f8 --- /dev/null +++ b/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2008-2018 TrinityCore + * + * 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 . + */ + +#include "Creature.h" +#include "CreatureAI.h" +#include "MoveSplineInit.h" +#include "MoveSpline.h" +#include "FormationMovementGenerator.h" + +void FormationMovementGenerator::DoInitialize(Creature* owner) +{ + owner->AddUnitState(UNIT_STATE_ROAMING); + + if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) + { + _interrupt = true; + owner->StopMoving(); + return; + } + + owner->AddUnitState(UNIT_STATE_ROAMING_MOVE); + + Movement::MoveSplineInit init(owner); + init.MoveTo(_destination); + if (_orientation) + init.SetFacing(_destination.GetOrientation()); + + switch (_moveType) + { + case 2: // WAYPOINT_MOVE_TYPE_LAND + init.SetAnimation(Movement::ToGround); + break; + case 3: // WAYPOINT_MOVE_TYPE_TAKEOFF + init.SetAnimation(Movement::ToFly); + break; + case 1: // WAYPOINT_MOVE_TYPE_RUN + init.SetWalk(false); + break; + case 0: // WAYPOINT_MOVE_TYPE_WALK + init.SetWalk(true); + break; + } + + if (_run) + init.SetWalk(false); + + init.Launch(); +} + +bool FormationMovementGenerator::DoUpdate(Creature* owner, uint32 /*diff*/) +{ + if (!owner) + return false; + + if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) + { + _interrupt = true; + owner->StopMoving(); + return true; + } + + if ((_interrupt && owner->movespline->Finalized()) || (_recalculateSpeed && !owner->movespline->Finalized())) + { + _recalculateSpeed = false; + _interrupt = false; + + owner->AddUnitState(UNIT_STATE_ROAMING_MOVE); + + Movement::MoveSplineInit init(owner); + init.MoveTo(_destination); + if (_orientation) + init.SetFacing(_destination.GetOrientation()); + + switch (_moveType) + { + case 2: // WAYPOINT_MOVE_TYPE_LAND + init.SetAnimation(Movement::ToGround); + break; + case 3: // WAYPOINT_MOVE_TYPE_TAKEOFF + init.SetAnimation(Movement::ToFly); + break; + case 1: // WAYPOINT_MOVE_TYPE_RUN + init.SetWalk(false); + break; + case 0: // WAYPOINT_MOVE_TYPE_WALK + init.SetWalk(true); + break; + } + + if (_run) + init.SetWalk(false); + init.Launch(); + } + + return !owner->movespline->Finalized(); +} + +void FormationMovementGenerator::DoFinalize(Creature* owner) +{ + owner->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE); + + if (owner->movespline->Finalized()) + MovementInform(owner); +} + +void FormationMovementGenerator::DoReset(Creature* owner) +{ + owner->StopMoving(); + DoInitialize(owner); +} + +void FormationMovementGenerator::MovementInform(Creature* owner) +{ + if (owner->AI()) + owner->AI()->MovementInform(FORMATION_MOTION_TYPE, _movementId); +} diff --git a/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.h new file mode 100644 index 0000000000..caf22ae3f5 --- /dev/null +++ b/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008-2018 TrinityCore + * + * 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 . + */ + +#ifndef TRINITY_FORMATIONMOVEMENTGENERATOR_H +#define TRINITY_FORMATIONMOVEMENTGENERATOR_H + +#include "MovementGenerator.h" + +class FormationMovementGenerator : public MovementGeneratorMedium< Creature, FormationMovementGenerator > +{ + public: + explicit FormationMovementGenerator(uint32 id, Position destination, uint32 moveType, bool run, bool orientation) : _movementId(id), _destination(destination), _moveType(moveType), _run(run), _orientation(orientation), _recalculateSpeed(false), _interrupt(false) { } + + MovementGeneratorType GetMovementGeneratorType() const override { return FORMATION_MOTION_TYPE; } + + void DoInitialize(Creature*); + void DoFinalize(Creature*); + void DoReset(Creature*); + bool DoUpdate(Creature*, uint32); + + void UnitSpeedChanged() override { _recalculateSpeed = true; } + + private: + void MovementInform(Creature*); + + uint32 _movementId; + Position _destination; + uint32 _moveType; + bool _run; + bool _orientation; + bool _recalculateSpeed; + bool _interrupt; +}; + +#endif // TRINITY_FORMATIONMOVEMENTGENERATOR_H diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp index 07e3bd8c72..d1abbd4694 100755 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp @@ -56,7 +56,7 @@ void PointMovementGenerator::DoInitialize(T* owner) // Call for creature group update if (Creature* creature = owner->ToCreature()) if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature) - creature->GetFormation()->LeaderMoveTo(_x, _y, _z); + creature->GetFormation()->LeaderMoveTo(Position(_destination), _movementId); } template @@ -90,7 +90,7 @@ bool PointMovementGenerator::DoUpdate(T* owner, uint32 /*diff*/) // Call for creature group update if (Creature* creature = owner->ToCreature()) if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature) - creature->GetFormation()->LeaderMoveTo(_x, _y, _z); + creature->GetFormation()->LeaderMoveTo(Position(_destination), _movementId); } return !owner->movespline->Finalized(); diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp index 5affa7a4e2..f80b0c0401 100644 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp @@ -117,7 +117,7 @@ void RandomMovementGenerator::SetRandomLocation(Creature* owner) // Call for creature group update if (owner->GetFormation() && owner->GetFormation()->getLeader() == owner) - owner->GetFormation()->LeaderMoveTo(position.m_positionX, position.m_positionY, position.m_positionZ); + owner->GetFormation()->LeaderMoveTo(position); } template diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index 0b0f907bd2..acefadcf4f 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -142,8 +142,7 @@ bool WaypointMovementGenerator::StartMove(Creature* creature) creature->AddUnitState(UNIT_STATE_ROAMING_MOVE); - Movement::Location formationDest(node->x, node->y, node->z, 0.0f); - + Position formationDest(node->x, node->y, node->z, (node->orientation && node->delay) ? node->orientation : 0.0f); Movement::MoveSplineInit init(creature); //! If creature is on transport, we assume waypoints set in DB are already transport offsets @@ -151,7 +150,11 @@ bool WaypointMovementGenerator::StartMove(Creature* creature) { init.DisableTransportPathTransformations(); if (TransportBase* trans = creature->GetDirectTransport()) - trans->CalculatePassengerPosition(formationDest.x, formationDest.y, formationDest.z, &formationDest.orientation); + { + float orientation = formationDest.GetOrientation(); + trans->CalculatePassengerPosition(formationDest.m_positionX, formationDest.m_positionY, formationDest.m_positionZ, &orientation); + formationDest.SetOrientation(orientation); + } } //! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call @@ -180,12 +183,9 @@ bool WaypointMovementGenerator::StartMove(Creature* creature) init.Launch(); - //Call for creature group update + // Call for creature group update if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature) - { - creature->SetWalk(node->move_type != WAYPOINT_MOVE_TYPE_RUN); - creature->GetFormation()->LeaderMoveTo(formationDest.x, formationDest.y, formationDest.z); - } + creature->GetFormation()->LeaderMoveTo(formationDest, node->id, node->move_type, (node->orientation && node->delay) ? true : false); return true; }