[11720] Implement spline movement subsystem

Spline movement controls movements of server-side controlled units (monster movement, taxi movement, etc).
Proper implementation of effects such as charge, jump, cyclic movement will rely on it.
However, need improve our states system before.

Technical changes:

 1. Added linear, catmullrom and bezier3 splines which based on client's algorthims. They can be reused for proper transport position interpolation.
 2. Precission increased. There are no more position desync issues since client's position calculation formulas used.
 3. Now possible to move by paths with multiple points, send whole path to client.
This commit is contained in:
SilverIce 2011-07-08 17:25:13 +03:00
parent e302fce513
commit 9d566398ad
52 changed files with 2471 additions and 1203 deletions

View file

@ -41,7 +41,7 @@ source_group("World/Handlers"
)
source_group("Motion generators"
REGULAR_EXPRESSION Movement|Holder|Motion|Traveller
REGULAR_EXPRESSION Generator|MotionMaster
)
source_group("Server"
@ -64,6 +64,13 @@ source_group("References"
REGULAR_EXPRESSION Reference|RefManager|ThreatManager
)
source_group("Movement"
REGULAR_EXPRESSION spline|Spline|packet_builder
FILES
movement/typedefs.h
movement/util.cpp
)
if(PCH)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
endif()

View file

@ -20,7 +20,8 @@
#include "Creature.h"
#include "MapManager.h"
#include "Opcodes.h"
#include "DestinationHolderImp.h"
#include "movement/MoveSplineInit.h"
#include "movement/MoveSpline.h"
template<class T>
void
@ -71,8 +72,6 @@ template<>
void
ConfusedMovementGenerator<Creature>::_InitSpecific(Creature &creature, bool &is_water_ok, bool &is_land_ok)
{
creature.RemoveSplineFlag(SPLINEFLAG_WALKMODE);
is_water_ok = creature.CanSwim();
is_land_ok = creature.CanWalk();
}
@ -97,7 +96,6 @@ 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);
}
@ -105,9 +103,6 @@ void ConfusedMovementGenerator<T>::Reset(T &unit)
template<class T>
bool ConfusedMovementGenerator<T>::Update(T &unit, const uint32 &diff)
{
if(!&unit)
return true;
// ignore in case other no reaction state
if (unit.hasUnitState(UNIT_STAT_CAN_NOT_REACT & ~UNIT_STAT_CONFUSED))
return true;
@ -116,36 +111,30 @@ bool ConfusedMovementGenerator<T>::Update(T &unit, const uint32 &diff)
{
// currently moving, update location
unit.addUnitState(UNIT_STAT_CONFUSED_MOVE);
Traveller<T> traveller(unit);
if (i_destinationHolder.UpdateTraveller(traveller, diff, false))
{
if (!IsActive(unit)) // force stop processing (movement can move out active zone with cleanup movegens list)
return true; // not expire now, but already lost
if (i_destinationHolder.HasArrived())
if (unit.movespline->Finalized())
{
// arrived, stop and wait a bit
unit.StopMoving();
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
unit.addUnitState(UNIT_STAT_CONFUSED_MOVE);
MANGOS_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);
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;
@ -161,7 +150,6 @@ template<>
void ConfusedMovementGenerator<Creature>::Finalize(Creature &unit)
{
unit.clearUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
unit.AddSplineFlag(SPLINEFLAG_WALKMODE);
}
template void ConfusedMovementGenerator<Player>::Initialize(Player &player);

View file

@ -20,8 +20,6 @@
#define MANGOS_CONFUSEDMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "Traveller.h"
#define MAX_CONF_WAYPOINTS 24
@ -43,7 +41,6 @@ class MANGOS_DLL_SPEC ConfusedMovementGenerator
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

View file

@ -45,6 +45,8 @@
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "movement/MoveSplineInit.h"
#include "movement/MoveSpline.h"
// apply implementation of the singletons
#include "Policies/SingletonImp.h"
@ -163,7 +165,7 @@ m_subtype(subtype), m_defaultMovementType(IDLE_MOTION_TYPE), m_equipmentId(0),
m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false),
m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false),
m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_temporaryFactionFlags(TEMPFACTION_NONE),
m_creatureInfo(NULL), m_splineFlags(SPLINEFLAG_WALKMODE)
m_creatureInfo(NULL)
{
m_regenTimer = 200;
m_valuesCount = UNIT_END;
@ -173,8 +175,6 @@ m_creatureInfo(NULL), m_splineFlags(SPLINEFLAG_WALKMODE)
m_CreatureSpellCooldowns.clear();
m_CreatureCategoryCooldowns.clear();
m_splineFlags = SPLINEFLAG_WALKMODE;
}
Creature::~Creature()
@ -322,6 +322,8 @@ bool Creature::InitEntry(uint32 Entry, CreatureData const* data /*=NULL*/, GameE
UpdateSpeed(MOVE_WALK, false);
UpdateSpeed(MOVE_RUN, false);
SetLevitate(CanFly());
// checked at loading
m_defaultMovementType = MovementGeneratorType(cinfo->MovementType);
@ -1484,8 +1486,6 @@ void Creature::SetDeathState(DeathState s)
SetHealth(GetMaxHealth());
SetLootRecipient(NULL);
AddSplineFlag(SPLINEFLAG_WALKMODE);
if (GetTemporaryFactionFlags() & TEMPFACTION_RESTORE_RESPAWN)
ClearTemporaryFaction();
@ -1530,25 +1530,19 @@ bool Creature::FallGround()
Unit::SetDeathState(CORPSE_FALLING);
float dz = tz - GetPositionZ();
float distance = sqrt(dz*dz);
// default run speed * 2 explicit, not verified though but result looks proper
double speed = baseMoveSpeed[MOVE_RUN] * 2;
speed *= 0.001; // to milliseconds
uint32 travelTime = uint32(distance/speed);
DEBUG_LOG("FallGround: traveltime: %u, distance: %f, speed: %f, from %f to %f", travelTime, distance, speed, GetPositionZ(), tz);
// For creatures that are moving towards target and dies, the visual effect is not nice.
// It is possibly caused by a xyz mismatch in DestinationHolder's GetLocationNow and the location
// of the mob in client. For mob that are already reached target or dies while not moving
// the visual appear to be fairly close to the expected.
Movement::MoveSplineInit init(*this);
init.MoveTo(GetPositionX(),GetPositionY(),tz);
init.SetFall();
init.Launch();
// hacky solution: by some reason died creatures not updated, that's why need finalize movement state
GetMap()->CreatureRelocation(this, GetPositionX(), GetPositionY(), tz, GetOrientation());
SendMonsterMove(GetPositionX(), GetPositionY(), tz, SPLINETYPE_NORMAL, SPLINEFLAG_FALLING, travelTime);
movespline->_Finalize();
return true;
}
@ -1955,8 +1949,8 @@ bool Creature::LoadCreatureAddon(bool reload)
if (cainfo->emote != 0)
SetUInt32Value(UNIT_NPC_EMOTESTATE, cainfo->emote);
if (cainfo->splineFlags != 0)
SetSplineFlags(SplineFlags(cainfo->splineFlags));
if (cainfo->splineFlags & SPLINEFLAG_FLYING)
SetLevitate(true);
if(cainfo->auras)
{
@ -2387,13 +2381,6 @@ void Creature::SetActiveObjectState( bool on )
map->Add(this);
}
void Creature::SendMonsterMoveWithSpeedToCurrentDestination(Player* player)
{
float x, y, z;
if (!IsStopped() && GetMotionMaster()->GetDestination(x, y, z))
SendMonsterMoveWithSpeed(x, y, z, 0, player);
}
void Creature::SendAreaSpiritHealerQueryOpcode(Player *pl)
{
uint32 next_resurrect = 0;
@ -2490,3 +2477,26 @@ bool Creature::HasStaticDBSpawnData() const
{
return sObjectMgr.GetCreatureData(GetGUIDLow()) != NULL;
}
void Creature::SetWalk(bool enable)
{
if (enable)
m_movementInfo.AddMovementFlag(MOVEFLAG_WALK_MODE);
else
m_movementInfo.RemoveMovementFlag(MOVEFLAG_WALK_MODE);
WorldPacket data(enable ? SMSG_SPLINE_MOVE_SET_WALK_MODE : SMSG_SPLINE_MOVE_SET_RUN_MODE, 9);
data << GetPackGUID();
SendMessageToSet(&data, true);
UpdateWalkMode(this, false);
}
void Creature::SetLevitate(bool enable)
{
if (enable)
m_movementInfo.AddMovementFlag(MOVEFLAG_LEVITATING);
else
m_movementInfo.RemoveMovementFlag(MOVEFLAG_LEVITATING);
WorldPacket data(enable ? SMSG_SPLINE_MOVE_GRAVITY_DISABLE : SMSG_SPLINE_MOVE_GRAVITY_ENABLE, 9);
data << GetPackGUID();
SendMessageToSet(&data, true);
}

View file

@ -516,31 +516,10 @@ class MANGOS_DLL_SPEC Creature : public Unit
CreatureAI* AI() { return i_AI; }
void AddSplineFlag(SplineFlags f)
{
bool need_walk_sync = (f & SPLINEFLAG_WALKMODE) != (m_splineFlags & SPLINEFLAG_WALKMODE);
m_splineFlags = SplineFlags(m_splineFlags | f);
if (need_walk_sync)
UpdateWalkMode(this, false);
}
void RemoveSplineFlag(SplineFlags f)
{
bool need_walk_sync = (f & SPLINEFLAG_WALKMODE) != (m_splineFlags & SPLINEFLAG_WALKMODE);
m_splineFlags = SplineFlags(m_splineFlags & ~f);
if (need_walk_sync)
UpdateWalkMode(this, false);
}
bool HasSplineFlag(SplineFlags f) const { return m_splineFlags & f; }
SplineFlags GetSplineFlags() const { return m_splineFlags; }
void SetSplineFlags(SplineFlags f)
{
bool need_walk_sync = (f & SPLINEFLAG_WALKMODE) != (m_splineFlags & SPLINEFLAG_WALKMODE);
m_splineFlags = f; // need set before
if (need_walk_sync)
UpdateWalkMode(this, false);
}
void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL);
void SetWalk(bool enable);
void SetLevitate(bool enable);
bool IsLevitating() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_LEVITATING);}
bool IsWalking() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_WALK_MODE);}
uint32 GetShieldBlockValue() const // dunno mob block value
{
@ -762,7 +741,6 @@ class MANGOS_DLL_SPEC Creature : public Unit
private:
GridReference<Creature> m_gridRef;
CreatureInfo const* m_creatureInfo; // in difficulty mode > 0 can different from ObjMgr::GetCreatureTemplate(GetEntry())
SplineFlags m_splineFlags;
};
class AssistDelayEvent : public BasicEvent

View file

@ -1,63 +0,0 @@
/*
* 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 MANGOS_DESTINATION_HOLDER_H
#define MANGOS_DESTINATION_HOLDER_H
#include "Platform/Define.h"
#include "Timer.h"
class WorldObject;
class Map;
#define TRAVELLER_UPDATE_INTERVAL 300
template<typename TRAVELLER>
class MANGOS_DLL_DECL DestinationHolder
{
ShortTimeTracker 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; }
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 force_update=false, 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

View file

@ -1,233 +0,0 @@
/*
* 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 MANGOS_DESTINATIONHOLDERIMP_H
#define MANGOS_DESTINATIONHOLDERIMP_H
#include "MapManager.h"
#include "DestinationHolder.h"
#include "Unit.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.GetTotalTravelTimeTo(i_destX,i_destY,i_destZ);
i_timeElapsed = 0;
if(sendMove)
{
if (i_totalTravelTime)
traveller.MoveTo(i_destX, i_destY, i_destZ, i_totalTravelTime);
else
traveller.Stop();
}
return i_totalTravelTime;
}
template<typename TRAVELLER>
bool
DestinationHolder<TRAVELLER>::UpdateTraveller(TRAVELLER &traveller, uint32 diff, bool force_update, bool micro_movement)
{
if (!micro_movement)
{
i_tracker.Update(diff);
i_timeElapsed += diff;
if (i_tracker.Passed() || force_update)
{
ResetUpdate();
if (!i_destSet)
return true;
float x,y,z;
GetLocationNowNoMicroMovement(x, y, 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;
}
return false;
}
i_tracker.Update(diff);
i_timeElapsed += diff;
if (i_tracker.Passed() || force_update)
{
ResetUpdate();
if (!i_destSet) return true;
if (!traveller.GetTraveller().hasUnitState(UNIT_STAT_MOVING | UNIT_STAT_TAXI_FLIGHT))
return true;
float x,y,z;
if (traveller.GetTraveller().hasUnitState(UNIT_STAT_TAXI_FLIGHT))
GetLocationNow(traveller.GetTraveller().GetMap() ,x, y, z, true); // Should reposition Object with right Coord, so I can bypass some Grid Relocation
else
GetLocationNow(traveller.GetTraveller().GetMap(), x, y, z, false);
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);
}
// 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;
return true;
}
return false;
}
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->GetTerrain()->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 = i_fromX + float((i_destX - i_fromX) * percent_passed);
y = i_fromY + float((i_destY - i_fromY) * percent_passed);
z = i_fromZ + float((i_destZ - i_fromZ) * percent_passed);
}
}
#endif

View file

@ -20,8 +20,9 @@
#include "CreatureAI.h"
#include "MapManager.h"
#include "FleeingMovementGenerator.h"
#include "DestinationHolderImp.h"
#include "ObjectAccessor.h"
#include "movement/MoveSplineInit.h"
#include "movement/MoveSpline.h"
#define MIN_QUIET_DISTANCE 28.0f
#define MAX_QUIET_DISTANCE 43.0f
@ -45,8 +46,11 @@ FleeingMovementGenerator<T>::_setTargetLocation(T &owner)
return;
owner.addUnitState(UNIT_STAT_FLEEING_MOVE);
Traveller<T> traveller(owner);
i_destinationHolder.SetDestination(traveller, x, y, z);
Movement::MoveSplineInit init(owner);
init.MoveTo(x,y,z);
init.SetWalk(false);
init.Launch();
}
template<class T>
@ -308,7 +312,6 @@ template<>
void
FleeingMovementGenerator<Creature>::_Init(Creature &owner)
{
owner.RemoveSplineFlag(SPLINEFLAG_WALKMODE);
owner.SetTargetGuid(ObjectGuid());
is_water_ok = owner.CanSwim();
is_land_ok = owner.CanWalk();
@ -331,7 +334,6 @@ void FleeingMovementGenerator<Player>::Finalize(Player &owner)
template<>
void FleeingMovementGenerator<Creature>::Finalize(Creature &owner)
{
owner.AddSplineFlag(SPLINEFLAG_WALKMODE);
owner.clearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
}
@ -361,28 +363,10 @@ bool FleeingMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
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, false))
{
if (!IsActive(owner)) // force stop processing (movement can move out active zone with cleanup movegens list)
return true; // not expire now, but already lost
i_destinationHolder.ResetUpdate(50);
if(i_nextCheckTime.Passed() && i_destinationHolder.HasArrived())
{
_setTargetLocation(owner);
return true;
}
}
return true;
}

View file

@ -20,8 +20,6 @@
#define MANGOS_FLEEINGMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "Traveller.h"
#include "ObjectGuid.h"
template<class T>
@ -57,8 +55,6 @@ class MANGOS_DLL_SPEC FleeingMovementGenerator
float i_cur_angle;
ObjectGuid i_frightGuid;
TimeTracker i_nextCheckTime;
DestinationHolder< Traveller<T> > i_destinationHolder;
};
class MANGOS_DLL_SPEC TimedFleeingMovementGenerator

View file

@ -94,10 +94,6 @@ VisibleNotifier::Notify()
// target aura duration for caster show only if target exist at caster client
if ((*vItr) != &player && (*vItr)->isType(TYPEMASK_UNIT))
player.SendAurasForTarget((Unit*)(*vItr));
// non finished movements show to player
if ((*vItr)->GetTypeId()==TYPEID_UNIT && ((Creature*)(*vItr))->isAlive())
((Creature*)(*vItr))->SendMonsterMoveWithSpeedToCurrentDestination(&player);
}
}

View file

@ -19,14 +19,13 @@
#include "HomeMovementGenerator.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "Traveller.h"
#include "DestinationHolderImp.h"
#include "ObjectMgr.h"
#include "WorldPacket.h"
#include "movement/MoveSplineInit.h"
#include "movement/MoveSpline.h"
void HomeMovementGenerator<Creature>::Initialize(Creature & owner)
{
owner.RemoveSplineFlag(SPLINEFLAG_WALKMODE);
_setTargetLocation(owner);
}
@ -39,56 +38,30 @@ void HomeMovementGenerator<Creature>::_setTargetLocation(Creature & owner)
if (owner.hasUnitState(UNIT_STAT_NOT_MOVE))
return;
float x, y, z;
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.GetRespawnCoord(x, y, z);
{
owner.GetRespawnCoord(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(UNIT_STAT_ALL_STATE);
}
bool HomeMovementGenerator<Creature>::Update(Creature &owner, const uint32& time_diff)
{
CreatureTraveller traveller( owner);
if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false))
{
if (!IsActive(owner)) // force stop processing (movement can move out active zone with cleanup movegens list)
return true; // not expire now, but already lost
}
if (time_diff >= i_travel_timer)
{
i_travel_timer = 0; // Used as check in Finalize
return false;
}
i_travel_timer -= time_diff;
return true;
return !owner.movespline->Finalized();
}
void HomeMovementGenerator<Creature>::Finalize(Creature& owner)
{
if (i_travel_timer == 0)
{
owner.AddSplineFlag(SPLINEFLAG_WALKMODE);
// restore orientation of not moving creature at returning to home
if (owner.GetDefaultMovementType() == IDLE_MOTION_TYPE)
{
// such a mob might need very exact spawning point, hence relocate to spawn-position
if (CreatureData const* data = sObjectMgr.GetCreatureData(owner.GetGUIDLow()))
{
owner.Relocate(data->posX, data->posY, data->posZ, data->orientation);
owner.SendHeartBeat(false);
}
}
if (owner.GetTemporaryFactionFlags() & TEMPFACTION_RESTORE_REACH_HOME)
owner.ClearTemporaryFaction();

View file

@ -20,8 +20,6 @@
#define MANGOS_HOMEMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "Traveller.h"
class Creature;
@ -45,11 +43,8 @@ class MANGOS_DLL_SPEC HomeMovementGenerator<Creature>
void modifyTravelTime(uint32 travel_time) { i_travel_timer = travel_time; }
MovementGeneratorType GetMovementGeneratorType() const { 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;
uint32 i_travel_timer;
};
#endif

View file

@ -6015,6 +6015,8 @@ bool ChatHandler::HandleMovegensCommand(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(MotionMaster::const_iterator itr = mm->begin(); itr != mm->end(); ++itr)
{
switch((*itr)->GetMovementGeneratorType())
@ -6058,8 +6060,6 @@ bool ChatHandler::HandleMovegensCommand(char* /*args*/)
case HOME_MOTION_TYPE:
if(unit->GetTypeId()==TYPEID_UNIT)
{
float x,y,z;
(*itr)->GetDestination(x,y,z);
PSendSysMessage(LANG_MOVEGENS_HOME_CREATURE,x,y,z);
}
else
@ -6068,8 +6068,6 @@ bool ChatHandler::HandleMovegensCommand(char* /*args*/)
case FLIGHT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FLIGHT); break;
case POINT_MOTION_TYPE:
{
float x,y,z;
(*itr)->GetDestination(x,y,z);
PSendSysMessage(LANG_MOVEGENS_POINT,x,y,z);
break;
}
@ -6289,12 +6287,6 @@ bool ChatHandler::HandleComeToMeCommand(char *args)
return false;
}
uint32 newFlags;
if (!ExtractUInt32(&args, newFlags))
return false;
caster->SetSplineFlags(SplineFlags(newFlags));
Player* pl = m_session->GetPlayer();
caster->GetMotionMaster()->MovePoint(0, pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ());

View file

@ -1924,6 +1924,7 @@ void Map::ScriptsProcess()
source->SetUInt32Value(step.script->setField.fieldId, step.script->setField.fieldValue);
break;
case SCRIPT_COMMAND_MOVE_TO:
{
if (!source)
{
sLog.outError("SCRIPT_COMMAND_MOVE_TO (script id %u) call for NULL creature.", step.script->id);
@ -1936,8 +1937,16 @@ void Map::ScriptsProcess()
break;
}
((Unit*)source)->MonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, step.script->moveTo.travelTime);
Unit * unit = (Unit*)source;
if (step.script->moveTo.travelTime != 0)
{
float speed = unit->GetDistance(step.script->x, step.script->y, step.script->z) / ((float)step.script->moveTo.travelTime * 0.001f);
unit->MonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, speed);
}
else
unit->NearTeleportTo(step.script->x, step.script->y, step.script->z, unit->GetOrientation());
break;
}
case SCRIPT_COMMAND_FLAG_SET:
if (!source)
{
@ -2791,10 +2800,7 @@ void Map::ScriptsProcess()
break;
}
if (step.script->run.run)
pOwner->RemoveSplineFlag(SPLINEFLAG_WALKMODE);
else
pOwner->AddSplineFlag(SPLINEFLAG_WALKMODE);
pOwner->SetWalk(!step.script->run.run);
break;
}

View file

@ -23,7 +23,6 @@
#include "Log.h"
#include "Transports.h"
#include "GridDefines.h"
#include "DestinationHolderImp.h"
#include "World.h"
#include "CellImpl.h"
#include "Corpse.h"

View file

@ -19,8 +19,6 @@
#include "MotionMaster.h"
#include "CreatureAISelector.h"
#include "Creature.h"
#include "Traveller.h"
#include "ConfusedMovementGenerator.h"
#include "FleeingMovementGenerator.h"
#include "HomeMovementGenerator.h"
@ -29,6 +27,7 @@
#include "TargetedMovementGenerator.h"
#include "WaypointMovementGenerator.h"
#include "RandomMovementGenerator.h"
#include "movement/MoveSpline.h"
#include <cassert>
@ -448,10 +447,14 @@ MovementGeneratorType MotionMaster::GetCurrentMovementGeneratorType() const
bool MotionMaster::GetDestination(float &x, float &y, float &z)
{
if (empty())
if (m_owner->movespline->Finalized())
return false;
return top()->GetDestination(x,y,z);
const G3D::Vector3& dest = m_owner->movespline->FinalDestination();
x = dest.x;
y = dest.y;
z = dest.z;
return true;
}
void MotionMaster::UpdateFinalDistanceToTarget(float fDistance)

View file

@ -51,8 +51,6 @@ class MANGOS_DLL_SPEC MovementGenerator
virtual void UpdateFinalDistance(float /*fDistance*/) { }
virtual bool GetDestination(float& /*x*/, float& /*y*/, float& /*z*/) const { return false; }
// used by Evade code for select point to evade with expected restart default movement
virtual bool GetResetPosition(Unit &, float& /*x*/, float& /*y*/, float& /*z*/) { return false; }

View file

@ -39,10 +39,9 @@
#include "CellImpl.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "ObjectPosSelector.h"
#include "TemporarySummon.h"
#include "movement/packet_builder.h"
Object::Object( )
{
@ -256,57 +255,13 @@ void Object::BuildMovementUpdate(ByteBuffer * data, uint16 updateFlags) const
{
Unit *unit = ((Unit*)this);
switch(GetTypeId())
{
case TYPEID_UNIT:
{
unit->m_movementInfo.SetMovementFlags(MOVEFLAG_NONE);
// disabled, makes them run-in-same-place before movement generator updated once.
/*if (((Creature*)unit)->hasUnitState(UNIT_STAT_MOVING))
unit->m_movementInfo.SetMovementFlags(MOVEFLAG_FORWARD);*/
if (((Creature*)unit)->CanFly())
{
// (ok) most seem to have this
unit->m_movementInfo.AddMovementFlag(MOVEFLAG_LEVITATING);
/*if (!((Creature*)unit)->hasUnitState(UNIT_STAT_MOVING))
{
// (ok) possibly some "hover" mode
unit->m_movementInfo.AddMovementFlag(MOVEFLAG_ROOT);
}
else*/
{
if (((Creature*)unit)->IsMounted())
{
// seems to be often when mounted
unit->m_movementInfo.AddMovementFlag(MOVEFLAG_FLYING);
}
}
}
}
break;
case TYPEID_PLAYER:
if (GetTypeId() == TYPEID_PLAYER)
{
Player *player = ((Player*)unit);
if(player->GetTransport())
player->m_movementInfo.AddMovementFlag(MOVEFLAG_ONTRANSPORT);
else
player->m_movementInfo.RemoveMovementFlag(MOVEFLAG_ONTRANSPORT);
// remove unknown, unused etc flags for now
player->m_movementInfo.RemoveMovementFlag(MOVEFLAG_SPLINE_ENABLED);
if(player->IsTaxiFlying())
{
MANGOS_ASSERT(player->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE);
player->m_movementInfo.AddMovementFlag(MOVEFLAG_FORWARD);
player->m_movementInfo.AddMovementFlag(MOVEFLAG_SPLINE_ENABLED);
}
}
break;
}
// Update movement info time
@ -326,86 +281,8 @@ void Object::BuildMovementUpdate(ByteBuffer * data, uint16 updateFlags) const
*data << float(unit->GetSpeed(MOVE_PITCH_RATE));
// 0x08000000
if(unit->m_movementInfo.GetMovementFlags() & MOVEFLAG_SPLINE_ENABLED)
{
if(GetTypeId() != TYPEID_PLAYER)
{
DEBUG_LOG("_BuildMovementUpdate: MOVEFLAG_SPLINE_ENABLED for non-player");
return;
}
Player *player = ((Player*)unit);
if(!player->IsTaxiFlying())
{
DEBUG_LOG("_BuildMovementUpdate: MOVEFLAG_SPLINE_ENABLED but not in flight");
return;
}
MANGOS_ASSERT(player->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE);
FlightPathMovementGenerator *fmg = (FlightPathMovementGenerator*)(player->GetMotionMaster()->top());
uint32 flags3 = SPLINEFLAG_WALKMODE | SPLINEFLAG_FLYING;
*data << uint32(flags3); // splines flag?
if(flags3 & SPLINEFLAG_FINALFACING) // may be orientation
{
*data << float(0);
}
else
{
if(flags3 & SPLINEFLAG_FINALTARGET) // probably guid there
{
*data << uint64(0);
}
else
{
if(flags3 & SPLINEFLAG_FINALPOINT) // probably x,y,z coords there
{
*data << float(0);
*data << float(0);
*data << float(0);
}
}
}
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); // sequenceId
*data << float(0); // added in 3.1
*data << float(0); // added in 3.1
// data as in SMSG_MONSTER_MOVE with flag SPLINEFLAG_TRAJECTORY
*data << float(0); // parabolic speed, added in 3.1
*data << uint32(0); // parabolic time, 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); // splineMode
*data << float(path[poscount-1].x);
*data << float(path[poscount-1].y);
*data << float(path[poscount-1].z);
}
if (unit->m_movementInfo.GetMovementFlags() & MOVEFLAG_SPLINE_ENABLED)
Movement::PacketBuilder::WriteCreate(*unit->movespline, *data);
}
else
{

View file

@ -20034,9 +20034,6 @@ void Player::UpdateVisibilityOf(WorldObject const* viewPoint, WorldObject* targe
// send data at target visibility change (adding to client)
if(target!=this && target->isType(TYPEMASK_UNIT))
SendAurasForTarget((Unit*)target);
if(target->GetTypeId()==TYPEID_UNIT && ((Creature*)target)->isAlive())
((Creature*)target)->SendMonsterMoveWithSpeedToCurrentDestination(this);
}
}
}

View file

@ -21,8 +21,9 @@
#include "Creature.h"
#include "CreatureAI.h"
#include "TemporarySummon.h"
#include "DestinationHolderImp.h"
#include "World.h"
#include "movement/MoveSplineInit.h"
#include "movement/MoveSpline.h"
//----- Point Movement Generator
template<class T>
@ -32,12 +33,9 @@ void PointMovementGenerator<T>::Initialize(T &unit)
unit.StopMoving();
unit.addUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
Traveller<T> traveller(unit);
i_destinationHolder.SetDestination(traveller, i_x, i_y, i_z);
if (unit.GetTypeId() == TYPEID_UNIT && ((Creature*)&unit)->CanFly())
((Creature&)unit).AddSplineFlag(SPLINEFLAG_FLYING);
Movement::MoveSplineInit init(unit);
init.MoveTo(i_x, i_y, i_z);
init.Launch();
}
template<class T>
@ -45,7 +43,7 @@ void PointMovementGenerator<T>::Finalize(T &unit)
{
unit.clearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
if (i_destinationHolder.HasArrived())
if (unit.movespline->Finalized())
MovementInform(unit);
}
@ -77,18 +75,7 @@ bool PointMovementGenerator<T>::Update(T &unit, const uint32 &diff)
}
unit.addUnitState(UNIT_STAT_ROAMING_MOVE);
Traveller<T> traveller(unit);
if (i_destinationHolder.UpdateTraveller(traveller, diff, false))
{
if (!IsActive(unit)) // force stop processing (movement can move out active zone with cleanup movegens list)
return true; // not expire now, but already lost
}
if (i_destinationHolder.HasArrived())
return false;
return true;
return !unit.movespline->Finalized();
}
template<>

View file

@ -20,8 +20,6 @@
#define MANGOS_POINTMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "Traveller.h"
#include "FollowerReference.h"
template<class T>
@ -47,7 +45,6 @@ class MANGOS_DLL_SPEC PointMovementGenerator
uint32 id;
float i_x,i_y,i_z;
TimeTracker i_nextMoveTime;
DestinationHolder< Traveller<T> > i_destinationHolder;
};
class MANGOS_DLL_SPEC AssistanceMovementGenerator

View file

@ -19,9 +19,10 @@
#include "Creature.h"
#include "MapManager.h"
#include "RandomMovementGenerator.h"
#include "DestinationHolderImp.h"
#include "Map.h"
#include "Util.h"
#include "movement/MoveSplineInit.h"
#include "movement/MoveSpline.h"
template<>
void
@ -91,15 +92,17 @@ RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
}
}
creature.AddSplineFlag(is_air_ok ? SPLINEFLAG_FLYING : SPLINEFLAG_WALKMODE);
Traveller<Creature> traveller(creature);
i_destinationHolder.SetDestination(traveller, destX, destY, destZ);
if (is_air_ok)
i_nextMoveTime.Reset(0);
else
i_nextMoveTime.Reset(urand(500, 10000));
creature.addUnitState(UNIT_STAT_ROAMING_MOVE);
if (is_air_ok)
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
else
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime() + urand(500, 10000));
Movement::MoveSplineInit init(creature);
init.MoveTo(destX, destY, destZ);
init.SetWalk(true);
init.Launch();
}
template<>
@ -108,11 +111,6 @@ void RandomMovementGenerator<Creature>::Initialize(Creature &creature)
if (!creature.isAlive())
return;
if (creature.CanFly())
creature.AddSplineFlag(SPLINEFLAG_FLYING);
else
creature.AddSplineFlag(SPLINEFLAG_WALKMODE);
creature.addUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
_setRandomLocation(creature);
}
@ -127,12 +125,14 @@ template<>
void RandomMovementGenerator<Creature>::Interrupt(Creature &creature)
{
creature.clearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
creature.SetWalk(false);
}
template<>
void RandomMovementGenerator<Creature>::Finalize(Creature &creature)
{
creature.clearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
creature.SetWalk(false);
}
template<>
@ -145,17 +145,12 @@ bool RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32
return true;
}
CreatureTraveller traveller(creature);
if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true))
if (creature.movespline->Finalized())
{
if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list)
return true; // not expire now, but already lost
}
i_nextMoveTime.Update(diff);
if (i_nextMoveTime.Passed())
_setRandomLocation(creature);
}
return true;
}

View file

@ -20,8 +20,6 @@
#define MANGOS_RANDOMMOTIONGENERATOR_H
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "Traveller.h"
template<class T>
class MANGOS_DLL_SPEC RandomMovementGenerator
@ -36,17 +34,11 @@ class MANGOS_DLL_SPEC RandomMovementGenerator
void Interrupt(T &);
void Reset(T &);
bool Update(T &, const uint32 &);
void UpdateMapPosition(uint32 mapid, float &x ,float &y, float &z)
{
i_destinationHolder.GetLocationNow(mapid, x,y,z);
}
MovementGeneratorType GetMovementGeneratorType() const { return RANDOM_MOTION_TYPE; }
bool GetResetPosition(T&, float& x, float& y, float& z);
private:
ShortTimeTracker i_nextMoveTime;
DestinationHolder< Traveller<T> > i_destinationHolder;
uint32 i_nextMove;
};

View file

@ -4056,7 +4056,6 @@ void Aura::HandleModPossessPet(bool apply, bool Real)
else
{
pet->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
pet->AddSplineFlag(SPLINEFLAG_WALKMODE);
}
}
}

View file

@ -2069,7 +2069,7 @@ void Spell::EffectDummy(SpellEffectIndex eff_idx)
if (unitTarget->hasUnitState(UNIT_STAT_FOLLOW | UNIT_STAT_FOLLOW_MOVE))
unitTarget->GetMotionMaster()->MovementExpired();
unitTarget->MonsterMove(pTargetDummy->GetPositionX(), pTargetDummy->GetPositionY(), pTargetDummy->GetPositionZ(), IN_MILLISECONDS);
unitTarget->MonsterMoveWithSpeed(pTargetDummy->GetPositionX(), pTargetDummy->GetPositionY(), pTargetDummy->GetPositionZ(), 24.f);
// Add state to temporarily prevent follow
unitTarget->addUnitState(UNIT_STAT_ROOT);
@ -2356,7 +2356,7 @@ void Spell::EffectDummy(SpellEffectIndex eff_idx)
}
case 64385: // Spinning (from Unusual Compass)
{
m_caster->SetFacingTo(frand(0, M_PI_F*2), true);
m_caster->SetFacingTo(frand(0, M_PI_F*2));
return;
}
case 64981: // Summon Random Vanquished Tentacle
@ -4921,11 +4921,8 @@ void Spell::EffectDistract(SpellEffectIndex /*eff_idx*/)
if (unitTarget->hasUnitState(UNIT_STAT_CAN_NOT_REACT))
return;
float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
unitTarget->SetFacingTo(unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY));
unitTarget->clearUnitState(UNIT_STAT_MOVING);
unitTarget->SetOrientation(angle);
unitTarget->SendMonsterMove(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), SPLINETYPE_FACINGANGLE, SPLINEFLAG_WALKMODE, 0, NULL, angle);
if (unitTarget->GetTypeId() == TYPEID_UNIT)
unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS);
@ -8428,7 +8425,7 @@ void Spell::EffectCharge(SpellEffectIndex /*eff_idx*/)
((Creature *)unitTarget)->StopMoving();
// Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
m_caster->MonsterMove(x, y, z, 1);
m_caster->MonsterMoveWithSpeed(x, y, z, 24.f);
// not all charge effects used in negative spells
if (unitTarget != m_caster && !IsPositiveSpell(m_spellInfo->Id))
@ -8453,7 +8450,7 @@ void Spell::EffectCharge2(SpellEffectIndex /*eff_idx*/)
return;
// Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
m_caster->MonsterMove(x, y, z, 1);
m_caster->MonsterMoveWithSpeed(x, y, z, 24.f);
// not all charge effects used in negative spells
if (unitTarget && unitTarget != m_caster && !IsPositiveSpell(m_spellInfo->Id))

View file

@ -20,8 +20,9 @@
#include "TargetedMovementGenerator.h"
#include "Errors.h"
#include "Creature.h"
#include "DestinationHolderImp.h"
#include "World.h"
#include "movement/MoveSplineInit.h"
#include "movement/MoveSpline.h"
#define SMALL_ALPHA 0.05f
@ -42,7 +43,7 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner)
// prevent redundant micro-movement for pets, other followers.
if (i_offset && i_target->IsWithinDistInMap(&owner,2*i_offset))
{
if (i_destinationHolder.HasDestination())
if (!owner.movespline->Finalized())
return;
owner.GetPosition(x, y, z);
@ -74,14 +75,15 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner)
if( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize )
return;
*/
if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->CanFly())
((Creature&)owner).AddSplineFlag(SPLINEFLAG_FLYING);
D::_addUnitStateMove(owner);
i_targetReached = false;
i_recalculateTravel = false;
D::_addUnitStateMove(owner);
Traveller<T> traveller(owner);
i_destinationHolder.SetDestination(traveller, x, y, z);
Movement::MoveSplineInit init(owner);
init.MoveTo(x,y,z);
init.Launch();
}
template<>
@ -140,21 +142,19 @@ bool TargetedMovementGeneratorMedium<T,D>::Update(T &owner, const uint32 & time_
return true;
}
Traveller<T> traveller(owner);
if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false))
i_recheckDistance.Update(time_diff);
if (i_recheckDistance.Passed())
{
if (!IsActive(owner)) // force stop processing (movement can move out active zone with cleanup movegens list)
return true;
i_destinationHolder.ResetUpdate(50);
//More distance let have better performance, less distance let have more sensitive reaction at target move.
float dist = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius()
float allowed_dist = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius()
+ sWorld.getConfig(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE);
if (i_destinationHolder.GetDistance3dFromDestSq(*i_target.getTarget()) > dist * dist)
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.HasArrived())
if (owner.movespline->Finalized())
{
if (i_angle == 0.f && !owner.HasInArc(0.01f, i_target.getTarget()))
owner.SetInFront(i_target.getTarget());
@ -191,12 +191,8 @@ void ChaseMovementGenerator<Player>::Initialize(Player &owner)
template<>
void ChaseMovementGenerator<Creature>::Initialize(Creature &owner)
{
owner.SetWalk(false);
owner.addUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE);
owner.RemoveSplineFlag(SPLINEFLAG_WALKMODE);
if (((Creature*)&owner)->CanFly())
owner.AddSplineFlag(SPLINEFLAG_FLYING);
_setTargetLocation(owner);
}
@ -264,10 +260,6 @@ void FollowMovementGenerator<Creature>::Initialize(Creature &owner)
owner.addUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE);
_updateWalkMode(owner);
_updateSpeed(owner);
if (((Creature*)&owner)->CanFly())
owner.AddSplineFlag(SPLINEFLAG_FLYING);
_setTargetLocation(owner);
}

View file

@ -20,8 +20,6 @@
#define MANGOS_TARGETEDMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "Traveller.h"
#include "FollowerReference.h"
class MANGOS_DLL_SPEC TargetedMovementGeneratorBase
@ -38,12 +36,11 @@ class MANGOS_DLL_SPEC TargetedMovementGeneratorMedium
: public MovementGeneratorMedium< T, D >, public TargetedMovementGeneratorBase
{
protected:
TargetedMovementGeneratorMedium(Unit &target, float offset = 0.f, float angle = 0.f) :
TargetedMovementGeneratorMedium(Unit &target, float offset, float angle) :
TargetedMovementGeneratorBase(target), i_offset(offset), i_angle(angle),
i_recalculateTravel(false), i_targetReached(false)
i_recalculateTravel(false), i_targetReached(false), i_recheckDistance(0)
{
}
~TargetedMovementGeneratorMedium() {}
public:
@ -51,22 +48,15 @@ class MANGOS_DLL_SPEC TargetedMovementGeneratorMedium
Unit* GetTarget() const { return i_target.getTarget(); }
bool GetDestination(float &x, float &y, float &z) const
{
if(!i_destinationHolder.HasDestination()) return false;
i_destinationHolder.GetDestination(x,y,z);
return true;
}
void unitSpeedChanged() { i_recalculateTravel=true; }
void UpdateFinalDistance(float fDistance);
protected:
void _setTargetLocation(T &);
ShortTimeTracker i_recheckDistance;
float i_offset;
float i_angle;
DestinationHolder< Traveller<T> > i_destinationHolder;
bool i_recalculateTravel : 1;
bool i_targetReached : 1;
};

View file

@ -27,7 +27,6 @@
#include "UpdateMask.h"
#include "Path.h"
#include "WaypointMovementGenerator.h"
#include "DestinationHolderImp.h"
void WorldSession::HandleTaxiNodeStatusQueryOpcode( WorldPacket & recv_data )
{

View file

@ -1,163 +0,0 @@
/*
* 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 MANGOS_TRAVELLER_H
#define MANGOS_TRAVELLER_H
#include "Common.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 MANGOS_DLL_DECL Traveller
{
T &i_traveller;
Traveller(T &t) : i_traveller(t) {}
Traveller(const Traveller &obj) : i_traveller(obj) {}
Traveller& operator=(const Traveller &obj)
{
~Traveller();
new (this) Traveller(obj);
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) { MANGOS_ASSERT(false); return 0.0f; }
float GetMoveDestinationTo(float x, float y, float z);
uint32 GetTotalTravelTimeTo(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) {}
void Stop() {}
};
template<class T>
inline uint32 Traveller<T>::GetTotalTravelTimeTo(float x, float y, float z)
{
float dist = GetMoveDestinationTo(x,y,z);
double speed = Speed();
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.HasSplineFlag(SPLINEFLAG_WALKMODE))
return i_traveller.GetSpeed(MOVE_WALK);
else if(i_traveller.HasSplineFlag(SPLINEFLAG_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.GetMap()->CreatureRelocation(&i_traveller, x, y, z, orientation);
}
template<>
inline float Traveller<Creature>::GetMoveDestinationTo(float x, float y, float z)
{
float dx = x - GetPositionX();
float dy = y - GetPositionY();
if (i_traveller.CanFly())
{
float dz = z - GetPositionZ();
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.SendMonsterMove(x, y, z, SPLINETYPE_NORMAL, i_traveller.GetSplineFlags(), t);
}
template<>
inline void Traveller<Creature>::Stop()
{
i_traveller.SendMonsterMove(i_traveller.GetPositionX(), i_traveller.GetPositionY(), i_traveller.GetPositionZ(), SPLINETYPE_STOP, i_traveller.GetSplineFlags(), 0);
}
// specialization for players
template<>
inline float Traveller<Player>::Speed()
{
if (i_traveller.IsTaxiFlying())
return PLAYER_FLIGHT_SPEED;
else
return i_traveller.GetSpeed(i_traveller.m_movementInfo.HasMovementFlag(MOVEFLAG_WALK_MODE) ? 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.IsTaxiFlying())
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.SetPosition(x, y, z, orientation);
}
template<>
inline void Traveller<Player>::MoveTo(float x, float y, float z, uint32 t)
{
//Only send SPLINEFLAG_WALKMODE, client has strange issues with other move flags
i_traveller.SendMonsterMove(x, y, z, SPLINETYPE_NORMAL, SPLINEFLAG_WALKMODE, t);
}
template<>
inline void Traveller<Player>::Stop()
{
//Only send SPLINEFLAG_WALKMODE, client has strange issues with other move flags
i_traveller.SendMonsterMove(i_traveller.GetPositionX(), i_traveller.GetPositionY(), i_traveller.GetPositionZ(), SPLINETYPE_STOP, SPLINEFLAG_WALKMODE, 0);
}
typedef Traveller<Creature> CreatureTraveller;
typedef Traveller<Player> PlayerTraveller;
#endif

View file

@ -45,10 +45,10 @@
#include "MapPersistentStateMgr.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "Path.h"
#include "Traveller.h"
#include "VMapFactory.h"
#include "MovementGenerator.h"
#include "movement/MoveSplineInit.h"
#include "movement/MoveSpline.h"
#include <math.h>
#include <stdarg.h>
@ -184,7 +184,8 @@ void GlobalCooldownMgr::CancelGlobalCooldown(SpellEntry const* spellInfo)
Unit::Unit() :
i_motionMaster(this), m_ThreatManager(this), m_HostileRefManager(this),
m_charmInfo(NULL),
m_vehicleInfo(NULL)
m_vehicleInfo(NULL),
movespline(new Movement::MoveSpline())
{
m_objectType |= TYPEMASK_UNIT;
m_objectTypeId = TYPEID_UNIT;
@ -279,6 +280,7 @@ Unit::~Unit()
delete m_charmInfo;
delete m_vehicleInfo;
delete movespline;
// those should be already removed at "RemoveFromWorld()" call
MANGOS_ASSERT(m_gameObj.size() == 0);
@ -345,7 +347,7 @@ void Unit::Update( uint32 update_diff, uint32 p_time )
ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, GetHealth() < GetMaxHealth()*0.20f);
ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, GetHealth() < GetMaxHealth()*0.35f);
ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, GetHealth() > GetMaxHealth()*0.75f);
UpdateSplineMovement(p_time);
i_motionMaster.UpdateMotion(p_time);
}
@ -360,83 +362,13 @@ bool Unit::haveOffhandWeapon() const
return false;
}
void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, SplineType type, SplineFlags flags, uint32 Time, Player* player, ...)
{
va_list vargs;
va_start(vargs,player);
float moveTime = (float)Time;
WorldPacket data( SMSG_MONSTER_MOVE, (41 + GetPackGUID().size()) );
data << GetPackGUID();
data << uint8(0); // new in 3.1 bool, used to toggle MOVEFLAG2_UNK4 = 0x0040 on client side
data << GetPositionX() << GetPositionY() << GetPositionZ();
data << uint32(WorldTimer::getMSTime());
data << uint8(type); // unknown
switch(type)
{
case SPLINETYPE_NORMAL: // normal packet
break;
case SPLINETYPE_STOP: // stop packet (raw pos?)
va_end(vargs);
SendMessageToSet( &data, true );
return;
case SPLINETYPE_FACINGSPOT: // facing spot, not used currently
{
data << float(va_arg(vargs,double));
data << float(va_arg(vargs,double));
data << float(va_arg(vargs,double));
break;
}
case SPLINETYPE_FACINGTARGET:
data << uint64(va_arg(vargs,uint64)); // ObjectGuid in fact
break;
case SPLINETYPE_FACINGANGLE:
data << float(va_arg(vargs,double)); // facing angle
break;
}
data << uint32(flags); // splineflags
data << uint32(moveTime); // Time in between points
data << uint32(1); // 1 single waypoint
data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B
va_end(vargs);
if(player)
player->GetSession()->SendPacket(&data);
else
SendMessageToSet( &data, true );
}
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.GetTotalTravelTimeTo(x, y, z);
}
else
{
Traveller<Creature> traveller(*(Creature*)this);
transitTime = traveller.GetTotalTravelTimeTo(x, y, z);
}
}
//float orientation = (float)atan2((double)dy, (double)dx);
SplineFlags flags = GetTypeId() == TYPEID_PLAYER ? SPLINEFLAG_WALKMODE : ((Creature*)this)->GetSplineFlags();
SendMonsterMove(x, y, z, SPLINETYPE_NORMAL, flags, transitTime, player);
}
void Unit::SendHeartBeat(bool toSelf)
void Unit::SendHeartBeat()
{
m_movementInfo.UpdateTime(WorldTimer::getMSTime());
WorldPacket data(MSG_MOVE_HEARTBEAT, 64);
data << GetPackGUID();
data << m_movementInfo;
SendMessageToSet(&data, toSelf);
SendMessageToSet(&data, true);
}
void Unit::resetAttackTimer(WeaponAttackType type)
@ -3740,29 +3672,21 @@ void Unit::SetInFront(Unit const* target)
SetOrientation(GetAngle(target));
}
void Unit::SetFacingTo(float ori, bool bToSelf /*= false*/)
void Unit::SetFacingTo(float ori)
{
// update orientation at server
SetOrientation(ori);
// and client
SendHeartBeat(bToSelf);
Movement::MoveSplineInit init(*this);
init.SetFacing(ori);
init.Launch();
}
// Consider move this to Creature:: since only creature appear to be able to use this
void Unit::SetFacingToObject(WorldObject* pObject)
{
if (GetTypeId() != TYPEID_UNIT)
return;
// 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.
SetOrientation(GetAngle(pObject));
SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), SPLINETYPE_FACINGTARGET, ((Creature*)this)->GetSplineFlags(), 0, NULL, pObject->GetObjectGuid().GetRawValue());
SetFacingTo(GetAngle(pObject));
}
bool Unit::isInAccessablePlaceFor(Creature const* c) const
@ -8211,19 +8135,17 @@ void Unit::UpdateWalkMode(Unit* source, bool self)
CallForAllControlledUnits(UpdateWalkModeHelper(source), CONTROLLED_PET|CONTROLLED_GUARDIANS|CONTROLLED_CHARM|CONTROLLED_MINIPET);
else if (self)
{
bool on = source->GetTypeId() == TYPEID_PLAYER
? ((Player*)source)->HasMovementFlag(MOVEFLAG_WALK_MODE)
: ((Creature*)source)->HasSplineFlag(SPLINEFLAG_WALKMODE);
bool on = source->m_movementInfo.HasMovementFlag(MOVEFLAG_WALK_MODE);
if (on)
{
if (((Creature*)this)->IsPet() && hasUnitState(UNIT_STAT_FOLLOW))
((Creature*)this)->AddSplineFlag(SPLINEFLAG_WALKMODE);
((Creature*)this)->SetWalk(true);
}
else
{
if (((Creature*)this)->IsPet())
((Creature*)this)->RemoveSplineFlag(SPLINEFLAG_WALKMODE);
((Creature*)this)->SetWalk(false);
}
}
else
@ -8469,20 +8391,7 @@ void Unit::SetDeathState(DeathState s)
RemoveMiniPet();
UnsummonAllTotems();
// after removing a Fearaura (in RemoveAllAurasOnDeath)
// Unit::SetFeared is called and makes that creatures attack player again
if (GetTypeId() == TYPEID_UNIT)
{
clearUnitState(UNIT_STAT_MOVING);
GetMap()->CreatureRelocation((Creature*)this, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), SPLINETYPE_NORMAL, SPLINEFLAG_WALKMODE, 0);
}
else
{
if (!IsStopped())
StopMoving();
}
ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false);
ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false);
@ -9981,12 +9890,9 @@ void Unit::StopMoving()
if (!IsInWorld())
return;
// send explicit stop packet
// player expected for correct work SPLINEFLAG_WALKMODE
SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), SPLINETYPE_STOP, GetTypeId() == TYPEID_PLAYER ? SPLINEFLAG_WALKMODE : SPLINEFLAG_NONE, 0);
// update position and orientation for near players
SendHeartBeat(false);
Movement::MoveSplineInit init(*this);
init.SetFacing(GetOrientation());
init.Launch();
}
void Unit::SetFeared(bool apply, ObjectGuid casterGuid, uint32 spellID, uint32 time)
@ -10529,7 +10435,7 @@ void Unit::NearTeleportTo( float x, float y, float z, float orientation, bool ca
GetMap()->CreatureRelocation((Creature*)this, x, y, z, orientation);
SendHeartBeat(false);
SendHeartBeat();
// finished relocation, movegen can different from top before creature relocation,
// but apply Reset expected to be safe in any case
@ -10539,49 +10445,12 @@ void Unit::NearTeleportTo( float x, float y, float z, float orientation, bool ca
}
}
void Unit::MonsterMove(float x, float y, float z, uint32 transitTime)
void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed)
{
SplineFlags flags = GetTypeId() == TYPEID_PLAYER ? SPLINEFLAG_WALKMODE : ((Creature*)this)->GetSplineFlags();
SendMonsterMove(x, y, z, SPLINETYPE_NORMAL, flags, transitTime);
if (GetTypeId() != TYPEID_PLAYER)
{
Creature* c = (Creature*)this;
// Creature relocation acts like instant movement generator, so current generator expects interrupt/reset calls to react properly
if (!c->GetMotionMaster()->empty())
if (MovementGenerator *movgen = c->GetMotionMaster()->top())
movgen->Interrupt(*c);
GetMap()->CreatureRelocation((Creature*)this, x, y, z, 0.0f);
// finished relocation, movegen can different from top before creature relocation,
// but apply Reset expected to be safe in any case
if (!c->GetMotionMaster()->empty())
if (MovementGenerator *movgen = c->GetMotionMaster()->top())
movgen->Reset(*c);
}
}
void Unit::MonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime)
{
SendMonsterMoveWithSpeed(x, y, z, transitTime );
if (GetTypeId() != TYPEID_PLAYER)
{
Creature* c = (Creature*)this;
// Creature relocation acts like instant movement generator, so current generator expects interrupt/reset calls to react properly
if (!c->GetMotionMaster()->empty())
if (MovementGenerator *movgen = c->GetMotionMaster()->top())
movgen->Interrupt(*c);
GetMap()->CreatureRelocation((Creature*)this, x, y, z, 0.0f);
// finished relocation, movegen can different from top before creature relocation,
// but apply Reset expected to be safe in any case
if (!c->GetMotionMaster()->empty())
if (MovementGenerator *movgen = c->GetMotionMaster()->top())
movgen->Reset(*c);
}
Movement::MoveSplineInit init(*this);
init.MoveTo(x,y,z);
init.SetVelocity(speed);
init.Launch();
}
struct SetPvPHelper
@ -10955,3 +10824,31 @@ void Unit::SetVehicleId(uint32 entry)
SendMessageToSet(&data, true);
}
}
void Unit::UpdateSplineMovement(uint32 t_diff)
{
enum{
POSITION_UPDATE_DELAY = 400,
};
if (movespline->Finalized())
return;
movespline->updateState(t_diff);
bool arrived = movespline->Finalized();
if (arrived)
m_movementInfo.RemoveMovementFlag(MovementFlags(MOVEFLAG_SPLINE_ENABLED|MOVEFLAG_FORWARD));
m_movesplineTimer.Update(t_diff);
if (m_movesplineTimer.Passed() || arrived)
{
m_movesplineTimer.Reset(POSITION_UPDATE_DELAY);
Movement::Location loc = movespline->ComputePosition();
if (GetTypeId() == TYPEID_PLAYER)
((Player*)this)->SetPosition(loc.x,loc.y,loc.z,loc.orientation);
else
GetMap()->CreatureRelocation((Creature*)this,loc.x,loc.y,loc.z,loc.orientation);
}
}

View file

@ -803,6 +803,10 @@ inline ByteBuffer& operator>> (ByteBuffer& buf, MovementInfo& mi)
return buf;
}
namespace Movement{
class MoveSpline;
}
enum DiminishingLevels
{
DIMINISHING_LEVEL_1 = 0,
@ -1459,25 +1463,20 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo);
void NearTeleportTo(float x, float y, float z, float orientation, bool casting = false);
void MonsterMove(float x, float y, float z, uint32 transitTime);
void MonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0);
void MonsterMoveWithSpeed(float x, float y, float z, float speed);
// recommend use MonsterMove/MonsterMoveWithSpeed for most case that correctly work with movegens
// if used additional args in ... part then floats must explicitly casted to double
void SendMonsterMove(float x, float y, float z, SplineType type, SplineFlags flags, uint32 Time, Player* player = NULL, ...);
void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0, Player* player = NULL);
void SendHeartBeat();
template<typename PathElem, typename PathNode>
void SendMonsterMoveByPath(Path<PathElem,PathNode> const& path, uint32 start, uint32 end, SplineFlags flags);
void SetInFront(Unit const* target);
void SetFacingTo(float ori);
void SetFacingToObject(WorldObject* pObject);
void SendHighestThreatUpdate(HostileReference* pHostileReference);
void SendThreatClear();
void SendThreatRemove(HostileReference* pHostileReference);
void SendThreatUpdate();
void SendHeartBeat(bool toSelf);
virtual void MoveOutOfRange(Player &) { };
bool isAlive() const { return (m_deathState == ALIVE); };
@ -1699,10 +1698,6 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
float GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const;
void SetBaseWeaponDamage(WeaponAttackType attType ,WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; }
void SetInFront(Unit const* target);
void SetFacingTo(float ori, bool bToSelf = false);
void SetFacingToObject(WorldObject* pObject);
// Visibility system
UnitVisibility GetVisibility() const { return m_Visibility; }
void SetVisibility(UnitVisibility x);
@ -1954,6 +1949,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
// Movement info
MovementInfo m_movementInfo;
Movement::MoveSpline * movespline;
void ScheduleAINotify(uint32 delay);
bool IsAINotifyScheduled() const { return m_AINotifyScheduled;}
@ -2012,6 +2008,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
VehicleInfo* m_vehicleInfo;
private:
void CleanupDeletedAuras();
void UpdateSplineMovement(uint32 t_diff);
// player or player's pet
float GetCombatRatingReduction(CombatRating cr) const;
@ -2029,6 +2026,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
UnitVisibility m_Visibility;
Position m_last_notified_position;
bool m_AINotifyScheduled;
ShortTimeTracker m_movesplineTimer;
Diminishing m_Diminishing;
// Manage all Units threatening us
@ -2130,33 +2128,4 @@ bool Unit::CheckAllControlledUnits(Func const& func, uint32 controlledMask) cons
return false;
}
template<typename Elem, typename Node>
inline void Unit::SendMonsterMoveByPath(Path<Elem,Node> const& path, uint32 start, uint32 end, SplineFlags flags)
{
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 << GetPackGUID();
data << uint8(0);
data << GetPositionX();
data << GetPositionY();
data << GetPositionZ();
data << uint32(WorldTimer::getMSTime());
data << uint8(SPLINETYPE_NORMAL);
data << uint32(flags);
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

View file

@ -35,11 +35,12 @@ alter table creature_movement add `wpguid` int(11) default '0';
#include "WaypointMovementGenerator.h"
#include "ObjectMgr.h"
#include "Creature.h"
#include "DestinationHolderImp.h"
#include "CreatureAI.h"
#include "WaypointManager.h"
#include "WorldPacket.h"
#include "ScriptMgr.h"
#include "movement/MoveSplineInit.h"
#include "movement/MoveSpline.h"
#include <cassert>
@ -87,11 +88,13 @@ void WaypointMovementGenerator<Creature>::Initialize(Creature &creature)
void WaypointMovementGenerator<Creature>::Finalize(Creature &creature)
{
creature.clearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
creature.SetWalk(false);
}
void WaypointMovementGenerator<Creature>::Interrupt(Creature &creature)
{
creature.clearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
creature.SetWalk(false);
}
void WaypointMovementGenerator<Creature>::Reset(Creature &creature)
@ -111,11 +114,6 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature)
creature.clearUnitState(UNIT_STAT_ROAMING_MOVE);
m_isArrivalDone = true;
if (i_path->at(i_currentNode).orientation != 100)
{
creature.SetFacingTo(i_path->at(i_currentNode).orientation);
}
if (i_path->at(i_currentNode).script_id)
{
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature movement start script %u at point %u for %s.", i_path->at(i_currentNode).script_id, i_currentNode, creature.GetGuidStr().c_str());
@ -179,13 +177,16 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature &creature)
m_isArrivalDone = false;
if (creature.CanFly())
creature.AddSplineFlag(SPLINEFLAG_FLYING);
creature.addUnitState(UNIT_STAT_ROAMING_MOVE);
const WaypointNode &node = i_path->at(i_currentNode);
CreatureTraveller traveller(creature);
i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
Movement::MoveSplineInit init(creature);
init.MoveTo(node.x, node.y, node.z);
if (node.orientation != 100 && node.delay != 0)
init.SetFacing(node.orientation);
init.SetWalk(!creature.IsLevitating());
init.Launch();
}
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
@ -212,14 +213,9 @@ bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint3
}
else
{
CreatureTraveller traveller(creature);
if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true) && !IsActive(creature))
return true;
if (creature.IsStopped())
Stop(STOP_TIME_FOR_PLAYER);
if (i_destinationHolder.HasArrived())
else if (creature.movespline->Finalized())
{
OnArrived(creature);
StartMove(creature);
@ -236,7 +232,13 @@ void WaypointMovementGenerator<Creature>::MovementInform(Creature &creature)
bool WaypointMovementGenerator<Creature>::GetResetPosition(Creature&, float& x, float& y, float& z)
{
return PathMovementBase<Creature, WaypointPath const*>::GetPosition(x,y,z);
// prevent a crash at empty waypoint path.
if (!i_path || i_path->empty())
return false;
const WaypointNode& node = i_path->at(i_currentNode);
x = node.x; y = node.y; z = node.z;
return true;
}
//----------------------------------------------------//
@ -266,10 +268,6 @@ 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_TAXI_FLIGHT);
float x, y, z;
i_destinationHolder.GetLocationNow(player.GetMap(), x, y, z);
player.SetPosition(x, y, z, player.GetOrientation());
player.Unmount();
player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
@ -291,57 +289,39 @@ void FlightPathMovementGenerator::Interrupt(Player & player)
player.clearUnitState(UNIT_STAT_TAXI_FLIGHT);
}
#define PLAYER_FLIGHT_SPEED 32.0f
void FlightPathMovementGenerator::Reset(Player & player)
{
player.getHostileRefManager().setOnlineOfflineState(false);
player.addUnitState(UNIT_STAT_TAXI_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);
player.SendMonsterMoveByPath(GetPath(),GetCurrentNode(),GetPathAtMapEnd(), SplineFlags(SPLINEFLAG_WALKMODE|SPLINEFLAG_FLYING));
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())
{
Traveller<Player> traveller(player);
if( i_destinationHolder.UpdateTraveller(traveller, diff, false) )
{
if (!IsActive(player)) // force stop processing (movement can move out active zone with cleanup movegens list)
return true; // not expire now, but already lost
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())
int32 pointId = player.movespline->currentPathIdx();
// currentPathIdx returns lastIdx + 1 at arrive
while (i_currentNode < pointId)
{
DoEventIfAny(player,(*i_path)[i_currentNode],true);
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "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);
}
return true;
}
}
else
return true;
}
else
return true;
DoEventIfAny(player,(*i_path)[i_currentNode],false);
++i_currentNode;
}
// we have arrived at the end of the path
return false;
return MovementInProgress();
}
void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
@ -372,6 +352,13 @@ void FlightPathMovementGenerator::DoEventIfAny(Player& player, TaxiPathNodeEntry
}
}
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;
}
//
// Unique1's ASTAR Pathfinding Code... For future use & reference...
//

View file

@ -26,10 +26,7 @@
*/
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "WaypointManager.h"
#include "Path.h"
#include "Traveller.h"
#include "Player.h"
@ -46,18 +43,15 @@ class MANGOS_DLL_SPEC PathMovementBase
PathMovementBase() : i_currentNode(0) {}
virtual ~PathMovementBase() {};
bool MovementInProgress(void) const { return i_currentNode < i_path->size(); }
bool MovementInProgress(void) const { return (i_currentNode+1) < i_path->size(); }
// template pattern, not defined .. override required
void LoadPath(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;
};
/** WaypointMovementGenerator loads a series of way points
@ -89,9 +83,6 @@ public PathMovementBase<Creature, WaypointPath const*>
// now path movement implmementation
void LoadPath(Creature &c);
// allow use for overwrite empty implementation
bool GetDestination(float& x, float& y, float& z) const { return PathMovementBase<Creature, WaypointPath const*>::GetDestination(x,y,z); }
bool GetResetPosition(Creature&, float& x, float& y, float& z);
private:
@ -145,8 +136,6 @@ public PathMovementBase<Player,TaxiPathNodeList const*>
void SetCurrentNodeAfterTeleport();
void SkipCurrentNode() { ++i_currentNode; }
void DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure);
// allow use for overwrite empty implementation
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);
};
#endif

View file

@ -0,0 +1,311 @@
/*
* 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
{
MANGOS_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;
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
{
Vector3 hermite;
spline.evaluate_derivative(point_Idx,u,hermite);
c.orientation = atan2(hermite.y, hermite.x);
if (splineflags.backward)
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;
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)
{
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());
MANGOS_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;
}
}

View file

@ -0,0 +1,125 @@
/*
* 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 MANGOSSERVER_MOVEPLINE_H
#define MANGOSSERVER_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;
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();
#pragma endregion
public:
void Initialize(const MoveSplineInitArgs&);
bool Initialized() const { return !spline.empty();}
explicit MoveSpline();
template<class UpdateHandler>
void updateState(int32 difftime, UpdateHandler& handler)
{
MANGOS_ASSERT(Initialized());
do
handler(_updateState(difftime));
while(difftime > 0);
}
void updateState(int32 difftime)
{
MANGOS_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 // MANGOSSERVER_MOVEPLINE_H

View file

@ -0,0 +1,142 @@
/*
* 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 MANGOSSERVER_MOVESPLINEFLAG_H
#define MANGOSSERVER_MOVESPLINEFLAG_H
#include "typedefs.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
Knockback = 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,
Backward = 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;}
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|Knockback) | Animation|anim;}
void EnableParabolic() { raw() = raw() & ~(Mask_Animations|Falling|Animation) | Parabolic;}
void EnableFalling() { raw() = raw() & ~(Mask_Animations|Parabolic|Knockback|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 knockback : 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 backward : 1;
bool unknown10 : 1;
bool unknown11 : 1;
bool unknown12 : 1;
bool unknown13 : 1;
};
#if defined( __GNUC__ )
#pragma pack()
#else
#pragma pack(pop)
#endif
}
#endif // MANGOSSERVER_MOVESPLINEFLAG_H

View file

@ -0,0 +1,106 @@
/*
* 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 "packet_builder.h"
#include "../Unit.h"
namespace Movement
{
UnitMoveType SelectSpeedType(uint32 moveFlags)
{
if (moveFlags & MOVEFLAG_FLYING)
{
if ( moveFlags & MOVEFLAG_BACKWARD /*&& speed_obj.flight >= speed_obj.flight_back*/ )
return MOVE_FLIGHT_BACK;
else
return MOVE_FLIGHT;
}
else if (moveFlags & MOVEFLAG_SWIMMING)
{
if (moveFlags & MOVEFLAG_BACKWARD /*&& speed_obj.swim >= speed_obj.swim_back*/)
return MOVE_SWIM_BACK;
else
return MOVE_SWIM;
}
else if (moveFlags & MOVEFLAG_WALK_MODE)
{
//if ( speed_obj.run > speed_obj.walk )
return MOVE_WALK;
}
else if (moveFlags & MOVEFLAG_BACKWARD /*&& speed_obj.run >= speed_obj.run_back*/)
return MOVE_RUN_BACK;
return MOVE_RUN;
}
void MoveSplineInit::Launch()
{
MoveSpline& move_spline = *unit.movespline;
Vector3 real_position(unit.GetPositionX(),unit.GetPositionY(),unit.GetPositionZ());
// 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;
uint32 moveFlags = unit.m_movementInfo.GetMovementFlags();
if (args.flags.walkmode)
moveFlags |= MOVEFLAG_WALK_MODE;
else
moveFlags &= ~MOVEFLAG_WALK_MODE;
moveFlags |= (MOVEFLAG_SPLINE_ENABLED|MOVEFLAG_FORWARD);
if (args.velocity == 0.f)
args.velocity = unit.GetSpeed(SelectSpeedType(moveFlags));
if (!args.Validate())
return;
unit.m_movementInfo.SetMovementFlags((MovementFlags)moveFlags);
move_spline.Initialize(args);
WorldPacket data(SMSG_MONSTER_MOVE, 64);
data << 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(MOVEFLAG_WALK_MODE);
args.flags.flying = unit.m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_FLYING|MOVEFLAG_LEVITATING));
}
void MoveSplineInit::SetFacing(const Unit * target)
{
args.flags.EnableFacingTarget();
args.facing.target = target->GetObjectGuid().GetRawValue();
}
}

View file

@ -0,0 +1,164 @@
/*
* 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 MANGOSSERVER_MOVESPLINEINIT_H
#define MANGOSSERVER_MOVESPLINEINIT_H
#include "MoveSplineInitArgs.h"
class Unit;
namespace Movement
{
/* Initializes and launches spline movement
*/
class MANGOS_DLL_SPEC 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, bool is_knockback = false);
/* 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();
/* Disabled by default
*/
void SetBackward();
/* 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 MoveJumpInit(Unit& st, const Vector3& dest, float velocity, float parabolic_heigth = 0.5f)
{
MoveSplineInit init(st);
init.MoveTo(dest);
init.SetParabolic(parabolic_heigth,0,false);
init.SetVelocity(velocity);
init.Launch();
}
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::SetBackward() { args.flags.backward = true;}
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, bool is_knockback)
{
args.time_perc = time_shift;
args.parabolic_amplitude = amplitude;
args.flags.EnableParabolic();
args.flags.knockback = is_knockback;
}
inline void MoveSplineInit::SetFacing(float o)
{
args.facing.angle = G3D::wrap(o, 0.f, (float)G3D::twoPi());
args.flags.EnableFacingAngle();
}
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 // MANGOSSERVER_MOVESPLINEINIT_H

View file

@ -0,0 +1,66 @@
/*
* 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 MANGOSSERVER_MOVESPLINEINIT_ARGS_H
#define MANGOSSERVER_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)
{
path.reserve(path_capacity);
}
PointsArray path;
FacingInfo facing;
MoveSplineFlag flags;
int32 path_Idx_offset;
float velocity;
float parabolic_amplitude;
float time_perc;
uint32 splineId;
/** Returns true to show that the arguments were configured correctly and MoveSpline initialization will succeed. */
bool Validate() const;
private:
bool _checkPathBounds() const;
};
}
#endif // MANGOSSERVER_MOVESPLINEINIT_ARGS_H

View file

@ -0,0 +1,189 @@
/*
* 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 "packet_builder.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;
data << float(1.f);//splineInfo.duration_mod_next;
data << move_spline.vertical_acceleration;
data << move_spline.effect_start_time;
uint32 nodes = move_spline.getPath().size();
data << nodes;
data.append<Vector3>(&move_spline.getPath()[0], nodes);
data << uint8(move_spline.spline.mode());
data << (move_spline.isCyclic() ? Vector3::zero() : move_spline.FinalDestination());
}
}
}

View file

@ -16,4 +16,21 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "DestinationHolder.h"
#ifndef MANGOSSERVER_PACKET_BUILDER_H
#define MANGOSSERVER_PACKET_BUILDER_H
class ByteBuffer;
class WorldPacket;
namespace Movement
{
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 // MANGOSSERVER_PACKET_BUILDER_H

View file

@ -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
{
MANGOS_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
{
MANGOS_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;
MANGOS_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
{
MANGOS_ASSERT(index >= index_lo && index < index_hi);
result = points[index+1] - points[index];
}
void SplineBase::EvaluateDerivativeCatmullRom(index_type index, float t, Vector3& result) const
{
MANGOS_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;
MANGOS_ASSERT(index >= index_lo && index < index_hi);
C_Evaluate_Derivative(&points[index], t, s_Bezier3Coeffs, result);
}
float SplineBase::SegLengthLinear(index_type index) const
{
MANGOS_ASSERT(index >= index_lo && index < index_hi);
return (points[index] - points[index+1]).length();
}
float SplineBase::SegLengthCatmullRom( index_type index ) const
{
MANGOS_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;
MANGOS_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)
{
MANGOS_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();
}
}

212
src/game/movement/spline.h Normal file
View file

@ -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 MANGOSSERVER_SPLINE_H
#define MANGOSSERVER_SPLINE_H
#include "typedefs.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 { MANGOS_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;
MANGOS_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 "spline.impl.h"
#endif // MANGOSSERVER_SPLINE_H

View file

@ -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
{
MANGOS_ASSERT(t >= 0.f && t <= 1.f);
length_type length_ = t * length();
index = computeIndexInBounds(length_);
MANGOS_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
{
MANGOS_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();
}
}

View file

@ -0,0 +1,78 @@
/*
* 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 MANGOSSERVER_TYPEDEFS_H
#define MANGOSSERVER_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;
}
#endif // MANGOSSERVER_TYPEDEFS_H

208
src/game/movement/util.cpp Normal file
View file

@ -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(Forward ),// 0x00000001,
STR(Backward ),// 0x00000002,
STR(Strafe_Left ),// 0x00000004,
STR(Strafe_Right ),// 0x00000008,
STR(Left ),// 0x00000010,
STR(Right ),// 0x00000020,
STR(Pitch_Up ),// 0x00000040,
STR(Pitch_Down ),// 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(Backward ),// 0x08000000, // Appears With Walkmode 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;
}
}

View file

@ -132,7 +132,7 @@ struct TimeTracker
struct ShortTimeTracker
{
public:
ShortTimeTracker(int32 expiry) : i_expiryTime(expiry) {}
ShortTimeTracker(int32 expiry = 0) : i_expiryTime(expiry) {}
void Update(int32 diff) { i_expiryTime -= diff; }
bool Passed() const { return (i_expiryTime <= 0); }
void Reset(int32 interval) { i_expiryTime = interval; }

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "11718"
#define REVISION_NR "11720"
#endif // __REVISION_NR_H__

View file

@ -399,7 +399,6 @@
<ClCompile Include="..\..\src\game\CreatureEventAIMgr.cpp" />
<ClCompile Include="..\..\src\game\DBCStores.cpp" />
<ClCompile Include="..\..\src\game\debugcmds.cpp" />
<ClCompile Include="..\..\src\game\DestinationHolder.cpp" />
<ClCompile Include="..\..\src\game\DuelHandler.cpp" />
<ClCompile Include="..\..\src\game\DynamicObject.cpp" />
<ClCompile Include="..\..\src\game\FleeingMovementGenerator.cpp" />
@ -443,6 +442,11 @@
<ClCompile Include="..\..\src\game\MotionMaster.cpp" />
<ClCompile Include="..\..\src\game\MovementGenerator.cpp" />
<ClCompile Include="..\..\src\game\MovementHandler.cpp" />
<ClCompile Include="..\..\src\game\movement\MoveSpline.cpp" />
<ClCompile Include="..\..\src\game\movement\MoveSplineInit.cpp" />
<ClCompile Include="..\..\src\game\movement\packet_builder.cpp" />
<ClCompile Include="..\..\src\game\movement\spline.cpp" />
<ClCompile Include="..\..\src\game\movement\util.cpp" />
<ClCompile Include="..\..\src\game\NPCHandler.cpp" />
<ClCompile Include="..\..\src\game\NullCreatureAI.cpp" />
<ClCompile Include="..\..\src\game\Object.cpp" />
@ -559,8 +563,6 @@
<ClInclude Include="..\..\src\game\DBCfmt.h" />
<ClInclude Include="..\..\src\game\DBCStores.h" />
<ClInclude Include="..\..\src\game\DBCStructure.h" />
<ClInclude Include="..\..\src\game\DestinationHolder.h" />
<ClInclude Include="..\..\src\game\DestinationHolderImp.h" />
<ClInclude Include="..\..\src\game\DynamicObject.h" />
<ClInclude Include="..\..\src\game\FleeingMovementGenerator.h" />
<ClInclude Include="..\..\src\game\FollowerReference.h" />
@ -599,6 +601,14 @@
<ClInclude Include="..\..\src\game\MassMailMgr.h" />
<ClInclude Include="..\..\src\game\MotionMaster.h" />
<ClInclude Include="..\..\src\game\MovementGenerator.h" />
<ClInclude Include="..\..\src\game\movement\MoveSpline.h" />
<ClInclude Include="..\..\src\game\movement\MoveSplineFlag.h" />
<ClInclude Include="..\..\src\game\movement\MoveSplineInit.h" />
<ClInclude Include="..\..\src\game\movement\MoveSplineInitArgs.h" />
<ClInclude Include="..\..\src\game\movement\packet_builder.h" />
<ClInclude Include="..\..\src\game\movement\spline.h" />
<ClInclude Include="..\..\src\game\movement\spline.impl.h" />
<ClInclude Include="..\..\src\game\movement\typedefs.h" />
<ClInclude Include="..\..\src\game\NPCHandler.h" />
<ClInclude Include="..\..\src\game\NullCreatureAI.h" />
<ClInclude Include="..\..\src\game\Object.h" />
@ -636,7 +646,6 @@
<ClInclude Include="..\..\src\game\Totem.h" />
<ClInclude Include="..\..\src\game\TotemAI.h" />
<ClInclude Include="..\..\src\game\Transports.h" />
<ClInclude Include="..\..\src\game\Traveller.h" />
<ClInclude Include="..\..\src\game\Unit.h" />
<ClInclude Include="..\..\src\game\UnitEvents.h" />
<ClInclude Include="..\..\src\game\UpdateData.h" />

View file

@ -25,6 +25,9 @@
<Filter Include="vmaps">
<UniqueIdentifier>{948284d3-9d89-4609-8cdd-28a213edb53e}</UniqueIdentifier>
</Filter>
<Filter Include="Movement">
<UniqueIdentifier>{0ac140f9-89c1-4830-b673-514c5e8b4d37}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\game\AccountMgr.cpp">
@ -255,9 +258,6 @@
<ClCompile Include="..\..\src\game\ConfusedMovementGenerator.cpp">
<Filter>Motion generators</Filter>
</ClCompile>
<ClCompile Include="..\..\src\game\DestinationHolder.cpp">
<Filter>Motion generators</Filter>
</ClCompile>
<ClCompile Include="..\..\src\game\FleeingMovementGenerator.cpp">
<Filter>Motion generators</Filter>
</ClCompile>
@ -481,6 +481,21 @@
<ClCompile Include="..\..\src\game\vmap\WorldModel.cpp">
<Filter>vmaps</Filter>
</ClCompile>
<ClCompile Include="..\..\src\game\movement\MoveSplineInit.cpp">
<Filter>Movement</Filter>
</ClCompile>
<ClCompile Include="..\..\src\game\movement\packet_builder.cpp">
<Filter>Movement</Filter>
</ClCompile>
<ClCompile Include="..\..\src\game\movement\spline.cpp">
<Filter>Movement</Filter>
</ClCompile>
<ClCompile Include="..\..\src\game\movement\util.cpp">
<Filter>Movement</Filter>
</ClCompile>
<ClCompile Include="..\..\src\game\movement\MoveSpline.cpp">
<Filter>Movement</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\game\AccountMgr.h">
@ -645,12 +660,6 @@
<ClInclude Include="..\..\src\game\ConfusedMovementGenerator.h">
<Filter>Motion generators</Filter>
</ClInclude>
<ClInclude Include="..\..\src\game\DestinationHolder.h">
<Filter>Motion generators</Filter>
</ClInclude>
<ClInclude Include="..\..\src\game\DestinationHolderImp.h">
<Filter>Motion generators</Filter>
</ClInclude>
<ClInclude Include="..\..\src\game\FleeingMovementGenerator.h">
<Filter>Motion generators</Filter>
</ClInclude>
@ -675,9 +684,6 @@
<ClInclude Include="..\..\src\game\TargetedMovementGenerator.h">
<Filter>Motion generators</Filter>
</ClInclude>
<ClInclude Include="..\..\src\game\Traveller.h">
<Filter>Motion generators</Filter>
</ClInclude>
<ClInclude Include="..\..\src\game\WaypointMovementGenerator.h">
<Filter>Motion generators</Filter>
</ClInclude>
@ -910,5 +916,29 @@
<ClInclude Include="..\..\src\game\vmap\WorldModel.h">
<Filter>vmaps</Filter>
</ClInclude>
<ClInclude Include="..\..\src\game\movement\MoveSpline.h">
<Filter>Movement</Filter>
</ClInclude>
<ClInclude Include="..\..\src\game\movement\MoveSplineFlag.h">
<Filter>Movement</Filter>
</ClInclude>
<ClInclude Include="..\..\src\game\movement\MoveSplineInit.h">
<Filter>Movement</Filter>
</ClInclude>
<ClInclude Include="..\..\src\game\movement\MoveSplineInitArgs.h">
<Filter>Movement</Filter>
</ClInclude>
<ClInclude Include="..\..\src\game\movement\packet_builder.h">
<Filter>Movement</Filter>
</ClInclude>
<ClInclude Include="..\..\src\game\movement\spline.h">
<Filter>Movement</Filter>
</ClInclude>
<ClInclude Include="..\..\src\game\movement\spline.impl.h">
<Filter>Movement</Filter>
</ClInclude>
<ClInclude Include="..\..\src\game\movement\typedefs.h">
<Filter>Movement</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -1053,18 +1053,6 @@
RelativePath="..\..\src\game\ConfusedMovementGenerator.h"
>
</File>
<File
RelativePath="..\..\src\game\DestinationHolder.cpp"
>
</File>
<File
RelativePath="..\..\src\game\DestinationHolder.h"
>
</File>
<File
RelativePath="..\..\src\game\DestinationHolderImp.h"
>
</File>
<File
RelativePath="..\..\src\game\FleeingMovementGenerator.cpp"
>
@ -1129,10 +1117,6 @@
RelativePath="..\..\src\game\TargetedMovementGenerator.h"
>
</File>
<File
RelativePath="..\..\src\game\Traveller.h"
>
</File>
<File
RelativePath="..\..\src\game\WaypointMovementGenerator.cpp"
>
@ -1717,6 +1701,62 @@
RelativePath="..\..\src\game\vmap\WorldModel.h"
>
</File>
</Filter>
<Filter
Name="Movement"
>
<File
RelativePath="..\..\src\game\Movement\MoveSpline.cpp"
>
</File>
<File
RelativePath="..\..\src\game\Movement\MoveSpline.h"
>
</File>
<File
RelativePath="..\..\src\game\Movement\MoveSplineFlag.h"
>
</File>
<File
RelativePath="..\..\src\game\Movement\MoveSplineInit.cpp"
>
</File>
<File
RelativePath="..\..\src\game\Movement\MoveSplineInit.h"
>
</File>
<File
RelativePath="..\..\src\game\Movement\MoveSplineInitArgs.h"
>
</File>
<File
RelativePath="..\..\src\game\Movement\packet_builder.cpp"
>
</File>
<File
RelativePath="..\..\src\game\Movement\packet_builder.h"
>
</File>
<File
RelativePath="..\..\src\game\Movement\spline.cpp"
>
</File>
<File
RelativePath="..\..\src\game\Movement\spline.h"
>
</File>
<File
RelativePath="..\..\src\game\Movement\spline.impl.h"
>
</File>
<File
RelativePath="..\..\src\game\Movement\typedefs.h"
>
</File>
<File
RelativePath="..\..\src\game\movement\util.cpp"
>
</File>
</Filter>
<File
RelativePath="..\..\src\game\pchdef.cpp"

View file

@ -1046,18 +1046,6 @@
RelativePath="..\..\src\game\ConfusedMovementGenerator.h"
>
</File>
<File
RelativePath="..\..\src\game\DestinationHolder.cpp"
>
</File>
<File
RelativePath="..\..\src\game\DestinationHolder.h"
>
</File>
<File
RelativePath="..\..\src\game\DestinationHolderImp.h"
>
</File>
<File
RelativePath="..\..\src\game\FleeingMovementGenerator.cpp"
>
@ -1122,10 +1110,6 @@
RelativePath="..\..\src\game\TargetedMovementGenerator.h"
>
</File>
<File
RelativePath="..\..\src\game\Traveller.h"
>
</File>
<File
RelativePath="..\..\src\game\WaypointMovementGenerator.cpp"
>
@ -1719,6 +1703,62 @@
>
</File>
</Filter>
<Filter
Name="Movement"
>
<File
RelativePath="..\..\src\game\Movement\MoveSpline.cpp"
>
</File>
<File
RelativePath="..\..\src\game\Movement\MoveSpline.h"
>
</File>
<File
RelativePath="..\..\src\game\Movement\MoveSplineFlag.h"
>
</File>
<File
RelativePath="..\..\src\game\Movement\MoveSplineInit.cpp"
>
</File>
<File
RelativePath="..\..\src\game\Movement\MoveSplineInit.h"
>
</File>
<File
RelativePath="..\..\src\game\Movement\MoveSplineInitArgs.h"
>
</File>
<File
RelativePath="..\..\src\game\Movement\packet_builder.cpp"
>
</File>
<File
RelativePath="..\..\src\game\Movement\packet_builder.h"
>
</File>
<File
RelativePath="..\..\src\game\Movement\spline.cpp"
>
</File>
<File
RelativePath="..\..\src\game\Movement\spline.h"
>
</File>
<File
RelativePath="..\..\src\game\Movement\spline.impl.h"
>
</File>
<File
RelativePath="..\..\src\game\Movement\typedefs.h"
>
</File>
<File
RelativePath="..\..\src\game\movement\util.cpp"
>
</File>
</Filter>
<File
RelativePath="..\..\src\game\pchdef.cpp"
>