aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/TargetedMovementGenerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/TargetedMovementGenerator.cpp')
-rw-r--r--src/server/game/TargetedMovementGenerator.cpp280
1 files changed, 280 insertions, 0 deletions
diff --git a/src/server/game/TargetedMovementGenerator.cpp b/src/server/game/TargetedMovementGenerator.cpp
new file mode 100644
index 00000000000..a2ad478bfd4
--- /dev/null
+++ b/src/server/game/TargetedMovementGenerator.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ByteBuffer.h"
+#include "TargetedMovementGenerator.h"
+#include "Errors.h"
+#include "Creature.h"
+#include "CreatureAI.h"
+#include "DestinationHolderImp.h"
+#include "World.h"
+
+#define SMALL_ALPHA 0.05f
+
+#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)
+{
+ if (!i_target.isValid() || !i_target->IsInWorld())
+ return false;
+
+ if (owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
+ return false;
+
+ float x, y, z;
+ Traveller<T> traveller(owner);
+ if (i_destinationHolder.HasDestination())
+ {
+ 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 (i_target->GetExactDistSq(i_targetX, i_targetY, i_targetZ) < 0.01f)
+ return false;
+ }
+
+ if (!i_offset)
+ {
+ // 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
+ {
+ // 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);
+ }
+
+ /*
+ We MUST not check the distance difference and avoid setting the new location for smaller distances.
+ By that we risk having far too many GetContactPoint() calls freezing the whole system.
+ In TargetedMovementGenerator<T>::Update() we check the distance to the target and at
+ some range we calculate a new position. The calculation takes some processor cycles due to vmaps.
+ If the distance to the target it too large to ignore,
+ but the distance to the new contact point is short enough to be ignored,
+ we will calculate a new contact point each update loop, but will never move to it.
+ The system will freeze.
+ ralf
+
+ //We don't update Mob Movement, if the difference between New destination and last destination is < BothObjectSize
+ float bothObjectSize = i_target->GetObjectSize() + owner.GetObjectSize() + 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;
+}
+
+template<class T>
+void
+TargetedMovementGenerator<T>::Initialize(T &owner)
+{
+ if (owner.isInCombat())
+ owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+
+ _setTargetLocation(owner);
+}
+
+template<class T>
+void
+TargetedMovementGenerator<T>::Finalize(T &owner)
+{
+ owner.clearUnitState(UNIT_STAT_CHASE);
+}
+
+template<class T>
+void
+TargetedMovementGenerator<T>::Reset(T &owner)
+{
+ Initialize(owner);
+}
+
+template<class T>
+bool
+TargetedMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
+{
+ if (!i_target.isValid() || !i_target->IsInWorld())
+ return false;
+
+ if (!&owner || !owner.isAlive())
+ return true;
+
+ if (owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DISTRACTED))
+ return true;
+
+ // prevent movement while casting spells with cast time or channel time
+ if (owner.hasUnitState(UNIT_STAT_CASTING))
+ {
+ if (!owner.IsStopped())
+ owner.StopMoving();
+ return true;
+ }
+
+ // prevent crash after creature killed pet
+ if (!owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget())
+ return true;
+
+ Traveller<T> traveller(owner);
+
+ if (!i_destinationHolder.HasDestination())
+ _setTargetLocation(owner);
+ else if (owner.IsStopped() && !i_destinationHolder.HasArrived())
+ {
+ owner.addUnitState(UNIT_STAT_CHASE);
+ i_destinationHolder.StartTravel(traveller);
+ return true;
+ }
+
+ if (i_destinationHolder.UpdateTraveller(traveller, time_diff))
+ {
+ // put targeted movement generators on a higher priority
+ //if (owner.GetObjectSize())
+ //i_destinationHolder.ResetUpdate(50);
+
+ // target moved
+ if (i_targetX != i_target->GetPositionX() || i_targetY != i_target->GetPositionY()
+ || i_targetZ != i_target->GetPositionZ())
+ {
+ if (_setTargetLocation(owner) || !owner.hasUnitState(UNIT_STAT_FOLLOW))
+ owner.SetInFront(i_target.getTarget());
+ i_target->GetPosition(i_targetX, i_targetY, i_targetZ);
+ }
+
+ if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel)
+ {
+ i_recalculateTravel = false;
+ //Angle update will take place into owner.StopMoving()
+ owner.SetInFront(i_target.getTarget());
+
+ owner.StopMoving();
+ if (owner.IsWithinMeleeRange(i_target.getTarget()) && !owner.hasUnitState(UNIT_STAT_FOLLOW))
+ owner.Attack(i_target.getTarget(),true);
+ }
+ }
+
+ // Implemented for PetAI to handle resetting flags when pet owner reached
+ if (i_destinationHolder.HasArrived())
+ MovementInform(owner);
+
+ return true;
+}
+
+template<class T>
+Unit*
+TargetedMovementGenerator<T>::GetTarget() const
+{
+ return i_target.getTarget();
+}
+
+template<class T>
+void TargetedMovementGenerator<T>::MovementInform(T & /*unit*/)
+{
+}
+
+template <> void TargetedMovementGenerator<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());
+}
+
+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;
+
+