Skip to content

Instantly share code, notes, and snippets.

@vermie
Created January 22, 2011 20:06
Show Gist options
  • Save vermie/791419 to your computer and use it in GitHub Desktop.
Save vermie/791419 to your computer and use it in GitHub Desktop.
ChargeMovementGenerator
diff --git a/src/game/ChargeMovementGenerator.cpp b/src/game/ChargeMovementGenerator.cpp
new file mode 100644
index 0000000..73838f2
--- /dev/null
+++ b/src/game/ChargeMovementGenerator.cpp
@@ -0,0 +1,126 @@
+
+#include "ChargeMovementGenerator.h"
+
+template<class T, class U>
+ChargeMovementGeneratorMedium<T, U>::ChargeMovementGeneratorMedium(Unit* target, const uint32 triggeredSpellId)
+ : PathMovementBase(), m_target(target), m_triggeredSpellId(triggeredSpellId)
+{
+}
+
+template<class T, class U>
+bool ChargeMovementGeneratorMedium<T, U>::Update(T &owner, const uint32 &diff)
+{
+ if (!&owner)
+ return true;
+
+ // if the unit can't move, stop charge
+ if (owner.hasUnitState(UNIT_STAT_NOT_MOVE))
+ return true;
+
+ // if there is no path, stop charge
+ if (i_path.empty())
+ return true;
+
+ Traveller<T> traveller(owner);
+ traveller.SetCustomSpeed(CHARGE_SPEED);
+
+ if (i_destinationHolder.UpdateTraveller(traveller, diff, false, false))
+ if (!IsActive(owner))
+ return true;
+
+ if (i_destinationHolder.HasArrived())
+ {
+ ++i_currentNode;
+
+ // if we are at the last node, stop charge
+ if (i_currentNode >= i_path.size())
+ return true;
+
+ MoveToNextNode(traveller);
+ }
+
+ return false;
+}
+
+template<class T, class U>
+void ChargeMovementGeneratorMedium<T, U>::MoveToNextNode(Traveller<T> &traveller)
+{
+ PathNode &node = i_path[i_currentNode];
+ i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z, false);
+}
+
+template<class T, class U>
+void ChargeMovementGeneratorMedium<T, U>::LoadPath(T &owner)
+{
+ // set the destination
+ float x, y, z;
+ m_target->GetContactPoint(&owner, x, y, z);
+
+ // get the path to the destination
+ PathInfo path(&owner, x, y, z);
+ i_path = path.getFullPath();
+
+ // start movement
+ Traveller<T> traveller(owner);
+ traveller.SetCustomSpeed(CHARGE_SPEED);
+ MoveToNextNode(traveller);
+
+ // send path to client
+ uint32 transitTime = uint32(i_path.GetTotalLength() / (CHARGE_SPEED / IN_MILLISECONDS));
+ owner.MonsterMoveByPath(i_path, 1, i_path.size(), transitTime);
+}
+
+template<class T, class U>
+void ChargeMovementGeneratorMedium<T, U>::Initialize(T &owner)
+{
+ owner.addUnitState(UNIT_STAT_CHARGE|UNIT_STAT_CHARGE_MOVE);
+
+ LoadPath(owner);
+
+ // TODO: disable player bar?
+}
+
+template<class T, class U>
+void ChargeMovementGeneratorMedium<T, U>::Finalize(T &owner)
+{
+ owner.clearUnitState(UNIT_STAT_CHARGE|UNIT_STAT_CHARGE_MOVE);
+
+ if (i_currentNode >= i_path.size() && m_target)
+ {
+ // we are at the destination, turn to target and cast spell
+ owner.SetInFront(m_target);
+
+ if (m_triggeredSpellId)
+ owner.CastSpell(m_target, m_triggeredSpellId, true);
+ }
+}
+
+template<class T, class U>
+void ChargeMovementGeneratorMedium<T, U>::Interrupt(T &owner)
+{
+ owner.clearUnitState(UNIT_STAT_CHARGE|UNIT_STAT_CHARGE_MOVE);
+}
+
+template<class T, class U>
+void ChargeMovementGeneratorMedium<T, U>::Reset(T &owner)
+{
+ Initialize(owner);
+}
+
+template ChargeMovementGeneratorMedium<Player, ChargeMovementGenerator<Player> >::ChargeMovementGeneratorMedium(Unit*, const uint32);
+template void ChargeMovementGeneratorMedium<Player, ChargeMovementGenerator<Player> >::Finalize(Player &);
+template void ChargeMovementGeneratorMedium<Player, ChargeMovementGenerator<Player> >::Initialize(Player &);
+template void ChargeMovementGeneratorMedium<Player, ChargeMovementGenerator<Player> >::Interrupt(Player &);
+template void ChargeMovementGeneratorMedium<Player, ChargeMovementGenerator<Player> >::LoadPath(Player &);
+template void ChargeMovementGeneratorMedium<Player, ChargeMovementGenerator<Player> >::MoveToNextNode(PlayerTraveller &);
+template void ChargeMovementGeneratorMedium<Player, ChargeMovementGenerator<Player> >::Reset(Player &);
+template bool ChargeMovementGeneratorMedium<Player, ChargeMovementGenerator<Player> >::Update(Player &, const uint32 &);
+
+template ChargeMovementGeneratorMedium<Creature, ChargeMovementGenerator<Creature> >::ChargeMovementGeneratorMedium(Unit*, const uint32);
+template void ChargeMovementGeneratorMedium<Creature, ChargeMovementGenerator<Creature> >::Finalize(Creature &);
+template void ChargeMovementGeneratorMedium<Creature, ChargeMovementGenerator<Creature> >::Initialize(Creature &);
+template void ChargeMovementGeneratorMedium<Creature, ChargeMovementGenerator<Creature> >::Interrupt(Creature &);
+template void ChargeMovementGeneratorMedium<Creature, ChargeMovementGenerator<Creature> >::LoadPath(Creature &);
+template void ChargeMovementGeneratorMedium<Creature, ChargeMovementGenerator<Creature> >::MoveToNextNode(CreatureTraveller &);
+template void ChargeMovementGeneratorMedium<Creature, ChargeMovementGenerator<Creature> >::Reset(Creature &);
+template bool ChargeMovementGeneratorMedium<Creature, ChargeMovementGenerator<Creature> >::Update(Creature &, const uint32 &);
diff --git a/src/game/ChargeMovementGenerator.h b/src/game/ChargeMovementGenerator.h
new file mode 100644
index 0000000..cde32d9
--- /dev/null
+++ b/src/game/ChargeMovementGenerator.h
@@ -0,0 +1,42 @@
+
+#ifndef MANGOS_CHARGEMOVEMENTGENERATOR_H
+#define MANGOS_CHARGEMOVEMENTGENERATOR_H
+
+#include "WaypointMovementGenerator.h"
+#include "PathFinder.h"
+
+// TODO: figure out nice speed for charge
+#define CHARGE_SPEED 25.0f
+
+template<class T, class U>
+class ChargeMovementGeneratorMedium : public MovementGeneratorMedium<T, U>, public PathMovementBase<T, PointPath>
+{
+public:
+ ChargeMovementGeneratorMedium(Unit* target, const uint32 triggeredSpellId);
+
+ void Initialize(T &u);
+ void Interrupt(T &);
+ void Finalize(T &);
+ void Reset(T &u);
+ bool Update(T &u, const uint32 &diff);
+
+ void LoadPath(T &u);
+
+ MovementGeneratorType GetMovementGeneratorType() const { return CHARGE_MOTION_TYPE; }
+
+private:
+ Unit* m_target;
+ const uint32 m_triggeredSpellId;
+
+ void MoveToNextNode(Traveller<T> &traveller);
+};
+
+template<class T>
+class ChargeMovementGenerator : public ChargeMovementGeneratorMedium<T, ChargeMovementGenerator<T> >
+{
+public:
+ ChargeMovementGenerator(Unit* target, const uint32 triggeredSpellId)
+ : ChargeMovementGeneratorMedium<T, ChargeMovementGenerator<T> >(target, triggeredSpellId) {}
+};
+
+#endif
\ No newline at end of file
diff --git a/src/game/Makefile.am b/src/game/Makefile.am
index 316711a..6b7062a 100644
--- a/src/game/Makefile.am
+++ b/src/game/Makefile.am
@@ -89,6 +89,8 @@ libmangosgame_a_SOURCES = \
CharacterDatabaseCleaner.cpp \
CharacterDatabaseCleaner.h \
CharacterHandler.cpp \
+ ChargeMovementHandler.cpp \
+ ChargeMovementHandler.h \
Chat.cpp \
Chat.h \
ChatHandler.cpp \
diff --git a/src/game/MotionMaster.cpp b/src/game/MotionMaster.cpp
index 0f74601..087e7bb 100644
--- a/src/game/MotionMaster.cpp
+++ b/src/game/MotionMaster.cpp
@@ -27,6 +27,7 @@
#include "IdleMovementGenerator.h"
#include "PointMovementGenerator.h"
#include "TargetedMovementGenerator.h"
+#include "ChargeMovementGenerator.h"
#include "WaypointMovementGenerator.h"
#include "RandomMovementGenerator.h"
@@ -66,7 +67,13 @@ MotionMaster::~MotionMaster()
void MotionMaster::UpdateMotion(uint32 diff)
{
if (m_owner->hasUnitState(UNIT_STAT_CAN_NOT_MOVE))
+ {
+ // cancel charge if owner is not dead
+ if (!m_owner->hasUnitState(UNIT_STAT_DIED) && top()->GetMovementGeneratorType() == CHARGE_MOTION_TYPE)
+ DirectExpire(true);
+
return;
+ }
MANGOS_ASSERT( !empty() );
m_cleanFlag |= MMCF_UPDATE;
@@ -403,6 +410,17 @@ void MotionMaster::MoveDistract(uint32 timer)
Mutate(mgen);
}
+void MotionMaster::MoveCharge(Unit* target, uint32 triggeredSpellId/* = 0*/)
+{
+ if (!target)
+ return;
+
+ if (m_owner->GetTypeId() == TYPEID_PLAYER)
+ Mutate(new ChargeMovementGenerator<Player>(target, triggeredSpellId));
+ else
+ Mutate(new ChargeMovementGenerator<Creature>(target, triggeredSpellId));
+}
+
void MotionMaster::Mutate(MovementGenerator *m)
{
if (!empty())
diff --git a/src/game/MotionMaster.h b/src/game/MotionMaster.h
index ec23db1..c17d9df 100644
--- a/src/game/MotionMaster.h
+++ b/src/game/MotionMaster.h
@@ -48,6 +48,7 @@ enum MovementGeneratorType
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)
FOLLOW_MOTION_TYPE = 14, // TargetedMovementGenerator.h
+ CHARGE_MOTION_TYPE = 15, // ChargeMovementGenerator.h (handles SpellEffect charge)
};
enum MMCleanFlag
@@ -107,6 +108,7 @@ class MANGOS_DLL_SPEC MotionMaster : private std::stack<MovementGenerator *>
void MoveWaypoint();
void MoveTaxiFlight(uint32 path, uint32 pathnode);
void MoveDistract(uint32 timeLimit);
+ void MoveCharge(Unit* target, uint32 triggeredSpellId = 0);
MovementGeneratorType GetCurrentMovementGeneratorType() const;
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
index 8263fb3..96faf2b 100644
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -7598,15 +7598,7 @@ void Spell::EffectCharge(SpellEffectIndex /*eff_idx*/)
if (!unitTarget)
return;
- //TODO: research more ContactPoint/attack distance.
- //3.666666 instead of ATTACK_DISTANCE(5.0f) in below seem to give more accurate result.
- float x, y, z;
- unitTarget->GetContactPoint(m_caster, x, y, z, 3.666666f);
-
- if (unitTarget->GetTypeId() != TYPEID_PLAYER)
- ((Creature *)unitTarget)->StopMoving();
-
- m_caster->MonsterMoveByPath(x, y, z, 25, false);
+ m_caster->GetMotionMaster()->MoveCharge(unitTarget);
// not all charge effects used in negative spells
if (unitTarget != m_caster && !IsPositiveSpell(m_spellInfo->Id))
diff --git a/src/game/Traveller.h b/src/game/Traveller.h
index 2101527..566c1a5 100644
--- a/src/game/Traveller.h
+++ b/src/game/Traveller.h
@@ -32,9 +32,8 @@
template<class T>
struct MANGOS_DLL_DECL Traveller
{
- T &i_traveller;
- Traveller(T &t) : i_traveller(t) {}
- Traveller(const Traveller &obj) : i_traveller(obj) {}
+ Traveller(T &t) : i_traveller(t), m_usingCustomSpeed(false) {}
+ Traveller(const Traveller &obj) : i_traveller(obj), m_usingCustomSpeed(false) {}
Traveller& operator=(const Traveller &obj)
{
~Traveller();
@@ -50,6 +49,7 @@ struct MANGOS_DLL_DECL Traveller
T& GetTraveller(void) { return i_traveller; }
float Speed(void) { MANGOS_ASSERT(false); return 0.0f; }
+ void SetCustomSpeed(float newSpeed) { m_usingCustomSpeed = true; m_speed = newSpeed; }
float GetMoveDestinationTo(float x, float y, float z);
uint32 GetTotalTravelTimeTo(float x, float y, float z);
@@ -57,6 +57,11 @@ struct MANGOS_DLL_DECL Traveller
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) {}
void Stop() {}
+
+private:
+ T &i_traveller;
+ float m_speed;
+ bool m_usingCustomSpeed;
};
template<class T>
@@ -73,7 +78,9 @@ inline uint32 Traveller<T>::GetTotalTravelTimeTo(float x, float y, float z)
template<>
inline float Traveller<Creature>::Speed()
{
- if(i_traveller.HasSplineFlag(SPLINEFLAG_WALKMODE))
+ if (m_usingCustomSpeed)
+ return m_speed;
+ else if(i_traveller.HasSplineFlag(SPLINEFLAG_WALKMODE))
return i_traveller.GetSpeed(MOVE_WALK);
else if(i_traveller.HasSplineFlag(SPLINEFLAG_UNKNOWN7))
return i_traveller.GetSpeed(MOVE_FLIGHT);
@@ -121,6 +128,8 @@ inline float Traveller<Player>::Speed()
{
if (i_traveller.IsTaxiFlying())
return PLAYER_FLIGHT_SPEED;
+ else if (m_usingCustomSpeed)
+ return m_speed;
else
return i_traveller.GetSpeed(i_traveller.m_movementInfo.HasMovementFlag(MOVEFLAG_WALK_MODE) ? MOVE_WALK : MOVE_RUN);
}
diff --git a/src/game/Unit.h b/src/game/Unit.h
index f362608..7c8af1a 100644
--- a/src/game/Unit.h
+++ b/src/game/Unit.h
@@ -440,8 +440,10 @@ enum UnitState
UNIT_STAT_FOLLOW_MOVE = 0x00010000,
UNIT_STAT_FLEEING = 0x00020000, // FleeMovementGenerator/TimedFleeingMovementGenerator active/onstack
UNIT_STAT_FLEEING_MOVE = 0x00040000,
+ UNIT_STAT_CHARGE = 0x00080000, // ChargeMovementGenerator active
+ UNIT_STAT_CHARGE_MOVE = 0x00100000,
- UNIT_STAT_IGNORE_PATHFINDING = 0x00080000, // do not use pathfinding in any MovementGenerator
+ UNIT_STAT_IGNORE_PATHFINDING = 0x00200000, // do not use pathfinding in any MovementGenerator
// masks (only for check)
@@ -455,11 +457,11 @@ enum UnitState
// stay or scripted movement for effect( = in player case you can't move by client command)
UNIT_STAT_NO_FREE_MOVE = UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DIED |
UNIT_STAT_TAXI_FLIGHT |
- UNIT_STAT_CONFUSED | UNIT_STAT_FLEEING,
+ UNIT_STAT_CONFUSED | UNIT_STAT_FLEEING | UNIT_STAT_CHARGE,
// not react at move in sight or other
UNIT_STAT_CAN_NOT_REACT = UNIT_STAT_STUNNED | UNIT_STAT_DIED |
- UNIT_STAT_CONFUSED | UNIT_STAT_FLEEING,
+ UNIT_STAT_CONFUSED | UNIT_STAT_FLEEING | UNIT_STAT_CHARGE,
// AI disabled by some reason
UNIT_STAT_LOST_CONTROL = UNIT_STAT_FLEEING | UNIT_STAT_CONTROLLED,
@@ -470,7 +472,7 @@ enum UnitState
// masks (for check or reset)
// for real move using movegen check and stop (except unstoppable flight)
- UNIT_STAT_MOVING = UNIT_STAT_ROAMING_MOVE | UNIT_STAT_CHASE_MOVE | UNIT_STAT_FOLLOW_MOVE | UNIT_STAT_FLEEING_MOVE,
+ UNIT_STAT_MOVING = UNIT_STAT_ROAMING_MOVE | UNIT_STAT_CHASE_MOVE | UNIT_STAT_FOLLOW_MOVE | UNIT_STAT_FLEEING_MOVE | UNIT_STAT_CHARGE_MOVE,
UNIT_STAT_ALL_STATE = 0xFFFFFFFF
};
diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp
index 107600a..4fd3933 100644
--- a/src/game/WaypointMovementGenerator.cpp
+++ b/src/game/WaypointMovementGenerator.cpp
@@ -302,7 +302,7 @@ bool WaypointMovementGenerator<Creature>::GetResetPosition(Creature&, float& x,
void WaypointMovementGenerator<Creature>::MoveToNextNode(CreatureTraveller &traveller)
{
- Creature* owner = &(traveller.i_traveller);
+ Creature* owner = &(traveller.GetTraveller());
const WaypointNode &node = i_path->at(i_currentNode);
i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z, false);
diff --git a/win/VC100/game.vcxproj b/win/VC100/game.vcxproj
index 956f5d9..9157443 100644
--- a/win/VC100/game.vcxproj
+++ b/win/VC100/game.vcxproj
@@ -386,6 +386,7 @@
<ClCompile Include="..\..\src\game\ChannelMgr.cpp" />
<ClCompile Include="..\..\src\game\CharacterDatabaseCleaner.cpp" />
<ClCompile Include="..\..\src\game\CharacterHandler.cpp" />
+ <ClCompile Include="..\..\src\game\ChargeMovementGenerator.cpp" />
<ClCompile Include="..\..\src\game\Chat.cpp" />
<ClCompile Include="..\..\src\game\ChatHandler.cpp" />
<ClCompile Include="..\..\src\game\CombatHandler.cpp" />
@@ -545,6 +546,7 @@
<ClInclude Include="..\..\src\game\Channel.h" />
<ClInclude Include="..\..\src\game\ChannelMgr.h" />
<ClInclude Include="..\..\src\game\CharacterDatabaseCleaner.h" />
+ <ClInclude Include="..\..\src\game\ChargeMovementGenerator.h" />
<ClInclude Include="..\..\src\game\Chat.h" />
<ClInclude Include="..\..\src\game\ConfusedMovementGenerator.h" />
<ClInclude Include="..\..\src\game\Corpse.h" />
diff --git a/win/VC100/game.vcxproj.filters b/win/VC100/game.vcxproj.filters
index d805b10..7c8603f 100644
--- a/win/VC100/game.vcxproj.filters
+++ b/win/VC100/game.vcxproj.filters
@@ -481,6 +481,9 @@
<ClCompile Include="..\..\src\game\vmap\WorldModel.cpp">
<Filter>vmaps</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\game\ChargeMovementGenerator.cpp">
+ <Filter>Motion generators</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\game\AccountMgr.h">
@@ -916,5 +919,8 @@
<ClInclude Include="..\..\src\game\vmap\WorldModel.h">
<Filter>vmaps</Filter>
</ClInclude>
+ <ClInclude Include="..\..\src\game\ChargeMovementGenerator.h">
+ <Filter>Motion generators</Filter>
+ </ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment