Core/Movement: 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:

* Added linear, catmullrom and bezier3 splines which based on client's algorthims. They can be reused for proper transport position interpolation.
* Precission increased. There are no more position desync issues since client's position calculation formulas used.
* Now possible to move by paths with multiple points, send whole path to client.

--
Original author of research and implementation: SilverIce. Massive kudos.
Original port for Trinity (ref #4629) Chaplain and Venugh
With the following incremental fixes during my review:

- Restore flightmaster end grid pre-loading
- Fix uninitialized Creature::m_path_id
- Add missing trinity_string entries for .movegens command
- Fix a bug in WaypointMovementGenerator that would trigger unexpected pausing at waypoints for various amounts of time

Known issues:
- Errors like WaypointMovementGenerator::LoadPath creature XXX (Entry: YYYYY GUID: ZZZZZZ) doesn't have waypoint path id: 0.
This is caused by bad DB data. This commit didn't "break" it.

Do not forget to re-run CMake before compiling.
This commit is contained in:
Machiavelli
2012-01-14 15:36:07 +01:00
parent 798677ca54
commit dbbac0bdaa
84 changed files with 3356 additions and 1943 deletions
@@ -0,0 +1,6 @@
DELETE FROM `trinity_string` WHERE `entry` IN(1139,1140,1141,1142);
INSERT INTO `trinity_string` (`entry`,`content_default`) VALUES
(1139,' Follow player %s (lowguid %u)'),
(1140,' Follow creature %s (lowguid %u)'),
(1141,' Follow <NULL>'),
(1142,' Effect movement');
+2 -2
View File
@@ -115,8 +115,8 @@ void GuardAI::EnterEvadeMode()
me->CombatStop(true);
i_state = STATE_NORMAL;
// Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
// Remove ChaseMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
me->GetMotionMaster()->MoveTargetedHome();
}
+3 -6
View File
@@ -417,10 +417,9 @@ void PetAI::MovementInform(uint32 moveType, uint32 data)
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveIdle();
}
break;
}
break;
case TARGETED_MOTION_TYPE:
case FOLLOW_MOTION_TYPE:
{
// If data is owner's GUIDLow then we've reached follow point,
// otherwise we're probably chasing a creature
@@ -430,11 +429,9 @@ void PetAI::MovementInform(uint32 moveType, uint32 data)
me->GetCharmInfo()->SetIsReturning(false);
me->GetCharmInfo()->SetIsFollowing(true);
me->GetCharmInfo()->SetIsCommandAttack(false);
me->AddUnitState(UNIT_STAT_FOLLOW);
}
break;
}
break;
default:
break;
}
@@ -475,7 +475,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
//Melee current victim if flag not set
if (!(action.cast.castFlags & CAST_NO_MELEE_IF_OOM))
{
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
{
m_AttackDistance = 0.0f;
m_AttackAngle = 0.0f;
@@ -483,7 +483,6 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
me->GetMotionMaster()->MoveChase(me->getVictim(), m_AttackDistance, m_AttackAngle);
}
}
}
else
{
@@ -595,7 +594,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
me->ClearUnitState(UNIT_STAT_MELEE_ATTACKING);
me->SendMeleeAttackStop(victim);
}
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
me->GetMotionMaster()->MoveIdle();
}
}
@@ -298,7 +298,8 @@ void ScriptedAI::DoModifyThreatPercent(Unit* unit, int32 pct)
void ScriptedAI::DoTeleportTo(float x, float y, float z, uint32 time)
{
me->Relocate(x, y, z);
me->SendMonsterMove(x, y, z, time);
float speed = me->GetDistance(x, y, z) / ((float)time * 0.001f);
me->MonsterMoveWithSpeed(x, y, z, speed);
}
void ScriptedAI::DoTeleportTo(const float position[4])
@@ -167,7 +167,7 @@ void FollowerAI::EnterEvadeMode()
{
sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI left combat, returning to CombatStartPosition.");
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
{
float fPosX, fPosY, fPosZ;
me->GetPosition(fPosX, fPosY, fPosZ);
@@ -176,7 +176,7 @@ void FollowerAI::EnterEvadeMode()
}
else
{
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
me->GetMotionMaster()->MoveTargetedHome();
}
@@ -1273,11 +1273,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
ObjectList* targets = GetTargets(e, unit);
if (e.GetTargetType() == SMART_TARGET_SELF)
me->SetFacing(me->GetHomePosition().GetOrientation(), NULL);
me->SetFacingTo(me->GetHomePosition().GetOrientation());
else if (e.GetTargetType() == SMART_TARGET_POSITION)
me->SetFacing(e.target.o, NULL);
me->SetFacingTo(e.target.o);
else if (targets && !targets->empty())
me->SetFacing(0, (*targets->begin()));
me->SetFacingToObject(*targets->begin());
delete targets;
break;
+2
View File
@@ -102,6 +102,7 @@ set(game_STAT_SRCS
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/mersennetwister
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/dep/zlib
@@ -170,6 +171,7 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/Maps
${CMAKE_CURRENT_SOURCE_DIR}/Miscellaneous
${CMAKE_CURRENT_SOURCE_DIR}/Movement
${CMAKE_CURRENT_SOURCE_DIR}/Movement/Spline
${CMAKE_CURRENT_SOURCE_DIR}/Movement/MovementGenerators
${CMAKE_CURRENT_SOURCE_DIR}/Movement/Waypoints
${CMAKE_CURRENT_SOURCE_DIR}/OutdoorPvP
+33 -28
View File
@@ -3692,6 +3692,9 @@ bool ChatHandler::HandleMovegensCommand(const char* /*args*/)
PSendSysMessage(LANG_MOVEGENS_LIST, (unit->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), unit->GetGUIDLow());
MotionMaster* mm = unit->GetMotionMaster();
float x,y,z;
mm->GetDestination(x,y,z);
for (uint8 i = 0; i < MAX_MOTION_SLOT; ++i)
{
MovementGenerator* mg = mm->GetMotionSlot(i);
@@ -3707,48 +3710,55 @@ bool ChatHandler::HandleMovegensCommand(const char* /*args*/)
case WAYPOINT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_WAYPOINT); break;
case ANIMAL_RANDOM_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_ANIMAL_RANDOM); break;
case CONFUSED_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_CONFUSED); break;
case TARGETED_MOTION_TYPE:
case CHASE_MOTION_TYPE:
{
Unit* target = NULL;
if (unit->GetTypeId() == TYPEID_PLAYER)
{
TargetedMovementGenerator<Player> const* mgen = static_cast<TargetedMovementGenerator<Player> const*>(mg);
Unit* target = mgen->GetTarget();
if (target)
PSendSysMessage(LANG_MOVEGENS_TARGETED_PLAYER, target->GetName(), target->GetGUIDLow());
else
SendSysMessage(LANG_MOVEGENS_TARGETED_NULL);
}
target = static_cast<ChaseMovementGenerator<Player> const*>(mg)->GetTarget();
else
{
TargetedMovementGenerator<Creature> const* mgen = static_cast<TargetedMovementGenerator<Creature> const*>(mg);
Unit* target = mgen->GetTarget();
if (target)
PSendSysMessage(LANG_MOVEGENS_TARGETED_CREATURE, target->GetName(), target->GetGUIDLow());
else
SendSysMessage(LANG_MOVEGENS_TARGETED_NULL);
}
target = static_cast<ChaseMovementGenerator<Creature> const*>(mg)->GetTarget();
if (!target)
SendSysMessage(LANG_MOVEGENS_CHASE_NULL);
else if (target->GetTypeId() == TYPEID_PLAYER)
PSendSysMessage(LANG_MOVEGENS_CHASE_PLAYER, target->GetName(), target->GetGUIDLow());
else
PSendSysMessage(LANG_MOVEGENS_CHASE_CREATURE, target->GetName(), target->GetGUIDLow());
break;
}
case FOLLOW_MOTION_TYPE:
{
Unit* target = NULL;
if (unit->GetTypeId() == TYPEID_PLAYER)
target = static_cast<FollowMovementGenerator<Player> const*>(mg)->GetTarget();
else
target = static_cast<FollowMovementGenerator<Creature> const*>(mg)->GetTarget();
if (!target)
SendSysMessage(LANG_MOVEGENS_FOLLOW_NULL);
else if (target->GetTypeId() == TYPEID_PLAYER)
PSendSysMessage(LANG_MOVEGENS_FOLLOW_PLAYER, target->GetName(), target->GetGUIDLow());
else
PSendSysMessage(LANG_MOVEGENS_FOLLOW_CREATURE, target->GetName(), target->GetGUIDLow());
break;
}
case HOME_MOTION_TYPE:
{
if (unit->GetTypeId() == TYPEID_UNIT)
{
float x, y, z;
mg->GetDestination(x, y, z);
PSendSysMessage(LANG_MOVEGENS_HOME_CREATURE, x, y, z);
}
else
SendSysMessage(LANG_MOVEGENS_HOME_PLAYER);
break;
}
case FLIGHT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FLIGHT); break;
case POINT_MOTION_TYPE:
{
float x, y, z;
mg->GetDestination(x, y, z);
PSendSysMessage(LANG_MOVEGENS_POINT, x, y, z);
break;
}
case FLEEING_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FEAR); break;
case DISTRACT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_DISTRACT); break;
case EFFECT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_EFFECT); break;
default:
PSendSysMessage(LANG_MOVEGENS_UNKNOWN, mg->GetMovementGeneratorType());
break;
@@ -4040,19 +4050,14 @@ bool ChatHandler::HandleComeToMeCommand(const char *args)
if (!newFlagStr)
return false;
uint32 newFlags = (uint32)strtoul(newFlagStr, NULL, 0);
Creature* caster = getSelectedCreature();
if (!caster)
{
m_session->GetPlayer()->SetUnitMovementFlags(newFlags);
SendSysMessage(LANG_SELECT_CREATURE);
SetSentErrorMessage(true);
return false;
}
caster->SetUnitMovementFlags(newFlags);
Player* player = m_session->GetPlayer();
caster->GetMotionMaster()->MovePoint(0, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
+43 -29
View File
@@ -48,6 +48,8 @@
#include "Vehicle.h"
#include "SpellAuraEffects.h"
#include "Group.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
// apply implementation of the singletons
TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const
@@ -143,7 +145,7 @@ m_PlayerDamageReq(0), m_lootMoney(0), m_lootRecipient(0), m_lootRecipientGroup(0
m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE),
m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
m_creatureInfo(NULL), m_creatureData(NULL), m_formation(NULL)
m_creatureInfo(NULL), m_creatureData(NULL), m_formation(NULL), m_path_id(0)
{
m_regenTimer = CREATURE_REGEN_INTERVAL;
m_valuesCount = UNIT_END;
@@ -332,6 +334,7 @@ bool Creature::InitEntry(uint32 Entry, uint32 /*team*/, const CreatureData* data
SetSpeed(MOVE_FLIGHT, 1.0f); // using 1.0 rate
SetFloatValue(OBJECT_FIELD_SCALE_X, cinfo->scale);
SetLevitate(canFly());
// checked at loading
m_defaultMovementType = MovementGeneratorType(cinfo->MovementType);
@@ -435,6 +438,17 @@ void Creature::Update(uint32 diff)
m_vehicleKit->Reset();
}
if (IsInWater())
{
if (canSwim())
AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
}
else
{
if (canWalk())
RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
}
switch (m_deathState)
{
case JUST_ALIVED:
@@ -472,9 +486,7 @@ void Creature::Update(uint32 diff)
}
case CORPSE:
{
m_Events.Update(diff);
_UpdateSpells(diff);
Unit::Update(diff);
// deathstate changed on spells update, prevent problems
if (m_deathState != CORPSE)
break;
@@ -565,9 +577,6 @@ void Creature::Update(uint32 diff)
m_regenTimer = CREATURE_REGEN_INTERVAL;
break;
}
case DEAD_FALLING:
GetMotionMaster()->UpdateMotion(diff);
break;
default:
break;
}
@@ -945,7 +954,8 @@ void Creature::AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint3
m_startMove = getMSTime();
m_moveTime = time;*/
SendMonsterMove(x, y, z, time);
float speed = GetDistance(x, y, z) / ((float)time * 0.001f);
MonsterMoveWithSpeed(x, y, z, speed);
}
Player* Creature::GetLootRecipient() const
@@ -1507,8 +1517,8 @@ void Creature::setDeathState(DeathState s)
if (m_formation && m_formation->getLeader() == this)
m_formation->FormationReset(true);
if ((canFly() || IsFlying()) && FallGround())
return;
if ((canFly() || IsFlying()))
i_motionMaster.MoveFall();
Unit::setDeathState(CORPSE);
}
@@ -1520,7 +1530,7 @@ void Creature::setDeathState(DeathState s)
SetLootRecipient(NULL);
ResetPlayerDamageReq();
CreatureTemplate const* cinfo = GetCreatureInfo();
AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
SetWalk(true);
if (GetCreatureInfo()->InhabitType & INHABIT_AIR)
AddUnitMovementFlag(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_FLYING);
if (GetCreatureInfo()->InhabitType & INHABIT_WATER)
@@ -1536,24 +1546,6 @@ void Creature::setDeathState(DeathState s)
}
}
bool Creature::FallGround()
{
// Let's abort after we called this function one time
if (getDeathState() == DEAD_FALLING)
return false;
float x, y, z;
GetPosition(x, y, z);
// use larger distance for vmap height search than in most other cases
float ground_Z = GetMap()->GetHeight(x, y, z, true, MAX_FALL_DISTANCE);
if (fabs(ground_Z - z) < 0.1f)
return false;
GetMotionMaster()->MoveFall(ground_Z, EVENT_FALL_GROUND);
Unit::setDeathState(DEAD_FALLING);
return true;
}
void Creature::Respawn(bool force)
{
DestroyForNearbyPlayers();
@@ -2415,3 +2407,25 @@ bool Creature::IsDungeonBoss() const
CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(GetEntry());
return cinfo && (cinfo->flags_extra & CREATURE_FLAG_EXTRA_DUNGEON_BOSS);
}
void Creature::SetWalk(bool enable)
{
if (enable)
AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
else
RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
WorldPacket data(enable ? SMSG_SPLINE_MOVE_SET_WALK_MODE : SMSG_SPLINE_MOVE_SET_RUN_MODE, 9);
data.append(GetPackGUID());
SendMessageToSet(&data, true);
}
void Creature::SetLevitate(bool enable)
{
if (enable)
AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
else
RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
WorldPacket data(enable ? SMSG_SPLINE_MOVE_GRAVITY_DISABLE : SMSG_SPLINE_MOVE_GRAVITY_ENABLE, 9);
data.append(GetPackGUID());
SendMessageToSet(&data, true);
}
+3 -1
View File
@@ -520,6 +520,9 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature
void AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type);
CreatureAI* AI() const { return (CreatureAI*)i_AI; }
void SetWalk(bool enable);
void SetLevitate(bool enable);
uint32 GetShieldBlockValue() const //dunno mob block value
{
return (getLevel()/2 + uint32(GetStat(STAT_STRENGTH)/20));
@@ -573,7 +576,6 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature
const char* GetNameForLocaleIdx(LocaleConstant locale_idx) const;
void setDeathState(DeathState s); // override virtual Unit::setDeathState
bool FallGround();
bool LoadFromDB(uint32 guid, Map* map) { return LoadCreatureFromDB(guid, map, false); }
bool LoadCreatureFromDB(uint32 guid, Map* map, bool addToMap = true);
@@ -212,10 +212,12 @@ void CreatureGroup::FormationReset(bool dismiss)
void CreatureGroup::LeaderMoveTo(float x, float y, float z)
{
//! To do: This should probably get its own movement generator or use WaypointMovementGenerator.
//! If the leader's path is known, member's path can be plotted as well using formation offsets.
if (!m_leader)
return;
float pathangle = atan2(m_leader->GetPositionY() - y, m_leader->GetPositionX() - x);
float pathangle = atan2(m_leader->GetPositionY() - y, m_leader->GetPositionX() - x);
for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
{
@@ -1869,4 +1869,4 @@ void GameObject::SetLootState(LootState s)
{
m_lootState = s;
AI()->OnStateChanged(s);
}
}
+72 -67
View File
@@ -45,6 +45,7 @@
#include "TemporarySummon.h"
#include "Totem.h"
#include "OutdoorPvPMgr.h"
#include "MovementPacketBuilder.h"
uint32 GuidHigh2TypeId(uint32 guid_hi)
{
@@ -312,78 +313,17 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint16 flags) const
*data << ((Unit*)this)->GetSpeed(MOVE_WALK);
*data << ((Unit*)this)->GetSpeed(MOVE_RUN);
*data << ((Unit*)this)->GetSpeed(MOVE_SWIM_BACK);
*data << ((Unit*)this)->GetSpeed(MOVE_SWIM);
*data << ((Unit*)this)->GetSpeed(MOVE_RUN_BACK);
*data << ((Unit*)this)->GetSpeed(MOVE_SWIM);
*data << ((Unit*)this)->GetSpeed(MOVE_SWIM_BACK);
*data << ((Unit*)this)->GetSpeed(MOVE_FLIGHT);
*data << ((Unit*)this)->GetSpeed(MOVE_FLIGHT_BACK);
*data << ((Unit*)this)->GetSpeed(MOVE_TURN_RATE);
*data << ((Unit*)this)->GetSpeed(MOVE_PITCH_RATE);
const Player* player = ToPlayer();
// 0x08000000
if (player && player->isInFlight())
{
uint32 flags3 = SPLINEFLAG_GLIDE;
*data << uint32(flags3); // splines flag?
if (flags3 & 0x20000) // may be orientation
{
*data << (float)0;
}
else
{
if (flags3 & 0x8000) // probably x, y, z coords there
{
*data << (float)0;
*data << (float)0;
*data << (float)0;
}
if (flags3 & 0x10000) // probably guid there
{
*data << uint64(0);
}
}
FlightPathMovementGenerator *fmg =
(FlightPathMovementGenerator*)(player->GetMotionMaster()->top());
TaxiPathNodeList const& path = fmg->GetPath();
float x, y, z;
player->GetPosition(x, y, z);
uint32 inflighttime = uint32(path.GetPassedLength(fmg->GetCurrentNode(), x, y, z) * 32);
uint32 traveltime = uint32(path.GetTotalLength() * 32);
*data << uint32(inflighttime); // passed move time?
*data << uint32(traveltime); // full move time?
*data << uint32(0); // ticks count?
*data << float(0); // added in 3.1
*data << float(0); // added in 3.1
*data << float(0); // added in 3.1
*data << uint32(0); // added in 3.1
uint32 poscount = uint32(path.size());
*data << uint32(poscount); // points count
for (uint32 i = 0; i < poscount; ++i)
{
*data << float(path[i].x);
*data << float(path[i].y);
*data << float(path[i].z);
}
*data << uint8(0); // added in 3.0.8
*data << float(path[poscount-1].x);
*data << float(path[poscount-1].y);
*data << float(path[poscount-1].z);
}
if (((Unit*)this)->m_movementInfo.GetMovementFlags() & MOVEMENTFLAG_SPLINE_ENABLED)
Movement::PacketBuilder::WriteCreate(*((Unit*)this)->movespline, *data);
}
else
{
@@ -487,7 +427,7 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint16 flags) const
// 0x200
if (flags & UPDATEFLAG_ROTATION)
{
*data << uint64(((GameObject*)this)->GetRotation());
*data << int64(((GameObject*)this)->GetRotation());
}
}
@@ -1595,6 +1535,70 @@ void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const
z = new_z+ 0.05f; // just to be sure that we are not a few pixel under the surface
}
void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const
{
switch (GetTypeId())
{
case TYPEID_UNIT:
{
// non fly unit don't must be in air
// non swim unit must be at ground (mostly speedup, because it don't must be in water and water level check less fast
if (!((Creature const*)this)->canFly())
{
bool canSwim = ((Creature const*)this)->canSwim();
float ground_z = z;
float max_z = canSwim
? GetBaseMap()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK))
: ((ground_z = GetBaseMap()->GetHeight(x, y, z, true)));
if (max_z > INVALID_HEIGHT)
{
if (z > max_z)
z = max_z;
else if (z < ground_z)
z = ground_z;
}
}
else
{
float ground_z = GetBaseMap()->GetHeight(x, y, z, true);
if (z < ground_z)
z = ground_z;
}
break;
}
case TYPEID_PLAYER:
{
// for server controlled moves playr work same as creature (but it can always swim)
if (!((Player const*)this)->canFly())
{
float ground_z = z;
float max_z = GetBaseMap()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK));
if (max_z > INVALID_HEIGHT)
{
if (z > max_z)
z = max_z;
else if (z < ground_z)
z = ground_z;
}
}
else
{
float ground_z = GetBaseMap()->GetHeight(x, y, z, true);
if (z < ground_z)
z = ground_z;
}
break;
}
default:
{
float ground_z = GetBaseMap()->GetHeight(x, y, z, true);
if(ground_z > INVALID_HEIGHT)
z = ground_z;
break;
}
}
}
bool Position::IsPositionValid() const
{
return Trinity::IsValidMapCoord(m_positionX, m_positionY, m_positionZ, m_orientation);
@@ -2033,7 +2037,8 @@ void Unit::BuildHeartBeatMsg(WorldPacket* data) const
void WorldObject::SendMessageToSet(WorldPacket* data, bool self)
{
SendMessageToSetInRange(data, GetVisibilityRange(), self);
if (IsInWorld())
SendMessageToSetInRange(data, GetVisibilityRange(), self);
}
void WorldObject::SendMessageToSetInRange(WorldPacket* data, float dist, bool /*self*/)
+3
View File
@@ -497,7 +497,9 @@ struct MovementInfo
}
uint32 GetMovementFlags() { return flags; }
void SetMovementFlags(uint32 flag) { flags = flag; }
void AddMovementFlag(uint32 flag) { flags |= flag; }
void RemoveMovementFlag(uint32 flag) { flags &= ~flag; }
bool HasMovementFlag(uint32 flag) const { return flags & flag; }
uint16 GetExtraMovementFlags() { return flags2; }
@@ -615,6 +617,7 @@ class WorldObject : public Object, public WorldLocation
return (m_valuesCount > UNIT_FIELD_COMBATREACH) ? m_floatValues[UNIT_FIELD_COMBATREACH] : DEFAULT_WORLD_OBJECT_SIZE;
}
void UpdateGroundPositionZ(float x, float y, float &z) const;
void UpdateAllowedPositionZ(float x, float y, float &z) const;
void GetRandomPoint(const Position &srcPos, float distance, float &rand_x, float &rand_y, float &rand_z) const;
void GetRandomPoint(const Position &srcPos, float distance, Position &pos) const
+2 -36
View File
@@ -2101,6 +2101,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
// reset movement flags at teleport, because player will continue move with these flags after teleport
SetUnitMovementFlags(0);
DisableSpline();
if (m_transport)
{
@@ -5148,43 +5149,10 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
}
}
/**
* FallMode = 0 implies that the player is dying, or already dead, and the proper death state will be set.
* = 1 simply causes the player to plummet towards the ground, and not suffer any damage.
* = 2 causes the player to plummet towards the ground, and causes falling damage, regardless
* of any auras that might of prevented fall damage.
*/
bool Player::FallGround(uint8 FallMode)
{
// Let's abort after we called this function one time
if (getDeathState() == DEAD_FALLING && FallMode == 0)
return false;
float x, y, z;
GetPosition(x, y, z);
float ground_Z = GetMap()->GetHeight(x, y, z);
float z_diff = 0.0f;
if ((z_diff = fabs(ground_Z - z)) < 0.1f)
return false;
GetMotionMaster()->MoveFall(ground_Z, EVENT_FALL_GROUND);
// Below formula for falling damage is from Player::HandleFall
if (FallMode == 2 && z_diff >= 14.57f)
{
uint32 damage = std::min(GetMaxHealth(), (uint32)((0.018f * z_diff - 0.2426f) * GetMaxHealth() * sWorld->getRate(RATE_DAMAGE_FALL)));
if (damage)
EnvironmentalDamage(DAMAGE_FALL, damage);
}
else if (FallMode == 0)
Unit::setDeathState(DEAD_FALLING);
return true;
}
void Player::KillPlayer()
{
if (IsFlying() && !GetTransport())
FallGround();
i_motionMaster.MoveFall();
SetMovement(MOVE_ROOT);
@@ -21474,8 +21442,6 @@ void Player::SendInitialVisiblePackets(Unit* target)
SendAurasForTarget(target);
if (target->isAlive())
{
if (target->GetMotionMaster()->GetCurrentMovementGeneratorType() != IDLE_MOTION_TYPE)
target->SendMonsterMoveWithSpeedToCurrentDestination(this);
if (target->HasUnitState(UNIT_STAT_MELEE_ATTACKING) && target->getVictim())
target->SendMeleeAttackStart(target->getVictim());
}
-1
View File
@@ -1964,7 +1964,6 @@ class Player : public Unit, public GridObject<Player>
Corpse* GetCorpse() const;
void SpawnCorpseBones();
void CreateCorpse();
bool FallGround(uint8 FallMode = 0);
void KillPlayer();
uint32 GetResurrectionSpellId();
void ResurrectPlayer(float restore_percent, bool applySickness = false);
+73 -185
View File
@@ -45,16 +45,16 @@
#include "InstanceSaveMgr.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "Path.h"
#include "CreatureGroups.h"
#include "PetAI.h"
#include "PassiveAI.h"
#include "Traveller.h"
#include "TemporarySummon.h"
#include "Vehicle.h"
#include "Transport.h"
#include "InstanceScript.h"
#include "SpellInfo.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#include <math.h>
@@ -62,9 +62,9 @@ float baseMoveSpeed[MAX_MOVE_TYPE] =
{
2.5f, // MOVE_WALK
7.0f, // MOVE_RUN
2.5f, // MOVE_RUN_BACK
4.5f, // MOVE_RUN_BACK
4.722222f, // MOVE_SWIM
4.5f, // MOVE_SWIM_BACK
2.5f, // MOVE_SWIM_BACK
3.141594f, // MOVE_TURN_RATE
7.0f, // MOVE_FLIGHT
4.5f, // MOVE_FLIGHT_BACK
@@ -73,9 +73,9 @@ float baseMoveSpeed[MAX_MOVE_TYPE] =
float playerBaseMoveSpeed[MAX_MOVE_TYPE] = {
2.5f, // MOVE_WALK
7.0f, // MOVE_RUN
2.5f, // MOVE_RUN_BACK
4.5f, // MOVE_RUN_BACK
4.722222f, // MOVE_SWIM
4.5f, // MOVE_SWIM_BACK
2.5f, // MOVE_SWIM_BACK
3.141594f, // MOVE_TURN_RATE
7.0f, // MOVE_FLIGHT
4.5f, // MOVE_FLIGHT_BACK
@@ -148,7 +148,7 @@ Unit::Unit(bool isWorldObject): WorldObject(isWorldObject),
m_movedPlayer(NULL), m_lastSanctuaryTime(0), IsAIEnabled(false), NeedChangeAI(false),
m_ControlledByPlayer(false), i_AI(NULL), i_disabledAI(NULL), m_procDeep(0),
m_removedAurasCount(0), i_motionMaster(this), m_ThreatManager(this), m_vehicle(NULL),
m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this)
m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this), movespline(new Movement::MoveSpline())
{
#ifdef _MSC_VER
#pragma warning(default:4355)
@@ -280,6 +280,7 @@ Unit::~Unit()
delete m_charmInfo;
delete m_vehicleKit;
delete movespline;
ASSERT(!m_duringRemoveFromWorld);
ASSERT(!m_attacking);
@@ -346,6 +347,7 @@ void Unit::Update(uint32 p_time)
ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, HealthAbovePct(75));
}
UpdateSplineMovement(p_time);
i_motionMaster.UpdateMotion(p_time);
}
@@ -357,151 +359,46 @@ bool Unit::haveOffhandWeapon() const
return m_canDualWield;
}
void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player* player)
void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed)
{
float x, y, z;
if (GetMotionMaster()->GetDestination(x, y, z))
SendMonsterMoveWithSpeed(x, y, z, 0, player);
Movement::MoveSplineInit init(*this);
init.MoveTo(x,y,z);
init.SetVelocity(speed);
init.Launch();
}
void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime, Player* player)
void Unit::UpdateSplineMovement(uint32 t_diff)
{
if (!transitTime)
enum{
POSITION_UPDATE_DELAY = 400,
};
if (movespline->Finalized())
return;
movespline->updateState(t_diff);
bool arrived = movespline->Finalized();
if (arrived)
DisableSpline();
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)
{
Traveller<Player> traveller(*(Player*)this);
transitTime = traveller.GetTotalTrevelTimeTo(x, y, z);
}
((Player*)this)->UpdatePosition(loc.x,loc.y,loc.z,loc.orientation);
else
{
Traveller<Creature> traveller(*ToCreature());
transitTime = traveller.GetTotalTrevelTimeTo(x, y, z);
}
GetMap()->CreatureRelocation((Creature*)this,loc.x,loc.y,loc.z,loc.orientation);
}
//float orientation = (float)atan2((double)dy, (double)dx);
SendMonsterMove(x, y, z, transitTime, player);
}
void Unit::SetFacing(float ori, WorldObject* obj)
void Unit::DisableSpline()
{
SetOrientation(obj ? GetAngle(obj) : ori);
WorldPacket data(SMSG_MONSTER_MOVE, (1+12+4+1+(obj ? 8 : 4)+4+4+4+12+GetPackGUID().size()));
data.append(GetPackGUID());
data << uint8(0); // unk
data << GetPositionX() << GetPositionY() << GetPositionZ();
data << getMSTime();
if (obj)
{
data << uint8(SPLINETYPE_FACING_TARGET);
data << uint64(obj->GetGUID());
}
else
{
data << uint8(SPLINETYPE_FACING_ANGLE);
data << ori;
}
data << uint32(SPLINEFLAG_NONE);
data << uint32(0); // move time 0
data << uint32(1); // one point
data << GetPositionX() << GetPositionY() << GetPositionZ();
SendMessageToSet(&data, true);
}
void Unit::SendMonsterStop(bool on_death)
{
WorldPacket data(SMSG_MONSTER_MOVE, (17 + GetPackGUID().size()));
data.append(GetPackGUID());
data << uint8(0); // new in 3.1
data << GetPositionX() << GetPositionY() << GetPositionZ();
data << getMSTime();
if (on_death == true)
{
data << uint8(0);
data << uint32((GetUnitMovementFlags() & MOVEMENTFLAG_LEVITATING) ? SPLINEFLAG_FLYING : SPLINEFLAG_WALKING);
data << uint32(0); // Time in between points
data << uint32(1); // 1 single waypoint
data << GetPositionX() << GetPositionY() << GetPositionZ();
}
else
data << uint8(1);
SendMessageToSet(&data, true);
ClearUnitState(UNIT_STAT_MOVE);
}
void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 Time, Player* player)
{
WorldPacket data(SMSG_MONSTER_MOVE, 1+12+4+1+4+4+4+12+GetPackGUID().size());
data.append(GetPackGUID());
data << uint8(0); // new in 3.1
data << GetPositionX() << GetPositionY() << GetPositionZ();
data << getMSTime();
data << uint8(0);
data << uint32((GetUnitMovementFlags() & MOVEMENTFLAG_LEVITATING) ? SPLINEFLAG_FLYING : SPLINEFLAG_WALKING);
data << Time; // Time in between points
data << uint32(1); // 1 single waypoint
data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B
if (player)
player->GetSession()->SendPacket(&data);
else
SendMessageToSet(&data, true);
AddUnitState(UNIT_STAT_MOVE);
}
void Unit::SendMonsterMove(MonsterMoveData const& moveData, Player* player)
{
WorldPacket data(SMSG_MONSTER_MOVE, GetPackGUID().size() + 1 + 12 + 4 + 1 + 4 + 8 + 4 + 4 + 12);
data.append(GetPackGUID());
data << uint8(0); // new in 3.1
data << GetPositionX() << GetPositionY() << GetPositionZ();
data << getMSTime();
data << uint8(0);
data << moveData.SplineFlag;
if (moveData.SplineFlag & SPLINEFLAG_ANIMATIONTIER)
{
data << uint8(moveData.AnimationState);
data << uint32(0);
}
data << moveData.Time;
if (moveData.SplineFlag & SPLINEFLAG_TRAJECTORY)
{
data << moveData.SpeedZ;
data << uint32(0); // walk time after jump
}
data << uint32(1); // waypoint count
data << moveData.DestLocation.GetPositionX();
data << moveData.DestLocation.GetPositionY();
data << moveData.DestLocation.GetPositionZ();
if (player)
player->GetSession()->SendPacket(&data);
else
SendMessageToSet(&data, true);
}
void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 MoveFlags, uint32 time, float speedZ, Player* player)
{
MonsterMoveData data;
data.DestLocation.Relocate(NewPosX, NewPosY, NewPosZ);
data.SplineFlag = MoveFlags;
data.Time = time;
data.SpeedZ = speedZ;
SendMonsterMove(data, player);
m_movementInfo.RemoveMovementFlag(MovementFlags(MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD));
movespline->_Interrupt();
}
void Unit::SendMonsterMoveExitVehicle(Position const* newPos)
@@ -3106,17 +3003,6 @@ bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
return IsWithinDistInMap(target, distance) && !HasInArc(2 * M_PI - arc, target);
}
void Unit::SetFacingToObject(WorldObject* pObject)
{
// update orientation at server
SetOrientation(GetAngle(pObject));
// and client
WorldPacket data;
BuildHeartBeatMsg(&data);
SendMessageToSet(&data, false);
}
bool Unit::isInAccessiblePlaceFor(Creature const* c) const
{
if (IsInWater())
@@ -12744,7 +12630,7 @@ void Unit::setDeathState(DeathState s)
ClearDiminishings();
GetMotionMaster()->Clear(false);
GetMotionMaster()->MoveIdle();
SendMonsterStop(true);
StopMoving();
// without this when removing IncreaseMaxHealth aura player may stuck with 1 hp
// do not why since in IncreaseMaxHealth currenthealth is checked
SetHealth(0);
@@ -13565,7 +13451,7 @@ void Unit::SetHealth(uint32 val)
{
if (getDeathState() == JUST_DIED)
val = 0;
else if (GetTypeId() == TYPEID_PLAYER && (getDeathState() == DEAD || getDeathState() == DEAD_FALLING))
else if (GetTypeId() == TYPEID_PLAYER && getDeathState() == DEAD)
val = 1;
else
{
@@ -14682,22 +14568,20 @@ void Unit::StopMoving()
{
ClearUnitState(UNIT_STAT_MOVING);
// send explicit stop packet
// rely on vmaps here because for example stormwind is in air
//float z = sMapMgr->GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true);
//if (fabs(GetPositionZ() - z) < 2.0f)
// Relocate(GetPositionX(), GetPositionY(), z);
//Relocate(GetPositionX(), GetPositionY(), GetPositionZ());
// not need send any packets if not in world
if (!IsInWorld())
return;
if (!(GetUnitMovementFlags() & MOVEMENTFLAG_ONTRANSPORT))
SendMonsterStop();
Movement::MoveSplineInit init(*this);
init.SetFacing(GetOrientation());
init.Launch();
}
void Unit::SendMovementFlagUpdate()
{
WorldPacket data;
BuildHeartBeatMsg(&data);
SendMessageToSet(&data, false);
SendMessageToSet(&data, true);
}
bool Unit::IsSitState() const
@@ -17097,7 +16981,7 @@ void Unit::_ExitVehicle(Position const* exitPosition)
WorldPacket data2;
BuildHeartBeatMsg(&data2);
SendMessageToSet(&data2, false);
SendMessageToSet(&data2, true);
if (vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION))
if (((Minion*)vehicle->GetBase())->GetOwner() == this)
@@ -17116,25 +17000,6 @@ void Unit::_ExitVehicle(Position const* exitPosition)
void Unit::BuildMovementPacket(ByteBuffer *data) const
{
switch (GetTypeId())
{
case TYPEID_UNIT:
if (canFly())
const_cast<Unit*>(this)->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
break;
case TYPEID_PLAYER:
// remove unknown, unused etc flags for now
const_cast<Unit*>(this)->RemoveUnitMovementFlag(MOVEMENTFLAG_SPLINE_ENABLED);
if (isInFlight())
{
WPAssert(const_cast<Unit*>(this)->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE);
const_cast<Unit*>(this)->AddUnitMovementFlag(MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_SPLINE_ENABLED);
}
break;
default:
break;
}
*data << uint32(GetUnitMovementFlags()); // movement flags
*data << uint16(m_movementInfo.flags2); // 2.3.0
*data << uint32(getMSTime()); // time
@@ -17198,13 +17063,13 @@ void Unit::SetFlying(bool apply)
void Unit::NearTeleportTo(float x, float y, float z, float orientation, bool casting /*= false*/)
{
DisableSpline();
if (GetTypeId() == TYPEID_PLAYER)
ToPlayer()->TeleportTo(GetMapId(), x, y, z, orientation, TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (casting ? TELE_TO_SPELL : 0));
else
{
// FIXME: this interrupts spell visual
DestroyForNearbyPlayers();
UpdatePosition(x, y, z, orientation, true);
SendMovementFlagUpdate();
}
}
@@ -17486,3 +17351,26 @@ bool CharmInfo::IsReturning()
{
return m_isReturning;
}
void Unit::SetInFront(Unit const* target)
{
if (!HasUnitState(UNIT_STAT_CANNOT_TURN))
SetOrientation(GetAngle(target));
}
void Unit::SetFacingTo(float ori)
{
Movement::MoveSplineInit init(*this);
init.SetFacing(ori);
init.Launch();
}
void Unit::SetFacingToObject(WorldObject* pObject)
{
// never face when already moving
if (!IsStopped())
return;
// TODO: figure out under what conditions creature will move towards object instead of facing it where it currently is.
SetFacingTo(GetAngle(pObject));
}
+35 -91
View File
@@ -465,7 +465,6 @@ enum DeathState
CORPSE = 2,
DEAD = 3,
JUST_ALIVED = 4,
DEAD_FALLING= 5
};
enum UnitState
@@ -493,13 +492,22 @@ enum UnitState
UNIT_STAT_MOVE = 0x00100000,
UNIT_STAT_ROTATING = 0x00200000,
UNIT_STAT_EVADE = 0x00400000,
UNIT_STAT_ROAMING_MOVE = 0x00800000,
UNIT_STAT_CONFUSED_MOVE = 0x01000000,
UNIT_STAT_FLEEING_MOVE = 0x02000000,
UNIT_STAT_CHASE_MOVE = 0x04000000,
UNIT_STAT_FOLLOW_MOVE = 0x08000000,
UNIT_STAT_UNATTACKABLE = (UNIT_STAT_IN_FLIGHT | UNIT_STAT_ONVEHICLE),
UNIT_STAT_MOVING = (UNIT_STAT_ROAMING | UNIT_STAT_CHASE),
//UNIT_STAT_MOVING = (UNIT_STAT_ROAMING | UNIT_STAT_CHASE),
// for real move using movegen check and stop (except unstoppable flight)
UNIT_STAT_MOVING = UNIT_STAT_ROAMING_MOVE | UNIT_STAT_CONFUSED_MOVE | UNIT_STAT_FLEEING_MOVE| UNIT_STAT_CHASE_MOVE | UNIT_STAT_FOLLOW_MOVE ,
UNIT_STAT_CONTROLLED = (UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING),
UNIT_STAT_LOST_CONTROL = (UNIT_STAT_CONTROLLED | UNIT_STAT_JUMPING | UNIT_STAT_CHARGING),
UNIT_STAT_SIGHTLESS = (UNIT_STAT_LOST_CONTROL | UNIT_STAT_EVADE),
UNIT_STAT_CANNOT_AUTOATTACK = (UNIT_STAT_LOST_CONTROL | UNIT_STAT_CASTING),
UNIT_STAT_CANNOT_TURN = (UNIT_STAT_LOST_CONTROL | UNIT_STAT_ROTATING),
// stay by different reasons
UNIT_STAT_NOT_MOVE = UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DIED | UNIT_STAT_DISTRACTED,
UNIT_STAT_ALL_STATE = 0xffffffff //(UNIT_STAT_STOPPED | UNIT_STAT_MOVING | UNIT_STAT_IN_COMBAT | UNIT_STAT_IN_FLIGHT)
};
@@ -719,59 +727,18 @@ enum MovementFlags2
MOVEMENTFLAG2_UNK15 = 0x00004000,
MOVEMENTFLAG2_UNK16 = 0x00008000,
};
enum SplineFlags
{
SPLINEFLAG_NONE = 0x00000000,
SPLINEFLAG_FORWARD = 0x00000001,
SPLINEFLAG_BACKWARD = 0x00000002,
SPLINEFLAG_STRAFE_LEFT = 0x00000004,
SPLINEFLAG_STRAFE_RIGHT = 0x00000008,
SPLINEFLAG_LEFT = 0x00000010,
SPLINEFLAG_RIGHT = 0x00000020,
SPLINEFLAG_PITCH_UP = 0x00000040,
SPLINEFLAG_PITCH_DOWN = 0x00000080,
SPLINEFLAG_DONE = 0x00000100,
SPLINEFLAG_FALLING = 0x00000200,
SPLINEFLAG_NO_SPLINE = 0x00000400,
SPLINEFLAG_TRAJECTORY = 0x00000800,
SPLINEFLAG_WALKING = 0x00001000,
SPLINEFLAG_FLYING = 0x00002000,
SPLINEFLAG_KNOCKBACK = 0x00004000,
SPLINEFLAG_FINAL_POINT = 0x00008000,
SPLINEFLAG_FINAL_TARGET = 0x00010000,
SPLINEFLAG_FINAL_FACING = 0x00020000,
SPLINEFLAG_CATMULL_ROM = 0x00040000,
SPLINEFLAG_UNKNOWN20 = 0x00080000,
SPLINEFLAG_UNKNOWN21 = 0x00100000,
SPLINEFLAG_ANIMATIONTIER = 0x00200000,
SPLINEFLAG_UNKNOWN23 = 0x00400000,
SPLINEFLAG_TRANSPORT = 0x00800000,
SPLINEFLAG_EXIT_VEHICLE = 0x01000000,
SPLINEFLAG_UNKNOWN26 = 0x02000000,
SPLINEFLAG_UNKNOWN27 = 0x04000000,
SPLINEFLAG_UNKNOWN28 = 0x08000000,
SPLINEFLAG_UNKNOWN29 = 0x10000000,
SPLINEFLAG_ANIMATION = 0x20000000,
SPLINEFLAG_UNKNOWN31 = 0x40000000,
SPLINEFLAG_UNKNOWN32 = 0x80000000,
SPLINEFLAG_GLIDE = SPLINEFLAG_WALKING | SPLINEFLAG_FLYING,
};
enum SplineMode
{
SPLINEMODE_LINEAR = 0,
SPLINEMODE_CATMULL_ROM = 1,
SPLINEMODE_BEZIER3 = 2
SPLINEFLAG_WALKMODE = 0x00001000,
SPLINEFLAG_FLYING = 0x00002000,
SPLINEFLAG_TRANSPORT = 0x00800000,
SPLINEFLAG_EXIT_VEHICLE = 0x01000000,
};
enum SplineType
{
SPLINETYPE_NORMAL = 0,
SPLINETYPE_STOP = 1,
SPLINETYPE_FACING_SPOT = 2,
SPLINETYPE_FACING_TARGET = 3,
SPLINETYPE_FACING_ANGLE = 4
SPLINETYPE_FACING_ANGLE = 4,
};
enum UnitTypeMask
@@ -789,6 +756,10 @@ enum UnitTypeMask
UNIT_MASK_ACCESSORY = 0x00000200,
};
namespace Movement{
class MoveSpline;
}
enum DiminishingLevels
{
DIMINISHING_LEVEL_1 = 0,
@@ -1628,20 +1599,18 @@ class Unit : public WorldObject
void JumpTo(float speedXY, float speedZ, bool forward = true);
void JumpTo(WorldObject* obj, float speedZ);
void SetFacing(float ori, WorldObject* obj = NULL);
void SendMonsterStop(bool on_death = false);
void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 Time, Player* player = NULL);
void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 MoveFlags, uint32 time, float speedZ, Player* player = NULL);
void SendMonsterMove(MonsterMoveData const& moveData, Player* receiver = NULL);
void MonsterMoveWithSpeed(float x, float y, float z, float speed);
//void SetFacing(float ori, WorldObject* obj = NULL);
void SendMonsterMoveExitVehicle(Position const* newPos);
//void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL);
void SendMonsterMoveTransport(Unit* vehicleOwner);
void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0, Player* player = NULL);
void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL);
void SendMovementFlagUpdate();
bool IsLevitating() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_LEVITATING);}
bool IsWalking() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING);}
template<typename PathElem, typename PathNode>
void SendMonsterMoveByPath(Path<PathElem, PathNode> const& path, uint32 start, uint32 end);
void SetInFront(Unit const* target);
void SetFacingTo(float ori);
void SetFacingToObject(WorldObject* pObject);
void SendChangeCurrentVictimOpcode(HostileReference* pHostileReference);
void SendClearThreatListOpcode();
@@ -1951,13 +1920,7 @@ class Unit : public WorldObject
void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; }
bool isInFrontInMap(Unit const* target, float distance, float arc = M_PI) const;
void SetInFront(Unit const* target)
{
if (!HasUnitState(UNIT_STAT_CANNOT_TURN))
SetOrientation(GetAngle(target));
}
bool isInBackInMap(Unit const* target, float distance, float arc = M_PI) const;
void SetFacingToObject(WorldObject* pObject);
// Visibility system
bool IsVisible() const { return (m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM) > SEC_PLAYER) ? false : true; }
@@ -2232,6 +2195,9 @@ class Unit : public WorldObject
SetUInt64Value(UNIT_FIELD_TARGET, 0);
}
// Movement info
Movement::MoveSpline * movespline;
protected:
explicit Unit (bool isWorldObject);
@@ -2303,6 +2269,8 @@ class Unit : public WorldObject
bool IsAlwaysVisibleFor(WorldObject const* seer) const;
bool IsAlwaysDetectableFor(WorldObject const* seer) const;
void DisableSpline();
private:
bool IsTriggeredAtSpellProcEvent(Unit* pVictim, Aura* aura, SpellInfo const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const* & spellProcEvent);
bool HandleDummyAuraProc(Unit* pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
@@ -2316,6 +2284,8 @@ class Unit : public WorldObject
bool HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura);
bool HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura);
void UpdateSplineMovement(uint32 t_diff);
// player or player's pet
float GetCombatRatingReduction(CombatRating cr) const;
uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const;
@@ -2330,6 +2300,7 @@ class Unit : public WorldObject
uint32 m_state; // Even derived shouldn't modify
uint32 m_CombatTimer;
uint32 m_lastManaUse; // msecs
TimeTrackerSmall m_movesplineTimer;
Diminishing m_Diminishing;
// Manage all Units that are threatened by us
@@ -2382,31 +2353,4 @@ namespace Trinity
const bool m_ascending;
};
}
template<typename Elem, typename Node>
inline void Unit::SendMonsterMoveByPath(Path<Elem, Node> const& path, uint32 start, uint32 end)
{
uint32 traveltime = uint32(path.GetTotalLength(start, end) * 32);
uint32 pathSize = end - start;
WorldPacket data(SMSG_MONSTER_MOVE, (GetPackGUID().size()+1+4+4+4+4+1+4+4+4+pathSize*4*3));
data.append(GetPackGUID());
data << uint8(0);
data << GetPositionX();
data << GetPositionY();
data << GetPositionZ();
data << uint32(getMSTime());
data << uint8(0);
data << uint32(((GetUnitMovementFlags() & MOVEMENTFLAG_LEVITATING) || isInFlight()) ? (SPLINEFLAG_FLYING|SPLINEFLAG_WALKING) : SPLINEFLAG_WALKING);
data << uint32(traveltime);
data << uint32(pathSize);
for (uint32 i = start; i < end; ++i)
{
data << float(path[i].x);
data << float(path[i].y);
data << float(path[i].z);
}
SendMessageToSet(&data, true);
}
#endif
+18
View File
@@ -1539,6 +1539,24 @@ inline GridMap* Map::GetGrid(float x, float y)
return GridMaps[gx][gy];
}
float Map::GetWaterOrGroundLevel(float x, float y, float z, float* ground /*= NULL*/, bool swim /*= false*/) const
{
if (const_cast<Map*>(this)->GetGrid(x, y))
{
// we need ground level (including grid height version) for proper return water level in point
float ground_z = GetHeight(x, y, z, true, 50.0f);
if (ground)
*ground = ground_z;
LiquidData liquid_status;
ZLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status);
return res ? ( swim ? liquid_status.level - 2.0f : liquid_status.level) : ground_z;
}
return VMAP_INVALID_HEIGHT_VALUE;
}
float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
{
// find raw .map surface under Z coordinates
+2
View File
@@ -424,6 +424,8 @@ class Map : public GridRefManager<NGridType>
InstanceMap* ToInstanceMap(){ if (IsDungeon()) return reinterpret_cast<InstanceMap*>(this); else return NULL; }
const InstanceMap* ToInstanceMap() const { if (IsDungeon()) return (const InstanceMap*)((InstanceMap*)this); else return NULL; }
float GetWaterOrGroundLevel(float x, float y, float z, float* ground = NULL, bool swim = false) const;
private:
void LoadMapAndVMap(int gx, int gy);
void LoadVMap(int gx, int gy);
-1
View File
@@ -25,7 +25,6 @@
#include "GridDefines.h"
#include "MapInstanced.h"
#include "InstanceScript.h"
#include "DestinationHolderImp.h"
#include "Config.h"
#include "World.h"
#include "CellImpl.h"
+8 -4
View File
@@ -492,9 +492,9 @@ enum TrinityStrings
LANG_MOVEGENS_WAYPOINT = 529,
LANG_MOVEGENS_ANIMAL_RANDOM = 530,
LANG_MOVEGENS_CONFUSED = 531,
LANG_MOVEGENS_TARGETED_PLAYER = 532,
LANG_MOVEGENS_TARGETED_CREATURE = 533,
LANG_MOVEGENS_TARGETED_NULL = 534,
LANG_MOVEGENS_CHASE_PLAYER = 532,
LANG_MOVEGENS_CHASE_CREATURE = 533,
LANG_MOVEGENS_CHASE_NULL = 534,
LANG_MOVEGENS_HOME_CREATURE = 535,
LANG_MOVEGENS_HOME_PLAYER = 536,
LANG_MOVEGENS_FLIGHT = 537,
@@ -807,7 +807,11 @@ enum TrinityStrings
LANG_CHAR_NOT_BANNED = 1136,
LANG_DEV_ON = 1137,
LANG_DEV_OFF = 1138,
// Room for more level 3 1139-1199 not used
LANG_MOVEGENS_FOLLOW_PLAYER = 1139,
LANG_MOVEGENS_FOLLOW_CREATURE = 1140,
LANG_MOVEGENS_FOLLOW_NULL = 1141,
LANG_MOVEGENS_EFFECT = 1142,
// Room for more level 3 1143-1199 not used
// Debug commands
LANG_CINEMATIC_NOT_EXIST = 1200,
@@ -1,20 +0,0 @@
/*
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "DestinationHolder.h"
@@ -1,65 +0,0 @@
/*
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRINITY_DESTINATION_HOLDER_H
#define TRINITY_DESTINATION_HOLDER_H
#include "Define.h"
#include "Timer.h"
class WorldObject;
class Map;
#define TRAVELLER_UPDATE_INTERVAL 300
template<typename TRAVELLER>
class DestinationHolder
{
TimeTrackerSmall i_tracker;
uint32 i_totalTravelTime;
uint32 i_timeElapsed;
bool i_destSet;
float i_fromX, i_fromY, i_fromZ;
float i_destX, i_destY, i_destZ;
public:
DestinationHolder() : i_tracker(TRAVELLER_UPDATE_INTERVAL), i_totalTravelTime(0), i_timeElapsed(0),
i_destSet(false), i_fromX(0), i_fromY(0), i_fromZ(0), i_destX(0), i_destY(0), i_destZ(0) {}
uint32 SetDestination(TRAVELLER &traveller, float dest_x, float dest_y, float dest_z, bool sendMove = true);
void GetDestination(float &x, float &y, float &z) const { x = i_destX; y = i_destY; z = i_destZ; }
bool UpdateExpired(void) const { return i_tracker.Passed(); }
void ResetUpdate(uint32 t = TRAVELLER_UPDATE_INTERVAL) { i_tracker.Reset(t); }
uint32 GetTotalTravelTime(void) const { return i_totalTravelTime; }
void IncreaseTravelTime(uint32 increment) { i_totalTravelTime += increment; }
void ResetTravelTime() { i_totalTravelTime = 0; }
bool HasDestination(void) const { return i_destSet; }
float GetDestinationDiff(float x, float y, float z) const;
bool HasArrived(void) const { return (i_totalTravelTime == 0 || i_timeElapsed >= i_totalTravelTime); }
bool UpdateTraveller(TRAVELLER &traveller, uint32 diff, bool micro_movement=false);
uint32 StartTravel(TRAVELLER &traveller, bool sendMove = true);
void GetLocationNow(const Map* map, float &x, float &y, float &z, bool is3D = false) const;
void GetLocationNowNoMicroMovement(float &x, float &y, float &z) const; // For use without micro movement
float GetDistance3dFromDestSq(const WorldObject &obj) const;
private:
void _findOffSetPoint(float x1, float y1, float x2, float y2, float offset, float &x, float &y);
};
#endif
@@ -1,215 +0,0 @@
/*
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRINITY_DESTINATIONHOLDERIMP_H
#define TRINITY_DESTINATIONHOLDERIMP_H
#include "MapManager.h"
#include "DestinationHolder.h"
#include <cmath>
template<typename TRAVELLER>
void
DestinationHolder<TRAVELLER>::_findOffSetPoint(float x1, float y1, float x2, float y2, float offset, float &x, float &y)
{
/* given the point (x1, y1) and (x2, y2).. need to find the point (x, y) on the same line
* such that the distance from (x, y) to (x2, y2) is offset.
* Let the distance of p1 to p2 = d.. then the ratio of offset/d = (x2-x)/(x2-x1)
* hence x = x2 - (offset/d)*(x2-x1)
* like wise offset/d = (y2-y)/(y2-y1);
*/
if (offset == 0)
{
x = x2;
y = y2;
}
else
{
double x_diff = double(x2 - x1);
double y_diff = double(y2 - y1);
double distance_d = (double)((x_diff*x_diff) + (y_diff * y_diff));
if (distance_d == 0)
{
x = x2;
y = y2;
}
else
{
distance_d = ::sqrt(distance_d); // starting distance
double distance_ratio = (double)(distance_d - offset)/(double)distance_d;
// line above has revised formula which is more correct, I think
x = (float)(x1 + (distance_ratio*x_diff));
y = (float)(y1 + (distance_ratio*y_diff));
}
}
}
template<typename TRAVELLER>
uint32
DestinationHolder<TRAVELLER>::SetDestination(TRAVELLER &traveller, float dest_x, float dest_y, float dest_z, bool sendMove)
{
i_destSet = true;
i_destX = dest_x;
i_destY = dest_y;
i_destZ = dest_z;
return StartTravel(traveller, sendMove);
}
template<typename TRAVELLER>
uint32
DestinationHolder<TRAVELLER>::StartTravel(TRAVELLER &traveller, bool sendMove)
{
if (!i_destSet) return 0;
i_fromX = traveller.GetPositionX();
i_fromY = traveller.GetPositionY();
i_fromZ = traveller.GetPositionZ();
i_totalTravelTime = traveller.GetTotalTrevelTimeTo(i_destX, i_destY, i_destZ);
i_timeElapsed = 0;
if (sendMove)
traveller.MoveTo(i_destX, i_destY, i_destZ, i_totalTravelTime);
return i_totalTravelTime;
}
template<typename TRAVELLER>
bool
DestinationHolder<TRAVELLER>::UpdateTraveller(TRAVELLER &traveller, uint32 diff, bool micro_movement)
{
i_timeElapsed += diff;
// Update every TRAVELLER_UPDATE_INTERVAL
i_tracker.Update(diff);
if (!i_tracker.Passed())
return false;
else
ResetUpdate();
if (!i_destSet) return true;
float x, y, z;
if (!micro_movement)
GetLocationNowNoMicroMovement(x, y, z);
else
{
if (!traveller.GetTraveller().HasUnitState(UNIT_STAT_MOVING | UNIT_STAT_IN_FLIGHT))
return true;
if (traveller.GetTraveller().HasUnitState(UNIT_STAT_IN_FLIGHT))
GetLocationNow(traveller.GetTraveller().GetBaseMap(), x, y, z, true); // Should reposition Object with right Coord, so I can bypass some Grid Relocation
else
GetLocationNow(traveller.GetTraveller().GetBaseMap(), x, y, z, false);
// Change movement computation to micro movement based on last tick coords, this makes system work
// even on multiple floors zones without hugh vmaps usage ;)
// Take care of underrun of uint32
if (i_totalTravelTime >= i_timeElapsed)
i_totalTravelTime -= i_timeElapsed; // Consider only the remaining part
else
i_totalTravelTime = 0;
i_timeElapsed = 0;
i_fromX = x; // and change origine
i_fromY = y; // then I take into account only micro movement
i_fromZ = z;
}
if (traveller.GetTraveller().GetPositionX() != x || traveller.GetTraveller().GetPositionY() != y || traveller.GetTraveller().GetPositionZ() != z)
{
float ori = traveller.GetTraveller().GetAngle(x, y);
traveller.Relocation(x, y, z, ori);
}
return true;
}
template<typename TRAVELLER>
void
DestinationHolder<TRAVELLER>::GetLocationNow(const Map* map, float &x, float &y, float &z, bool is3D) const
{
if (HasArrived())
{
x = i_destX;
y = i_destY;
z = i_destZ;
}
else if (HasDestination())
{
double percent_passed = (double)i_timeElapsed / (double)i_totalTravelTime;
const float distanceX = (float)((i_destX - i_fromX) * percent_passed);
const float distanceY = (float)((i_destY - i_fromY) * percent_passed);
const float distanceZ = (float)((i_destZ - i_fromZ) * percent_passed);
x = i_fromX + distanceX;
y = i_fromY + distanceY;
float z2 = i_fromZ + distanceZ;
// All that is not finished but previous code neither... Traveller need be able to swim.
if (is3D)
z = z2;
else
{
//That part is good for mob Walking on the floor. But the floor is not always what we thought.
z = map->GetHeight(x, y, i_fromZ, false); // Disable cave check
const float groundDist = sqrt(distanceX*distanceX + distanceY*distanceY);
const float zDist = fabs(i_fromZ - z) + 0.000001f;
const float slope = groundDist / zDist;
if (slope < 1.0f) // This prevents the ground returned by GetHeight to be used when in cave
z = z2; // a climb or jump of more than 45 is denied
}
}
}
template<typename TRAVELLER>
float
DestinationHolder<TRAVELLER>::GetDistance3dFromDestSq(const WorldObject &obj) const
{
float x, y, z;
obj.GetPosition(x, y, z);
return (i_destX-x)*(i_destX-x)+(i_destY-y)*(i_destY-y)+(i_destZ-z)*(i_destZ-z);
}
template<typename TRAVELLER>
float
DestinationHolder<TRAVELLER>::GetDestinationDiff(float x, float y, float z) const
{
return sqrt(((x-i_destX)*(x-i_destX)) + ((y-i_destY)*(y-i_destY)) + ((z-i_destZ)*(z-i_destZ)));
}
template<typename TRAVELLER>
void
DestinationHolder<TRAVELLER>::GetLocationNowNoMicroMovement(float &x, float &y, float &z) const
{
if (HasArrived())
{
x = i_destX;
y = i_destY;
z = i_destZ;
}
else
{
double percent_passed = (double)i_timeElapsed / (double)i_totalTravelTime;
x = (float)(i_fromX + ((i_destX - i_fromX) * percent_passed));
y = (float)(i_fromY + ((i_destY - i_fromY) * percent_passed));
z = (float)(i_fromZ + ((i_destZ - i_fromZ) * percent_passed));
}
}
#endif
+77 -83
View File
@@ -19,7 +19,6 @@
#include "MotionMaster.h"
#include "CreatureAISelector.h"
#include "Creature.h"
#include "Traveller.h"
#include "ConfusedMovementGenerator.h"
#include "FleeingMovementGenerator.h"
@@ -29,7 +28,8 @@
#include "TargetedMovementGenerator.h"
#include "WaypointMovementGenerator.h"
#include "RandomMovementGenerator.h"
#include "MoveSpline.h"
#include "MoveSplineInit.h"
#include <cassert>
inline bool isStatic(MovementGenerator *mv)
@@ -193,16 +193,23 @@ void MotionMaster::MoveRandom(float spawndist)
void MotionMaster::MoveTargetedHome()
{
//if (i_owner->HasUnitState(UNIT_STAT_FLEEING))
// return;
Clear(false);
if (i_owner->GetTypeId() == TYPEID_UNIT)
if (i_owner->GetTypeId()==TYPEID_UNIT && !((Creature*)i_owner)->GetCharmerOrOwnerGUID())
{
sLog->outStaticDebug("Creature (Entry: %u GUID: %u) targeted home", i_owner->GetEntry(), i_owner->GetGUIDLow());
Mutate(new HomeMovementGenerator<Creature>(), MOTION_SLOT_ACTIVE);
}
else if (i_owner->GetTypeId()==TYPEID_UNIT && ((Creature*)i_owner)->GetCharmerOrOwnerGUID())
{
sLog->outStaticDebug("Pet or controlled creature (Entry: %u GUID: %u) targeting home", i_owner->GetEntry(), i_owner->GetGUIDLow() );
Unit *target = ((Creature*)i_owner)->GetCharmerOrOwner();
if (target)
{
sLog->outStaticDebug("Following %s (GUID: %u)", target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : ((Creature*)target)->GetDBTableGUIDLow() );
Mutate(new FollowMovementGenerator<Creature>(*target,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE), MOTION_SLOT_ACTIVE);
}
}
else
{
sLog->outError("Player (GUID: %u) attempt targeted home", i_owner->GetGUIDLow());
@@ -230,14 +237,14 @@ void MotionMaster::MoveChase(Unit* target, float dist, float angle)
if (!target || target == i_owner || i_owner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE))
return;
i_owner->ClearUnitState(UNIT_STAT_FOLLOW);
//i_owner->ClearUnitState(UNIT_STAT_FOLLOW);
if (i_owner->GetTypeId() == TYPEID_PLAYER)
{
sLog->outStaticDebug("Player (GUID: %u) chase to %s (GUID: %u)",
i_owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
Mutate(new TargetedMovementGenerator<Player>(*target, dist, angle), MOTION_SLOT_ACTIVE);
Mutate(new ChaseMovementGenerator<Player>(*target,dist,angle), MOTION_SLOT_ACTIVE);
}
else
{
@@ -245,7 +252,7 @@ void MotionMaster::MoveChase(Unit* target, float dist, float angle)
i_owner->GetEntry(), i_owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
Mutate(new TargetedMovementGenerator<Creature>(*target, dist, angle), MOTION_SLOT_ACTIVE);
Mutate(new ChaseMovementGenerator<Creature>(*target,dist,angle), MOTION_SLOT_ACTIVE);
}
}
@@ -255,13 +262,13 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlo
if (!target || target == i_owner || i_owner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE))
return;
i_owner->AddUnitState(UNIT_STAT_FOLLOW);
//i_owner->AddUnitState(UNIT_STAT_FOLLOW);
if (i_owner->GetTypeId() == TYPEID_PLAYER)
{
sLog->outStaticDebug("Player (GUID: %u) follow to %s (GUID: %u)", i_owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
Mutate(new TargetedMovementGenerator<Player>(*target, dist, angle), slot);
Mutate(new FollowMovementGenerator<Player>(*target,dist,angle), slot);
}
else
{
@@ -269,7 +276,7 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlo
i_owner->GetEntry(), i_owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
Mutate(new TargetedMovementGenerator<Creature>(*target, dist, angle), slot);
Mutate(new FollowMovementGenerator<Creature>(*target,dist,angle), slot);
}
}
@@ -290,54 +297,32 @@ void MotionMaster::MovePoint(uint32 id, float x, float y, float z)
void MotionMaster::MoveLand(uint32 id, Position const& pos, float speed)
{
if (i_owner->GetTypeId() != TYPEID_UNIT)
return;
uint32 moveFlag = SPLINEFLAG_FLYING | SPLINEFLAG_ANIMATIONTIER;
uint32 moveTime = uint32(i_owner->GetExactDist(&pos) / speed) * IN_MILLISECONDS;
// CHARGING state makes the unit use m_TempSpeed and JUMPING prevents sending movement packet in PointMovementGenerator
i_owner->AddUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING);
i_owner->m_TempSpeed = speed;
float x, y, z;
pos.GetPosition(x, y, z);
sLog->outStaticDebug("Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", i_owner->GetEntry(), id, x, y, z);
Mutate(new PointMovementGenerator<Creature>(id, x, y, z), MOTION_SLOT_ACTIVE);
MonsterMoveData data;
data.DestLocation.Relocate(pos);
data.SplineFlag = moveFlag;
data.Time = moveTime;
data.AnimationState = ANIMATION_ON_GROUND;
i_owner->SendMonsterMove(data);
Movement::MoveSplineInit init(*i_owner);
init.MoveTo(x,y,z);
init.SetVelocity(speed);
init.SetAnimation(Movement::ToGround);
init.Launch();
Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED);
}
void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, float speed)
{
if (i_owner->GetTypeId() != TYPEID_UNIT)
return;
uint32 moveFlag = SPLINEFLAG_FLYING | SPLINEFLAG_ANIMATIONTIER;
uint32 moveTime = uint32(i_owner->GetExactDist(&pos) / speed) * IN_MILLISECONDS;
// CHARGING state makes the unit use m_TempSpeed and JUMPING prevents sending movement packet in PointMovementGenerator
i_owner->AddUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING);
i_owner->m_TempSpeed = speed;
float x, y, z;
pos.GetPosition(x, y, z);
sLog->outStaticDebug("Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", i_owner->GetEntry(), id, x, y, z);
Mutate(new PointMovementGenerator<Creature>(id, x, y, z), MOTION_SLOT_ACTIVE);
MonsterMoveData data;
data.DestLocation.Relocate(pos);
data.SplineFlag = moveFlag;
data.Time = moveTime;
data.AnimationState = ANIMATION_FLYING;
i_owner->SendMonsterMove(data);
Movement::MoveSplineInit init(*i_owner);
init.MoveTo(x,y,z);
init.SetVelocity(speed);
init.SetAnimation(Movement::ToFly);
init.Launch();
Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED);
}
void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ)
@@ -347,7 +332,9 @@ void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, floa
return;
float x, y, z;
float dist = speedXY * speedZ * 0.1f;
float moveTimeHalf = speedZ / Movement::gravity;
float dist = 2 * moveTimeHalf * speedXY;
i_owner->GetNearPoint(i_owner, x, y, z, i_owner->GetObjectSize(), dist, i_owner->GetAngle(srcX, srcY) + M_PI);
MoveJump(x, y, z, speedXY, speedZ);
}
@@ -359,35 +346,48 @@ void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ)
return;
float x, y, z;
float dist = speedXY * speedZ * 0.1f;
float moveTimeHalf = speedZ / Movement::gravity;
float dist = 2 * moveTimeHalf * speedXY;
i_owner->GetClosePoint(x, y, z, i_owner->GetObjectSize(), dist, angle);
MoveJump(x, y, z, speedXY, speedZ);
}
void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float speedZ)
void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id)
{
uint32 moveFlag = SPLINEFLAG_TRAJECTORY | SPLINEFLAG_WALKING;
uint32 time = uint32(speedZ * 100);
sLog->outStaticDebug("Unit (GUID: %u) jump to point (X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), x, y, z);
// Instantly interrupt non melee spells being casted
if (i_owner->IsNonMeleeSpellCasted(true))
i_owner->InterruptNonMeleeSpells(true);
float moveTimeHalf = speedZ / Movement::gravity;
float max_height = -Movement::computeFallElevation(moveTimeHalf,false,-speedZ);
i_owner->AddUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING);
i_owner->m_TempSpeed = speedXY;
if (i_owner->GetTypeId() == TYPEID_PLAYER)
Movement::MoveSplineInit init(*i_owner);
init.MoveTo(x,y,z);
init.SetParabolic(max_height,0);
init.SetVelocity(speedXY);
init.Launch();
Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED);
}
void MotionMaster::MoveFall()
{
// use larger distance for vmap height search than in most other cases
float tz = i_owner->GetMap()->GetHeight(i_owner->GetPositionX(), i_owner->GetPositionY(), i_owner->GetPositionZ(), true, MAX_FALL_DISTANCE);
if (tz <= INVALID_HEIGHT)
{
sLog->outStaticDebug("Player (GUID: %u) jump to point (X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), x, y, z);
Mutate(new PointMovementGenerator<Player>(0, x, y, z), MOTION_SLOT_CONTROLLED);
}
else
{
sLog->outStaticDebug("Creature (Entry: %u GUID: %u) jump to point (X: %f Y: %f Z: %f)",
i_owner->GetEntry(), i_owner->GetGUIDLow(), x, y, z);
Mutate(new PointMovementGenerator<Creature>(0, x, y, z), MOTION_SLOT_CONTROLLED);
sLog->outStaticDebug("MotionMaster::MoveFall: unable retrive a proper height at map %u (x: %f, y: %f, z: %f).",
i_owner->GetMap()->GetId(), i_owner->GetPositionX(), i_owner->GetPositionX(), i_owner->GetPositionZ());
return;
}
i_owner->SendMonsterMove(x, y, z, moveFlag, time, speedZ);
// Abort too if the ground is very near
if (fabs(i_owner->GetPositionZ() - tz) < 0.1f)
return;
Movement::MoveSplineInit init(*i_owner);
init.MoveTo(i_owner->GetPositionX(),i_owner->GetPositionY(),tz);
init.SetFall();
init.Launch();
Mutate(new EffectMovementGenerator(0), MOTION_SLOT_CONTROLLED);
}
void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id)
@@ -395,29 +395,19 @@ void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id)
if (Impl[MOTION_SLOT_CONTROLLED] && Impl[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE)
return;
i_owner->AddUnitState(UNIT_STAT_CHARGING);
i_owner->m_TempSpeed = speed;
if (i_owner->GetTypeId() == TYPEID_PLAYER)
{
sLog->outStaticDebug("Player (GUID: %u) charge point (X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), x, y, z);
Mutate(new PointMovementGenerator<Player>(id, x, y, z), MOTION_SLOT_CONTROLLED);
Mutate(new PointMovementGenerator<Player>(id, x, y, z, speed), MOTION_SLOT_CONTROLLED);
}
else
{
sLog->outStaticDebug("Creature (Entry: %u GUID: %u) charge point (X: %f Y: %f Z: %f)",
i_owner->GetEntry(), i_owner->GetGUIDLow(), x, y, z);
Mutate(new PointMovementGenerator<Creature>(id, x, y, z), MOTION_SLOT_CONTROLLED);
Mutate(new PointMovementGenerator<Creature>(id, x, y, z, speed), MOTION_SLOT_CONTROLLED);
}
}
void MotionMaster::MoveFall(float z, uint32 id)
{
i_owner->SetFlying(false);
i_owner->SendMovementFlagUpdate();
//AddUnitMovementFlag(MOVEMENTFLAG_FALLING);
MoveCharge(i_owner->GetPositionX(), i_owner->GetPositionY(), z, SPEED_CHARGE, id);
}
void MotionMaster::MoveSeekAssistance(float x, float y, float z)
{
if (i_owner->GetTypeId() == TYPEID_PLAYER)
@@ -561,7 +551,7 @@ void MotionMaster::MovePath(uint32 path_id, bool repeatable)
//i_owner->GetTypeId() == TYPEID_PLAYER ?
//Mutate(new WaypointMovementGenerator<Player>(path_id, repeatable)):
Mutate(new WaypointMovementGenerator<Creature>(path_id, repeatable), MOTION_SLOT_IDLE);
Mutate(new WaypointMovementGenerator<Creature>(path_id, repeatable), MOTION_SLOT_IDLE);
sLog->outStaticDebug("%s (GUID: %u) start moving over path(Id:%u, repeatable: %s)",
i_owner->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature",
@@ -632,8 +622,12 @@ void MotionMaster::DelayedDelete(_Ty curr)
bool MotionMaster::GetDestination(float &x, float &y, float &z)
{
if (empty())
if (i_owner->movespline->Finalized())
return false;
return top()->GetDestination(x, y, z);
const G3D::Vector3& dest = i_owner->movespline->FinalDestination();
x = dest.x;
y = dest.y;
z = dest.z;
return true;
}
+9 -6
View File
@@ -39,7 +39,7 @@ enum MovementGeneratorType
MAX_DB_MOTION_TYPE = 3, // *** this and below motion types can't be set in DB.
ANIMAL_RANDOM_MOTION_TYPE = MAX_DB_MOTION_TYPE, // AnimalRandomMovementGenerator.h
CONFUSED_MOTION_TYPE = 4, // ConfusedMovementGenerator.h
TARGETED_MOTION_TYPE = 5, // TargetedMovementGenerator.h
CHASE_MOTION_TYPE = 5, // TargetedMovementGenerator.h
HOME_MOTION_TYPE = 6, // HomeMovementGenerator.h
FLIGHT_MOTION_TYPE = 7, // WaypointMovementGenerator.h
POINT_MOTION_TYPE = 8, // PointMovementGenerator.h
@@ -48,8 +48,10 @@ enum MovementGeneratorType
ASSISTANCE_MOTION_TYPE= 11, // PointMovementGenerator.h (first part of flee for assistance)
ASSISTANCE_DISTRACT_MOTION_TYPE = 12, // IdleMovementGenerator.h (second part of flee for assistance)
TIMED_FLEEING_MOTION_TYPE = 13, // FleeingMovementGenerator.h (alt.second part of flee for assistance)
ROTATE_MOTION_TYPE = 14,
NULL_MOTION_TYPE = 15,
FOLLOW_MOTION_TYPE = 14,
ROTATE_MOTION_TYPE = 15,
EFFECT_MOTION_TYPE = 16,
NULL_MOTION_TYPE = 17,
};
enum MovementSlot
@@ -86,7 +88,6 @@ class MotionMaster //: private std::stack<MovementGenerator *>
typedef std::vector<_Ty> ExpireList;
int i_top;
bool empty() const { return (i_top < 0); }
void pop() { Impl[i_top] = NULL; --i_top; }
void push(_Ty _Val) { ++i_top; Impl[i_top] = _Val; }
@@ -107,6 +108,7 @@ class MotionMaster //: private std::stack<MovementGenerator *>
void Initialize();
void InitDefault();
bool empty() const { return (i_top < 0); }
int size() const { return i_top + 1; }
_Ty top() const { return Impl[i_top]; }
_Ty GetMotionSlot(int slot) const { return Impl[slot]; }
@@ -158,10 +160,11 @@ class MotionMaster //: private std::stack<MovementGenerator *>
void MoveTakeoff(uint32 id, Position const& pos, float speed);
void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE);
void MoveFall(float z, uint32 id = 0);
void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ);
void MoveJumpTo(float angle, float speedXY, float speedZ);
void MoveJump(float x, float y, float z, float speedXY, float speedZ);
void MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id = 0);
void MoveFall();
void MoveSeekAssistance(float x, float y, float z);
void MoveSeekAssistanceDistract(uint32 timer);
void MoveTaxiFlight(uint32 path, uint32 pathnode);
@@ -21,4 +21,3 @@
MovementGenerator::~MovementGenerator()
{
}
@@ -43,8 +43,6 @@ class MovementGenerator
virtual MovementGeneratorType GetMovementGeneratorType() = 0;
virtual void unitSpeedChanged() { }
virtual bool GetDestination(float& /*x*/, float& /*y*/, float& /*z*/) const { return false; }
};
template<class T, class D>
@@ -18,10 +18,10 @@
#include "Creature.h"
#include "MapManager.h"
#include "Opcodes.h"
#include "ConfusedMovementGenerator.h"
#include "DestinationHolderImp.h"
#include "VMapFactory.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#ifdef MAP_BASED_RAND_GEN
#define rand_norm() unit.rand_norm()
@@ -31,8 +31,8 @@
template<class T>
void ConfusedMovementGenerator<T>::Initialize(T &unit)
{
float const wanderDistance = 4;
float x, y, z;
const float wander_distance=4;
float x,y,z;
x = unit.GetPositionX();
y = unit.GetPositionY();
z = unit.GetPositionZ();
@@ -44,52 +44,33 @@ void ConfusedMovementGenerator<T>::Initialize(T &unit)
bool is_water_ok, is_land_ok;
_InitSpecific(unit, is_water_ok, is_land_ok);
for (uint8 idx = 0; idx <= MAX_CONF_WAYPOINTS; ++idx)
for (uint8 idx = 0; idx < MAX_CONF_WAYPOINTS + 1; ++idx)
{
float wanderX = x + wanderDistance * (float)rand_norm() - wanderDistance/2;
float wanderY = y + wanderDistance * (float)rand_norm() - wanderDistance/2;
Trinity::NormalizeMapCoord(wanderX);
Trinity::NormalizeMapCoord(wanderY);
const float wanderX=wander_distance*(float)rand_norm() - wander_distance/2;
const float wanderY=wander_distance*(float)rand_norm() - wander_distance/2;
float new_z = map->GetHeight(wanderX, wanderY, z, true);
if (new_z > INVALID_HEIGHT && unit.IsWithinLOS(wanderX, wanderY, new_z))
{
// Don't move in water if we're not already in
// Don't move on land if we're not already on it either
bool is_water_now = map->IsInWater(x, y, z);
bool is_water_next = map->IsInWater(wanderX, wanderY, new_z);
if ((is_water_now && !is_water_next && !is_land_ok) || (!is_water_now && is_water_next && !is_water_ok))
{
i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x; // Back to previous location
i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y;
i_waypoints[idx][2] = idx > 0 ? i_waypoints[idx-1][2] : z;
continue;
}
i_waypoints[idx][0] = x + wanderX;
i_waypoints[idx][1] = y + wanderY;
// Taken from FleeingMovementGenerator
if (!(new_z - z) || wanderDistance / fabs(new_z - z) > 1.0f)
{
i_waypoints[idx][0] = wanderX;
i_waypoints[idx][1] = wanderY;
i_waypoints[idx][2] = new_z;
continue;
}
}
else // Back to previous location
// prevent invalid coordinates generation
Trinity::NormalizeMapCoord(i_waypoints[idx][0]);
Trinity::NormalizeMapCoord(i_waypoints[idx][1]);
bool is_water = map->IsInWater(i_waypoints[idx][0],i_waypoints[idx][1],z);
// if generated wrong path just ignore
if ((is_water && !is_water_ok) || (!is_water && !is_land_ok))
{
i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x;
i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y;
i_waypoints[idx][2] = idx > 0 ? i_waypoints[idx-1][2] : z;
continue;
}
unit.UpdateAllowedPositionZ(i_waypoints[idx][0], i_waypoints[idx][1], z);
i_waypoints[idx][2] = z;
}
unit.SetTarget(0);
unit.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
unit.CastStop();
unit.StopMoving();
unit.AddUnitMovementFlag(MOVEMENTFLAG_WALKING); // Should actually be splineflag
unit.AddUnitState(UNIT_STAT_CONFUSED);
unit.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
unit.AddUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
}
template<>
@@ -111,69 +92,70 @@ void ConfusedMovementGenerator<T>::Reset(T &unit)
{
i_nextMove = 1;
i_nextMoveTime.Reset(0);
i_destinationHolder.ResetUpdate();
unit.StopMoving();
unit.AddUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
}
template<class T>
bool ConfusedMovementGenerator<T>::Update(T &unit, const uint32 diff)
bool ConfusedMovementGenerator<T>::Update(T &unit, const uint32 &diff)
{
if (!&unit)
return true;
if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
return true;
if (i_nextMoveTime.Passed())
{
// currently moving, update location
Traveller<T> traveller(unit);
if (i_destinationHolder.UpdateTraveller(traveller, diff))
{
if (i_destinationHolder.HasArrived())
{
// arrived, stop and wait a bit
unit.ClearUnitState(UNIT_STAT_MOVE);
unit.AddUnitState(UNIT_STAT_CONFUSED_MOVE);
i_nextMove = urand(1, MAX_CONF_WAYPOINTS);
i_nextMoveTime.Reset(urand(100, 1000));
}
if (unit.movespline->Finalized())
{
i_nextMove = urand(1,MAX_CONF_WAYPOINTS);
i_nextMoveTime.Reset(urand(0, 1500-1)); // TODO: check the minimum reset time, should be probably higher
}
}
else
{
// waiting for next move
i_nextMoveTime.Update(diff);
if (i_nextMoveTime.Passed())
if(i_nextMoveTime.Passed() )
{
// start moving
ASSERT(i_nextMove <= MAX_CONF_WAYPOINTS);
const float x = i_waypoints[i_nextMove][0];
const float y = i_waypoints[i_nextMove][1];
const float z = i_waypoints[i_nextMove][2];
Traveller<T> traveller(unit);
i_destinationHolder.SetDestination(traveller, x, y, z);
unit.AddUnitState(UNIT_STAT_CONFUSED_MOVE);
ASSERT( i_nextMove <= MAX_CONF_WAYPOINTS );
float x = i_waypoints[i_nextMove][0];
float y = i_waypoints[i_nextMove][1];
float z = i_waypoints[i_nextMove][2];
Movement::MoveSplineInit init(unit);
init.MoveTo(x, y, z);
init.SetWalk(true);
init.Launch();
}
}
return true;
}
template<class T>
void ConfusedMovementGenerator<T>::Finalize(T &unit)
template<>
void ConfusedMovementGenerator<Player>::Finalize(Player &unit)
{
unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
unit.ClearUnitState(UNIT_STAT_CONFUSED);
unit.ClearUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
}
if (unit.GetTypeId() == TYPEID_UNIT && unit.getVictim())
template<>
void ConfusedMovementGenerator<Creature>::Finalize(Creature &unit)
{
unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
unit.ClearUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
if (unit.getVictim())
unit.SetTarget(unit.getVictim()->GetGUID());
}
template void ConfusedMovementGenerator<Player>::Initialize(Player &player);
template void ConfusedMovementGenerator<Creature>::Initialize(Creature &creature);
template void ConfusedMovementGenerator<Player>::Finalize(Player &player);
template void ConfusedMovementGenerator<Creature>::Finalize(Creature &creature);
template void ConfusedMovementGenerator<Player>::Reset(Player &player);
template void ConfusedMovementGenerator<Creature>::Reset(Creature &creature);
template bool ConfusedMovementGenerator<Player>::Update(Player &player, const uint32 diff);
template bool ConfusedMovementGenerator<Creature>::Update(Creature &creature, const uint32 diff);
template bool ConfusedMovementGenerator<Player>::Update(Player &player, const uint32 &diff);
template bool ConfusedMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff);
@@ -20,8 +20,7 @@
#define TRINITY_CONFUSEDGENERATOR_H
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "Traveller.h"
#include "Timer.h"
#define MAX_CONF_WAYPOINTS 24
@@ -35,21 +34,13 @@ class ConfusedMovementGenerator
void Initialize(T &);
void Finalize(T &);
void Reset(T &);
bool Update(T &, const uint32);
bool GetDestination(float &x, float &y, float &z) const
{
if (i_destinationHolder.HasArrived()) return false;
i_destinationHolder.GetDestination(x, y, z);
return true;
}
bool Update(T &, const uint32 &);
MovementGeneratorType GetMovementGeneratorType() { return CONFUSED_MOTION_TYPE; }
private:
void _InitSpecific(T &, bool &, bool &);
TimeTracker i_nextMoveTime;
float i_waypoints[MAX_CONF_WAYPOINTS+1][3];
DestinationHolder< Traveller<T> > i_destinationHolder;
uint32 i_nextMove;
};
#endif
@@ -20,8 +20,9 @@
#include "CreatureAI.h"
#include "MapManager.h"
#include "FleeingMovementGenerator.h"
#include "DestinationHolderImp.h"
#include "ObjectAccessor.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#define MIN_QUIET_DISTANCE 28.0f
#define MAX_QUIET_DISTANCE 43.0f
@@ -43,25 +44,12 @@ FleeingMovementGenerator<T>::_setTargetLocation(T &owner)
if (!_getPoint(owner, x, y, z))
return;
owner.AddUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING);
Traveller<T> traveller(owner);
i_destinationHolder.SetDestination(traveller, x, y, z);
}
owner.AddUnitState(UNIT_STAT_FLEEING_MOVE);
template<>
bool FleeingMovementGenerator<Creature>::GetDestination(float &x, float &y, float &z) const
{
if (i_destinationHolder.HasArrived())
return false;
i_destinationHolder.GetDestination(x, y, z);
return true;
}
template<>
bool FleeingMovementGenerator<Player>::GetDestination(float & /*x*/, float & /*y*/, float & /*z*/) const
{
return false;
Movement::MoveSplineInit init(owner);
init.MoveTo(x,y,z);
init.SetWalk(false);
init.Launch();
}
template<class T>
@@ -75,10 +63,10 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
y = owner.GetPositionY();
z = owner.GetPositionZ();
float temp_x, temp_y, angle = 0;
float temp_x, temp_y, angle;
const Map* _map = owner.GetBaseMap();
//primitive path-finding
for (uint8 i = 0; i < 18; ++i)
for(uint8 i = 0; i < 18; ++i)
{
if (i_only_forward && i > 2)
break;
@@ -143,11 +131,11 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
distance /= 4;
break;
case 15:
angle = i_cur_angle + static_cast<float>(M_PI*3/4);
angle = i_cur_angle + static_cast<float>(3*M_PI/4);
distance /= 2;
break;
case 16:
angle = i_cur_angle - static_cast<float>(M_PI*3/4);
angle = i_cur_angle - static_cast<float>(3*M_PI/4);
distance /= 2;
break;
case 17:
@@ -161,9 +149,9 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
Trinity::NormalizeMapCoord(temp_y);
if (owner.IsWithinLOS(temp_x, temp_y, z))
{
bool is_water_now = _map->IsInWater(x, y, z);
bool is_water_now = _map->IsInWater(x,y,z);
if (is_water_now && _map->IsInWater(temp_x, temp_y, z))
if (is_water_now && _map->IsInWater(temp_x,temp_y,z))
{
x = temp_x;
y = temp_y;
@@ -181,8 +169,8 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
if (!(new_z - z) || distance / fabs(new_z - z) > 1.0f)
{
float new_z_left = _map->GetHeight(temp_x + (float)(cos(angle+M_PI/2)), temp_y + (float)(sin(angle+M_PI/2)), z, true);
float new_z_right = _map->GetHeight(temp_x + (float)(cos(angle-M_PI/2)), temp_y + (float)(sin(angle-M_PI/2)), z, true);
float new_z_left = _map->GetHeight(temp_x + 1.0f*cos(angle+static_cast<float>(M_PI/2)),temp_y + 1.0f*sin(angle+static_cast<float>(M_PI/2)),z,true);
float new_z_right = _map->GetHeight(temp_x + 1.0f*cos(angle-static_cast<float>(M_PI/2)),temp_y + 1.0f*sin(angle-static_cast<float>(M_PI/2)),z,true);
if (fabs(new_z_left - new_z) < 1.2f && fabs(new_z_right - new_z) < 1.2f)
{
x = temp_x;
@@ -194,7 +182,7 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
}
}
i_to_distance_from_caster = 0.0f;
i_nextCheckTime.Reset(urand(500, 1000));
i_nextCheckTime.Reset( urand(500,1000) );
return false;
}
@@ -213,12 +201,12 @@ FleeingMovementGenerator<T>::_setMoveData(T &owner)
(i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster) ||
// if we reach bigger distance
(cur_dist_xyz > MAX_QUIET_DISTANCE) || // if we are too far
(i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE))
(i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE) )
// if we leave 'quiet zone'
{
// we are very far or too close, stopping
i_to_distance_from_caster = 0.0f;
i_nextCheckTime.Reset(urand(500, 1000));
i_nextCheckTime.Reset( urand(500,1000) );
return false;
}
else
@@ -232,9 +220,7 @@ FleeingMovementGenerator<T>::_setMoveData(T &owner)
float cur_dist;
float angle_to_caster;
Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID);
if (fright)
if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
{
cur_dist = fright->GetDistance(&owner);
if (cur_dist < cur_dist_xyz)
@@ -284,7 +270,7 @@ FleeingMovementGenerator<T>::_setMoveData(T &owner)
i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + (float)rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
}
int8 sign = rand_norm() > 0.5f ? 1 : -1;
int8 sign = (float)rand_norm() > 0.5f ? 1 : -1;
i_cur_angle = sign*angle + angle_to_caster;
// current distance
@@ -300,14 +286,12 @@ FleeingMovementGenerator<T>::Initialize(T &owner)
if (!&owner)
return;
_Init(owner);
owner.CastStop();
owner.AddUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING);
owner.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
owner.SetTarget(0);
owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
owner.AddUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
_Init(owner);
if (Unit *fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
{
i_caster_x = fright->GetPositionX();
i_caster_y = fright->GetPositionY();
@@ -334,6 +318,7 @@ FleeingMovementGenerator<Creature>::_Init(Creature &owner)
if (!&owner)
return;
//owner.SetTargetGuid(ObjectGuid());
is_water_ok = owner.canSwim();
is_land_ok = owner.canWalk();
}
@@ -346,51 +331,44 @@ FleeingMovementGenerator<Player>::_Init(Player &)
is_land_ok = true;
}
template<class T>
void
FleeingMovementGenerator<T>::Finalize(T &owner)
template<>
void FleeingMovementGenerator<Player>::Finalize(Player &owner)
{
owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
owner.ClearUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING);
if (owner.GetTypeId() == TYPEID_UNIT && owner.getVictim())
owner.ClearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
}
template<>
void FleeingMovementGenerator<Creature>::Finalize(Creature &owner)
{
owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
owner.ClearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
if (owner.getVictim())
owner.SetTarget(owner.getVictim()->GetGUID());
}
template<class T>
void
FleeingMovementGenerator<T>::Reset(T &owner)
void FleeingMovementGenerator<T>::Reset(T &owner)
{
Initialize(owner);
}
template<class T>
bool
FleeingMovementGenerator<T>::Update(T &owner, const uint32 time_diff)
FleeingMovementGenerator<T>::Update(T &owner, const uint32 &time_diff)
{
if (!&owner || !owner.isAlive())
return false;
if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED))
{
owner.ClearUnitState(UNIT_STAT_FLEEING_MOVE);
return true;
Traveller<T> traveller(owner);
}
i_nextCheckTime.Update(time_diff);
if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || !i_destinationHolder.HasDestination())
{
if (i_nextCheckTime.Passed() && owner.movespline->Finalized())
_setTargetLocation(owner);
return true;
}
if (i_destinationHolder.UpdateTraveller(traveller, time_diff))
{
i_destinationHolder.ResetUpdate(50);
if (i_nextCheckTime.Passed() && i_destinationHolder.HasArrived())
{
_setTargetLocation(owner);
return true;
}
}
return true;
}
@@ -402,17 +380,15 @@ template bool FleeingMovementGenerator<Player>::_getPoint(Player &, float &, flo
template bool FleeingMovementGenerator<Creature>::_getPoint(Creature &, float &, float &, float &);
template void FleeingMovementGenerator<Player>::_setTargetLocation(Player &);
template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature &);
template void FleeingMovementGenerator<Player>::Finalize(Player &);
template void FleeingMovementGenerator<Creature>::Finalize(Creature &);
template void FleeingMovementGenerator<Player>::Reset(Player &);
template void FleeingMovementGenerator<Creature>::Reset(Creature &);
template bool FleeingMovementGenerator<Player>::Update(Player &, const uint32);
template bool FleeingMovementGenerator<Creature>::Update(Creature &, const uint32);
template bool FleeingMovementGenerator<Player>::Update(Player &, const uint32 &);
template bool FleeingMovementGenerator<Creature>::Update(Creature &, const uint32 &);
void TimedFleeingMovementGenerator::Finalize(Unit &owner)
{
owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
owner.ClearUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING);
owner.ClearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
if (Unit* victim = owner.getVictim())
{
if (owner.isAlive())
@@ -429,13 +405,20 @@ bool TimedFleeingMovementGenerator::Update(Unit & owner, const uint32 time_diff)
return false;
if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED))
{
owner.ClearUnitState(UNIT_STAT_FLEEING_MOVE);
return true;
}
i_totalFleeTime.Update(time_diff);
if (i_totalFleeTime.Passed())
return false;
// This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, const uint32) version
i_totalFleeTime.Update(time_diff);
if (i_totalFleeTime.Passed())
return false;
// This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, const uint32 &) version
// This is done instead of casting Unit& to Creature& and call parent method, then we can use Unit directly
return MovementGeneratorMedium< Creature, FleeingMovementGenerator<Creature> >::Update(owner, time_diff);
}
@@ -20,8 +20,6 @@
#define TRINITY_FLEEINGMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "Traveller.h"
template<class T>
class FleeingMovementGenerator
@@ -33,8 +31,7 @@ class FleeingMovementGenerator
void Initialize(T &);
void Finalize(T &);
void Reset(T &);
bool Update(T &, const uint32);
bool GetDestination(float &x, float &y, float &z) const;
bool Update(T &, const uint32 &);
MovementGeneratorType GetMovementGeneratorType() { return FLEEING_MOTION_TYPE; }
@@ -56,8 +53,6 @@ class FleeingMovementGenerator
float i_cur_angle;
uint64 i_frightGUID;
TimeTracker i_nextCheckTime;
DestinationHolder< Traveller<T> > i_destinationHolder;
};
class TimedFleeingMovementGenerator
@@ -19,22 +19,16 @@
#include "HomeMovementGenerator.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "Traveller.h"
#include "DestinationHolderImp.h"
#include "WorldPacket.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
void HomeMovementGenerator<Creature>::Initialize(Creature & owner)
{
owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
owner.AddUnitState(UNIT_STAT_EVADE);
_setTargetLocation(owner);
}
void HomeMovementGenerator<Creature>::Finalize(Creature & owner)
{
owner.ClearUnitState(UNIT_STAT_EVADE);
}
void HomeMovementGenerator<Creature>::Reset(Creature &)
{
}
@@ -47,42 +41,35 @@ void HomeMovementGenerator<Creature>::_setTargetLocation(Creature & owner)
if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
return;
float x, y, z;
owner.GetHomePosition(x, y, z, ori);
Movement::MoveSplineInit init(owner);
float x, y, z, o;
// at apply we can select more nice return points base at current movegen
//if (owner.GetMotionMaster()->empty() || !owner.GetMotionMaster()->top()->GetResetPosition(owner,x,y,z))
//{
owner.GetHomePosition(x, y, z, o);
init.SetFacing(o);
//}
init.MoveTo(x,y,z);
init.SetWalk(false);
init.Launch();
CreatureTraveller traveller(owner);
uint32 travel_time = i_destinationHolder.SetDestination(traveller, x, y, z);
modifyTravelTime(travel_time);
owner.ClearUnitState(uint32(UNIT_STAT_ALL_STATE & ~UNIT_STAT_EVADE));
arrived = false;
owner.ClearUnitState(UNIT_STAT_ALL_STATE & ~UNIT_STAT_EVADE);
}
bool HomeMovementGenerator<Creature>::Update(Creature &owner, const uint32 time_diff)
{
CreatureTraveller traveller(owner);
i_destinationHolder.UpdateTraveller(traveller, time_diff);
arrived = owner.movespline->Finalized();
return !arrived;
}
if (time_diff > i_travel_timer)
void HomeMovementGenerator<Creature>::Finalize(Creature& owner)
{
if (arrived)
{
owner.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
// restore orientation of not moving creature at returning to home
if (owner.GetDefaultMovementType() == IDLE_MOTION_TYPE)
{
//sLog->outDebug("Entering HomeMovement::GetDestination(z, y, z)");
owner.SetOrientation(ori);
WorldPacket packet;
owner.BuildHeartBeatMsg(&packet);
owner.SendMessageToSet(&packet, false);
}
owner.ClearUnitState(UNIT_STAT_EVADE);
owner.SetWalk(true);
owner.LoadCreaturesAddon(true);
owner.AI()->JustReachedHome();
return false;
}
i_travel_timer -= time_diff;
return true;
}
@@ -20,8 +20,6 @@
#define TRINITY_HOMEMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "Traveller.h"
class Creature;
@@ -34,24 +32,18 @@ class HomeMovementGenerator<Creature>
{
public:
HomeMovementGenerator() {}
HomeMovementGenerator() : arrived(false) {}
~HomeMovementGenerator() {}
void Initialize(Creature &);
void Finalize(Creature &);
void Reset(Creature &);
bool Update(Creature &, const uint32);
void modifyTravelTime(uint32 travel_time) { i_travel_timer = travel_time; }
MovementGeneratorType GetMovementGeneratorType() { return HOME_MOTION_TYPE; }
bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x, y, z); return true; }
private:
void _setTargetLocation(Creature &);
DestinationHolder< Traveller<Creature> > i_destinationHolder;
float ori;
uint32 i_travel_timer;
bool arrived;
};
#endif
@@ -20,61 +20,59 @@
#include "Errors.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "DestinationHolderImp.h"
#include "World.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
//----- Point Movement Generator
template<class T>
void PointMovementGenerator<T>::Initialize(T &unit)
{
unit.StopMoving();
Traveller<T> traveller(unit);
// OLD: knockback effect has UNIT_STAT_JUMPING set, so if here we disable sentmonstermove there will be creature position sync problem between client and server
// NEW: reactivated this check - UNIT_STAT_JUMPING is only used in MoveJump, which sends its own packet
i_destinationHolder.SetDestination(traveller, i_x, i_y, i_z, /*true*/ !unit.HasUnitState(UNIT_STAT_JUMPING));
if (!unit.IsStopped())
unit.StopMoving();
unit.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
Movement::MoveSplineInit init(unit);
init.MoveTo(i_x, i_y, i_z);
if (speed > 0.0f)
init.SetVelocity(speed);
init.Launch();
}
template<class T>
bool PointMovementGenerator<T>::Update(T &unit, const uint32 diff)
bool PointMovementGenerator<T>::Update(T &unit, const uint32 &diff)
{
if (!&unit)
return false;
if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED))
if(unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED))
{
if (unit.HasUnitState(UNIT_STAT_CHARGING))
return false;
else
return true;
unit.ClearUnitState(UNIT_STAT_ROAMING_MOVE);
return true;
}
Traveller<T> traveller(unit);
i_destinationHolder.UpdateTraveller(traveller, diff);
if (i_destinationHolder.HasArrived())
{
unit.ClearUnitState(UNIT_STAT_MOVE);
arrived = true;
return false;
}
else if (!unit.HasUnitState(UNIT_STAT_MOVE) && !unit.HasUnitState(UNIT_STAT_JUMPING))
{
i_destinationHolder.StartTravel(traveller);
}
return true;
unit.AddUnitState(UNIT_STAT_ROAMING_MOVE);
return !unit.movespline->Finalized();
}
template<class T>
void PointMovementGenerator<T>:: Finalize(T &unit)
{
if (unit.HasUnitState(UNIT_STAT_CHARGING))
unit.ClearUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING);
if (arrived) // without this crash!
unit.ClearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
if (unit.movespline->Finalized())
MovementInform(unit);
}
template<class T>
void PointMovementGenerator<T>::Reset(T &unit)
{
if (!unit.IsStopped())
unit.StopMoving();
unit.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
}
template<class T>
void PointMovementGenerator<T>::MovementInform(T & /*unit*/)
{
@@ -82,22 +80,23 @@ void PointMovementGenerator<T>::MovementInform(T & /*unit*/)
template <> void PointMovementGenerator<Creature>::MovementInform(Creature &unit)
{
if (id == EVENT_FALL_GROUND)
{
unit.setDeathState(JUST_DIED);
unit.SetFlying(true);
}
unit.AI()->MovementInform(POINT_MOTION_TYPE, id);
//if (id == EVENT_FALL_GROUND)
//{
// unit.setDeathState(JUST_DIED);
// unit.SetFlying(true);
//}
if (unit.AI())
unit.AI()->MovementInform(POINT_MOTION_TYPE, id);
}
template void PointMovementGenerator<Player>::Initialize(Player&);
template bool PointMovementGenerator<Player>::Update(Player &, const uint32 diff);
template void PointMovementGenerator<Player>::MovementInform(Player&);
template void PointMovementGenerator<Player>::Finalize(Player&);
template void PointMovementGenerator<Creature>::Initialize(Creature&);
template bool PointMovementGenerator<Creature>::Update(Creature&, const uint32 diff);
template void PointMovementGenerator<Player>::Finalize(Player&);
template void PointMovementGenerator<Creature>::Finalize(Creature&);
template void PointMovementGenerator<Player>::Reset(Player&);
template void PointMovementGenerator<Creature>::Reset(Creature&);
template bool PointMovementGenerator<Player>::Update(Player &, const uint32 &);
template bool PointMovementGenerator<Creature>::Update(Creature&, const uint32 &);
void AssistanceMovementGenerator::Finalize(Unit &unit)
{
@@ -107,3 +106,24 @@ void AssistanceMovementGenerator::Finalize(Unit &unit)
unit.GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY));
}
bool EffectMovementGenerator::Update(Unit &unit, const uint32)
{
return !unit.movespline->Finalized();
}
void EffectMovementGenerator::Finalize(Unit &unit)
{
if (unit.GetTypeId() != TYPEID_UNIT)
return;
if (((Creature&)unit).AI() && unit.movespline->Finalized())
((Creature&)unit).AI()->MovementInform(EFFECT_MOTION_TYPE, m_Id);
// Need restore previous movement since we have no proper states system
//if (unit.isAlive() && !unit.HasUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_FLEEING))
//{
// if (Unit * victim = unit.getVictim())
// unit.GetMotionMaster()->MoveChase(victim);
// else
// unit.GetMotionMaster()->Initialize();
//}
}
@@ -20,8 +20,6 @@
#define TRINITY_POINTMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "Traveller.h"
#include "FollowerReference.h"
template<class T>
@@ -29,13 +27,13 @@ class PointMovementGenerator
: public MovementGeneratorMedium< T, PointMovementGenerator<T> >
{
public:
PointMovementGenerator(uint32 _id, float _x, float _y, float _z) : id(_id),
i_x(_x), i_y(_y), i_z(_z), i_nextMoveTime(0), arrived(false) {}
PointMovementGenerator(uint32 _id, float _x, float _y, float _z, float _speed = 0.0f) : id(_id),
i_x(_x), i_y(_y), i_z(_z), speed(_speed) {}
void Initialize(T &);
void Finalize(T &unit);
void Reset(T &unit){unit.StopMoving();}
bool Update(T &, const uint32 diff);
void Finalize(T &);
void Reset(T &);
bool Update(T &, const uint32 &);
void MovementInform(T &);
@@ -45,9 +43,7 @@ class PointMovementGenerator
private:
uint32 id;
float i_x, i_y, i_z;
TimeTracker i_nextMoveTime;
DestinationHolder< Traveller<T> > i_destinationHolder;
bool arrived;
float speed;
};
class AssistanceMovementGenerator
@@ -61,5 +57,19 @@ class AssistanceMovementGenerator
void Finalize(Unit &);
};
// Does almost nothing - just doesn't allows previous movegen interrupt current effect.
class EffectMovementGenerator : public MovementGenerator
{
public:
explicit EffectMovementGenerator(uint32 Id) : m_Id(Id) {}
void Initialize(Unit &) {}
void Finalize(Unit &unit);
void Reset(Unit &) {}
bool Update(Unit &u, const uint32);
MovementGeneratorType GetMovementGeneratorType() { return EFFECT_MOTION_TYPE; }
private:
uint32 m_Id;
};
#endif
@@ -19,123 +19,103 @@
#include "Creature.h"
#include "MapManager.h"
#include "RandomMovementGenerator.h"
#include "Traveller.h"
#include "ObjectAccessor.h"
#include "DestinationHolderImp.h"
#include "Map.h"
#include "Util.h"
#include "CreatureGroups.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#define RUNNING_CHANCE_RANDOMMV 20 //will be "1 / RUNNING_CHANCE_RANDOMMV"
template<>
bool
RandomMovementGenerator<Creature>::GetDestination(float &x, float &y, float &z) const
{
if (i_destinationHolder.HasArrived())
return false;
i_destinationHolder.GetDestination(x, y, z);
return true;
}
#ifdef MAP_BASED_RAND_GEN
#define rand_norm() creature.rand_norm()
#endif
template<>
void
RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
float X, Y, Z, nx, ny, nz, ori, dist;
creature.GetHomePosition(X, Y, Z, ori);
float respX, respY, respZ, respO, currZ, destX, destY, destZ, travelDistZ;
creature.GetHomePosition(respX, respY, respZ, respO);
currZ = creature.GetPositionZ();
Map const* map = creature.GetBaseMap();
// For 2D/3D system selection
//bool is_land_ok = creature.canWalk();
//bool is_water_ok = creature.canSwim();
bool is_air_ok = creature.canFly();
//bool is_land_ok = creature.CanWalk(); // not used?
//bool is_water_ok = creature.CanSwim(); // not used?
bool is_air_ok = creature.canFly();
for (uint32 i = 0; ; ++i)
const float angle = float(rand_norm()) * static_cast<float>(M_PI*2.0f);
const float range = float(rand_norm()) * wander_distance;
const float distanceX = range * cos(angle);
const float distanceY = range * sin(angle);
destX = respX + distanceX;
destY = respY + distanceY;
// prevent invalid coordinates generation
Trinity::NormalizeMapCoord(destX);
Trinity::NormalizeMapCoord(destY);
travelDistZ = distanceX*distanceX + distanceY*distanceY;
if (is_air_ok) // 3D system above ground and above water (flying mode)
{
const float angle = (float)rand_norm()*static_cast<float>(M_PI*2);
const float range = (float)rand_norm()*wander_distance;
const float distanceX = range * cos(angle);
const float distanceY = range * sin(angle);
// Limit height change
const float distanceZ = float(rand_norm()) * sqrtf(travelDistZ)/2.0f;
destZ = respZ + distanceZ;
float levelZ = map->GetWaterOrGroundLevel(destX, destY, destZ-2.0f);
nx = X + distanceX;
ny = Y + distanceY;
// Problem here, we must fly above the ground and water, not under. Let's try on next tick
if (levelZ >= destZ)
return;
}
//else if (is_water_ok) // 3D system under water and above ground (swimming mode)
else // 2D only
{
// 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE)
travelDistZ = travelDistZ >= 100.0f ? 10.0f : sqrtf(travelDistZ);
// prevent invalid coordinates generation
Trinity::NormalizeMapCoord(nx);
Trinity::NormalizeMapCoord(ny);
// The fastest way to get an accurate result 90% of the time.
// Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
destZ = map->GetHeight(destX, destY, respZ+travelDistZ-2.0f, false);
dist = (nx - X)*(nx - X) + (ny - Y)*(ny - Y);
if (i == 5)
if (fabs(destZ - respZ) > travelDistZ) // Map check
{
nz = Z;
break;
}
// Vmap Horizontal or above
destZ = map->GetHeight(destX, destY, respZ - 2.0f, true);
if (is_air_ok) // 3D system above ground and above water (flying mode)
{
const float distanceZ = (float)(rand_norm()) * sqrtf(dist)/2; // Limit height change
nz = Z + distanceZ;
float tz = map->GetHeight(nx, ny, nz-2.0f, false); // Map check only, vmap needed here but need to alter vmaps checks for height.
float wz = map->GetWaterLevel(nx, ny);
if (tz >= nz || wz >= nz)
continue; // Problem here, we must fly above the ground and water, not under. Let's try on next tick
}
//else if (is_water_ok) // 3D system under water and above ground (swimming mode)
else // 2D only
{
dist = dist >= 100.0f ? 10.0f : sqrtf(dist); // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE)
// The fastest way to get an accurate result 90% of the time.
// Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
nz = map->GetHeight(nx, ny, Z+dist-2.0f, false); // Map check
if (fabs(nz-Z)>dist)
if (fabs(destZ - respZ) > travelDistZ)
{
nz = map->GetHeight(nx, ny, Z-2.0f, true); // Vmap Horizontal or above
if (fabs(nz-Z)>dist)
{
nz = map->GetHeight(nx, ny, Z+dist-2.0f, true); // Vmap Higher
if (fabs(nz-Z)>dist)
continue; // let's forget this bad coords where a z cannot be find and retry at next tick
}
// Vmap Higher
destZ = map->GetHeight(destX, destY, respZ+travelDistZ-2.0f, true);
// let's forget this bad coords where a z cannot be find and retry at next tick
if (fabs(destZ - respZ) > travelDistZ)
return;
}
}
break;
}
Traveller<Creature> traveller(creature);
creature.SetOrientation(creature.GetAngle(nx, ny));
i_destinationHolder.SetDestination(traveller, nx, ny, nz);
creature.AddUnitState(UNIT_STAT_ROAMING);
if (is_air_ok)
{
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
}
//else if (is_water_ok) // Swimming mode to be done with more than this check
i_nextMoveTime.Reset(0);
else
{
i_nextMoveTime.Reset(urand(500+i_destinationHolder.GetTotalTravelTime(), 5000+i_destinationHolder.GetTotalTravelTime()));
creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
}
i_nextMoveTime.Reset(urand(500, 10000));
creature.AddUnitState(UNIT_STAT_ROAMING_MOVE);
Movement::MoveSplineInit init(creature);
init.MoveTo(destX, destY, destZ);
init.SetWalk(true);
init.Launch();
//Call for creature group update
if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature)
{
creature.GetFormation()->LeaderMoveTo(nx, ny, nz);
}
creature.GetFormation()->LeaderMoveTo(destX, destY, destZ);
}
template<>
void
RandomMovementGenerator<Creature>::Initialize(Creature &creature)
void RandomMovementGenerator<Creature>::Initialize(Creature &creature)
{
if (!creature.isAlive())
return;
@@ -143,8 +123,7 @@ RandomMovementGenerator<Creature>::Initialize(Creature &creature)
if (!wander_distance)
wander_distance = creature.GetRespawnRadius();
if (irand(0, RUNNING_CHANCE_RANDOMMV) > 0)
creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
creature.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
_setRandomLocation(creature);
}
@@ -156,8 +135,11 @@ RandomMovementGenerator<Creature>::Reset(Creature &creature)
}
template<>
void
RandomMovementGenerator<Creature>::Finalize(Creature & /*creature*/){}
void RandomMovementGenerator<Creature>::Finalize(Creature &creature)
{
creature.ClearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
creature.SetWalk(false);
}
template<>
bool
@@ -165,35 +147,29 @@ RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32 diff)
{
if (creature.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
{
i_nextMoveTime.Update(i_nextMoveTime.GetExpiry()); // Expire the timer
creature.ClearUnitState(UNIT_STAT_ROAMING);
i_nextMoveTime.Reset(0); // Expire the timer
creature.ClearUnitState(UNIT_STAT_ROAMING_MOVE);
return true;
}
i_nextMoveTime.Update(diff);
if (i_destinationHolder.HasArrived() && !creature.IsStopped() && !creature.canFly())
creature.ClearUnitState(UNIT_STAT_ROAMING | UNIT_STAT_MOVE);
if (!i_destinationHolder.HasArrived() && creature.IsStopped())
creature.AddUnitState(UNIT_STAT_ROAMING);
CreatureTraveller traveller(creature);
if (i_destinationHolder.UpdateTraveller(traveller, diff, true))
if (creature.movespline->Finalized())
{
i_nextMoveTime.Update(diff);
if (i_nextMoveTime.Passed())
{
if (irand(0, RUNNING_CHANCE_RANDOMMV) > 0)
creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
_setRandomLocation(creature);
}
else if (creature.isPet() && creature.GetOwner() && !creature.IsWithinDist(creature.GetOwner(), PET_FOLLOW_DIST+2.5f))
{
creature.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
_setRandomLocation(creature);
}
}
return true;
}
template<>
bool RandomMovementGenerator<Creature>::GetResetPosition(Creature &creature, float& x, float& y, float& z)
{
float radius;
creature.GetRespawnPosition(x, y, z, NULL, &radius);
// use current if in range
if (creature.IsWithinDist2d(x,y,radius))
creature.GetPosition(x,y,z);
return true;
}
@@ -20,15 +20,12 @@
#define TRINITY_RANDOMMOTIONGENERATOR_H
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "Traveller.h"
template<class T>
class RandomMovementGenerator
: public MovementGeneratorMedium< T, RandomMovementGenerator<T> >
{
public:
// Wander dist is related on db spawn dist. So what if we wanna set eandom movement on summoned creature?!
RandomMovementGenerator(float spawn_dist = 0.0f) : i_nextMoveTime(0), wander_distance(spawn_dist) {}
void _setRandomLocation(T &);
@@ -36,18 +33,13 @@ class RandomMovementGenerator
void Finalize(T &);
void Reset(T &);
bool Update(T &, const uint32);
bool GetDestination(float &x, float &y, float &z) const;
void UpdateMapPosition(uint32 mapid, float &x, float &y, float &z)
{
i_destinationHolder.GetLocationNow(mapid, x, y, z);
}
bool GetResetPosition(T&, float& x, float& y, float& z);
MovementGeneratorType GetMovementGeneratorType() { return RANDOM_MOTION_TYPE; }
private:
TimeTrackerSmall i_nextMoveTime;
DestinationHolder< Traveller<T> > i_destinationHolder;
float wander_distance;
uint32 i_nextMove;
float wander_distance;
};
#endif
@@ -21,106 +21,42 @@
#include "Errors.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "DestinationHolderImp.h"
#include "World.h"
#define SMALL_ALPHA 0.05f
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#include <cmath>
/*
struct StackCleaner
{
Creature &i_creature;
StackCleaner(Creature &creature) : i_creature(creature) {}
void Done(void) { i_creature.StopMoving(); }
~StackCleaner()
{
i_creature->Clear();
}
};
*/
template<class T>
TargetedMovementGenerator<T>::TargetedMovementGenerator(Unit &target, float offset, float angle)
: TargetedMovementGeneratorBase(target)
, i_offset(offset), i_angle(angle), i_recalculateTravel(false)
{
target.GetPosition(i_targetX, i_targetY, i_targetZ);
}
template<class T>
bool
TargetedMovementGenerator<T>::_setTargetLocation(T &owner)
template<class T, typename D>
void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner)
{
if (!i_target.isValid() || !i_target->IsInWorld())
return false;
return;
if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
return false;
if (owner.HasUnitState(UNIT_STAT_NOT_MOVE))
return;
float x, y, z;
Traveller<T> traveller(owner);
if (i_destinationHolder.HasDestination())
if (i_offset && i_target->IsWithinDistInMap(&owner,2*i_offset))
{
if (i_destinationHolder.HasArrived())
{
// prevent redundant micro-movement
if (!i_offset)
{
if (i_target->IsWithinMeleeRange(&owner))
return false;
}
else if (!i_angle && !owner.HasUnitState(UNIT_STAT_FOLLOW))
{
if (i_target->IsWithinDistInMap(&owner, i_offset))
return false;
}
else
{
if (i_target->IsWithinDistInMap(&owner, i_offset + 1.0f))
return false;
}
}
else
{
bool stop = false;
if (!i_offset)
{
if (i_target->IsWithinMeleeRange(&owner, 0))
stop = true;
}
else if (!i_angle && !owner.HasUnitState(UNIT_STAT_FOLLOW))
{
if (i_target->IsWithinDist(&owner, i_offset * 0.8f))
stop = true;
}
if (!owner.movespline->Finalized())
return;
if (stop)
{
owner.GetPosition(x, y, z);
i_destinationHolder.SetDestination(traveller, x, y, z);
i_destinationHolder.StartTravel(traveller, false);
owner.StopMoving();
return false;
}
}
if (i_target->GetExactDistSq(i_targetX, i_targetY, i_targetZ) < 0.01f)
return false;
owner.GetPosition(x, y, z);
}
if (!i_offset)
else if (!i_offset)
{
if (i_target->IsWithinMeleeRange(&owner))
return;
// to nearest random contact position
i_target->GetRandomContactPoint(&owner, x, y, z, 0, MELEE_RANGE - 0.5f);
}
else if (!i_angle && !owner.HasUnitState(UNIT_STAT_FOLLOW))
{
// caster chase
i_target->GetContactPoint(&owner, x, y, z, i_offset * urand(80, 95) * 0.01f);
}
else
{
if (i_target->IsWithinDistInMap(&owner, i_offset + 1.0f))
return;
// to at i_offset distance from target and i_angle from target facing
i_target->GetClosePoint(x, y, z, owner.GetObjectSize(), i_offset, i_angle);
}
@@ -137,55 +73,65 @@ TargetedMovementGenerator<T>::_setTargetLocation(T &owner)
ralf
//We don't update Mob Movement, if the difference between New destination and last destination is < BothObjectSize
float bothObjectSize = i_target->GetObjectSize() + owner.GetObjectSize() + CONTACT_DISTANCE;
if (i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x, y, z) < bothObjectSize)
float bothObjectSize = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + CONTACT_DISTANCE;
if( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize )
return;
*/
i_destinationHolder.SetDestination(traveller, x, y, z);
owner.AddUnitState(UNIT_STAT_CHASE);
i_destinationHolder.StartTravel(traveller);
return true;
D::_addUnitStateMove(owner);
i_targetReached = false;
i_recalculateTravel = false;
Movement::MoveSplineInit init(owner);
init.MoveTo(x,y,z);
init.SetWalk(((D*)this)->EnableWalking());
init.Launch();
}
template<class T>
void
TargetedMovementGenerator<T>::Initialize(T &owner)
template<>
void TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::UpdateFinalDistance(float /*fDistance*/)
{
if (owner.isInCombat())
owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
_setTargetLocation(owner);
// nothing to do for Player
}
template<class T>
void
TargetedMovementGenerator<T>::Finalize(T &owner)
template<>
void TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::UpdateFinalDistance(float /*fDistance*/)
{
owner.ClearUnitState(UNIT_STAT_CHASE);
// nothing to do for Player
}
template<class T>
void
TargetedMovementGenerator<T>::Reset(T &owner)
template<>
void TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::UpdateFinalDistance(float fDistance)
{
Initialize(owner);
i_offset = fDistance;
i_recalculateTravel = true;
}
template<class T>
bool
TargetedMovementGenerator<T>::Update(T &owner, const uint32 time_diff)
template<>
void TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::UpdateFinalDistance(float fDistance)
{
i_offset = fDistance;
i_recalculateTravel = true;
}
template<class T, typename D>
bool TargetedMovementGeneratorMedium<T,D>::Update(T &owner, const uint32 & time_diff)
{
if (!i_target.isValid() || !i_target->IsInWorld())
return false;
if (!&owner || !owner.isAlive())
if (!owner.isAlive())
return true;
if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DISTRACTED))
if (owner.HasUnitState(UNIT_STAT_NOT_MOVE))
{
D::_clearUnitStateMove(owner);
return true;
}
// prevent movement while casting spells with cast time or channel time
if (owner.HasUnitState(UNIT_STAT_CASTING))
if (owner.IsNonMeleeSpellCasted(false, false, true))
{
if (!owner.IsStopped())
owner.StopMoving();
@@ -193,85 +139,170 @@ TargetedMovementGenerator<T>::Update(T &owner, const uint32 time_diff)
}
// prevent crash after creature killed pet
if (!owner.HasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget())
return true;
Traveller<T> traveller(owner);
if (!i_destinationHolder.HasDestination())
_setTargetLocation(owner);
else if (owner.IsStopped() && !i_destinationHolder.HasArrived())
if (static_cast<D*>(this)->_lostTarget(owner))
{
owner.AddUnitState(UNIT_STAT_CHASE);
i_destinationHolder.StartTravel(traveller);
D::_clearUnitStateMove(owner);
return true;
}
if (i_destinationHolder.UpdateTraveller(traveller, time_diff))
i_recheckDistance.Update(time_diff);
if (i_recheckDistance.Passed())
{
// put targeted movement generators on a higher priority
//if (owner.GetObjectSize())
//i_destinationHolder.ResetUpdate(50);
i_recheckDistance.Reset(50);
//More distance let have better performance, less distance let have more sensitive reaction at target move.
float allowed_dist = i_target->GetObjectSize() + owner.GetObjectSize() + MELEE_RANGE - 0.5f;
float dist = (owner.movespline->FinalDestination() - G3D::Vector3(i_target->GetPositionX(),i_target->GetPositionY(),i_target->GetPositionZ())).squaredLength();
if (dist >= allowed_dist * allowed_dist)
_setTargetLocation(owner);
}
// target moved
if (i_targetX != i_target->GetPositionX() || i_targetY != i_target->GetPositionY()
|| i_targetZ != i_target->GetPositionZ())
{
if (_setTargetLocation(owner) || !owner.HasUnitState(UNIT_STAT_FOLLOW))
owner.SetInFront(i_target.getTarget());
i_target->GetPosition(i_targetX, i_targetY, i_targetZ);
}
if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel)
{
i_recalculateTravel = false;
//Angle update will take place into owner.StopMoving()
if (owner.movespline->Finalized())
{
static_cast<D*>(this)->MovementInform(owner);
if (i_angle == 0.f && !owner.HasInArc(0.01f, i_target.getTarget()))
owner.SetInFront(i_target.getTarget());
owner.StopMoving();
if (owner.IsWithinMeleeRange(i_target.getTarget()) && !owner.HasUnitState(UNIT_STAT_FOLLOW))
owner.Attack(i_target.getTarget(), true);
if (!i_targetReached)
{
i_targetReached = true;
static_cast<D*>(this)->_reachTarget(owner);
}
}
// Implemented for PetAI to handle resetting flags when pet owner reached
if (i_destinationHolder.HasArrived())
MovementInform(owner);
else
{
if (i_recalculateTravel)
_setTargetLocation(owner);
}
return true;
}
//-----------------------------------------------//
template<class T>
Unit*
TargetedMovementGenerator<T>::GetTarget() const
void ChaseMovementGenerator<T>::_reachTarget(T &owner)
{
return i_target.getTarget();
if (owner.IsWithinMeleeRange(this->i_target.getTarget()))
owner.Attack(this->i_target.getTarget(),true);
}
template<>
void ChaseMovementGenerator<Player>::Initialize(Player &owner)
{
owner.AddUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE);
_setTargetLocation(owner);
}
template<>
void ChaseMovementGenerator<Creature>::Initialize(Creature &owner)
{
owner.SetWalk(false);
owner.AddUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE);
_setTargetLocation(owner);
}
template<class T>
void TargetedMovementGenerator<T>::MovementInform(T & /*unit*/)
void ChaseMovementGenerator<T>::Finalize(T &owner)
{
owner.ClearUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE);
}
template<class T>
void ChaseMovementGenerator<T>::Reset(T &owner)
{
Initialize(owner);
}
//-----------------------------------------------//
template<>
bool FollowMovementGenerator<Creature>::EnableWalking() const
{
return i_target.isValid() && i_target->IsWalking();
}
template<>
bool FollowMovementGenerator<Player>::EnableWalking() const
{
return false;
}
template<>
void FollowMovementGenerator<Player>::_updateSpeed(Player &/*u*/)
{
// nothing to do for Player
}
template<>
void FollowMovementGenerator<Creature>::_updateSpeed(Creature &u)
{
// pet only sync speed with owner
if (!((Creature&)u).isPet() || !i_target.isValid() || i_target->GetGUID() != u.GetOwnerGUID())
return;
u.UpdateSpeed(MOVE_RUN,true);
u.UpdateSpeed(MOVE_WALK,true);
u.UpdateSpeed(MOVE_SWIM,true);
}
template<>
void FollowMovementGenerator<Player>::Initialize(Player &owner)
{
owner.AddUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE);
_updateSpeed(owner);
_setTargetLocation(owner);
}
template<>
void FollowMovementGenerator<Creature>::Initialize(Creature &owner)
{
owner.AddUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE);
_updateSpeed(owner);
_setTargetLocation(owner);
}
template<class T>
void FollowMovementGenerator<T>::Finalize(T &owner)
{
owner.ClearUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE);
_updateSpeed(owner);
}
template<class T>
void FollowMovementGenerator<T>::Reset(T &owner)
{
Initialize(owner);
}
template<class T>
void FollowMovementGenerator<T>::MovementInform(T & /*unit*/)
{
}
template <> void TargetedMovementGenerator<Creature>::MovementInform(Creature &unit)
template<>
void FollowMovementGenerator<Creature>::MovementInform(Creature &unit)
{
// Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
unit.AI()->MovementInform(TARGETED_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
if (unit.AI())
unit.AI()->MovementInform(FOLLOW_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
}
template void TargetedMovementGenerator<Player>::MovementInform(Player&); // Not implemented for players
template TargetedMovementGenerator<Player>::TargetedMovementGenerator(Unit &target, float offset, float angle);
template TargetedMovementGenerator<Creature>::TargetedMovementGenerator(Unit &target, float offset, float angle);
template bool TargetedMovementGenerator<Player>::_setTargetLocation(Player &);
template bool TargetedMovementGenerator<Creature>::_setTargetLocation(Creature &);
template void TargetedMovementGenerator<Player>::Initialize(Player &);
template void TargetedMovementGenerator<Creature>::Initialize(Creature &);
template void TargetedMovementGenerator<Player>::Finalize(Player &);
template void TargetedMovementGenerator<Creature>::Finalize(Creature &);
template void TargetedMovementGenerator<Player>::Reset(Player &);
template void TargetedMovementGenerator<Creature>::Reset(Creature &);
template bool TargetedMovementGenerator<Player>::Update(Player &, const uint32);
template bool TargetedMovementGenerator<Creature>::Update(Creature &, const uint32);
template Unit* TargetedMovementGenerator<Player>::GetTarget() const;
template Unit* TargetedMovementGenerator<Creature>::GetTarget() const;
//-----------------------------------------------//
template void TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::_setTargetLocation(Player &);
template void TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::_setTargetLocation(Player &);
template void TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::_setTargetLocation(Creature &);
template void TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::_setTargetLocation(Creature &);
template bool TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::Update(Player &, const uint32 &);
template bool TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::Update(Player &, const uint32 &);
template bool TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::Update(Creature &, const uint32 &);
template bool TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::Update(Creature &, const uint32 &);
template void ChaseMovementGenerator<Player>::_reachTarget(Player &);
template void ChaseMovementGenerator<Creature>::_reachTarget(Creature &);
template void ChaseMovementGenerator<Player>::Finalize(Player &);
template void ChaseMovementGenerator<Creature>::Finalize(Creature &);
template void ChaseMovementGenerator<Player>::Reset(Player &);
template void ChaseMovementGenerator<Creature>::Reset(Creature &);
template void FollowMovementGenerator<Player>::Finalize(Player &);
template void FollowMovementGenerator<Creature>::Finalize(Creature &);
template void FollowMovementGenerator<Player>::Reset(Player &);
template void FollowMovementGenerator<Creature>::Reset(Creature &);
template void FollowMovementGenerator<Player>::MovementInform(Player &unit);
@@ -20,9 +20,8 @@
#define TRINITY_TARGETEDMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "Traveller.h"
#include "FollowerReference.h"
#include "Timer.h"
class TargetedMovementGeneratorBase
{
@@ -33,41 +32,84 @@ class TargetedMovementGeneratorBase
FollowerReference i_target;
};
template<class T, typename D>
class TargetedMovementGeneratorMedium
: public MovementGeneratorMedium< T, D >, public TargetedMovementGeneratorBase
{
protected:
TargetedMovementGeneratorMedium(Unit &target, float offset, float angle) :
TargetedMovementGeneratorBase(target), i_offset(offset), i_angle(angle),
i_recalculateTravel(false), i_targetReached(false), i_recheckDistance(0)
{
}
~TargetedMovementGeneratorMedium() {}
public:
bool Update(T &, const uint32 &);
Unit* GetTarget() const { return i_target.getTarget(); }
void unitSpeedChanged() { i_recalculateTravel=true; }
void UpdateFinalDistance(float fDistance);
protected:
void _setTargetLocation(T &);
TimeTrackerSmall i_recheckDistance;
float i_offset;
float i_angle;
bool i_recalculateTravel : 1;
bool i_targetReached : 1;
};
template<class T>
class TargetedMovementGenerator
: public MovementGeneratorMedium< T, TargetedMovementGenerator<T> >, public TargetedMovementGeneratorBase
class ChaseMovementGenerator : public TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >
{
public:
TargetedMovementGenerator(Unit &target, float offset = 0, float angle = 0);
~TargetedMovementGenerator() {}
ChaseMovementGenerator(Unit &target)
: TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target) {}
ChaseMovementGenerator(Unit &target, float offset, float angle)
: TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target, offset, angle) {}
~ChaseMovementGenerator() {}
MovementGeneratorType GetMovementGeneratorType() { return CHASE_MOTION_TYPE; }
void Initialize(T &);
void Finalize(T &);
void Reset(T &);
bool Update(T &, const uint32);
MovementGeneratorType GetMovementGeneratorType() { return TARGETED_MOTION_TYPE; }
void MovementInform(T &){}
static void _clearUnitStateMove(T &u) { u.ClearUnitState(UNIT_STAT_CHASE_MOVE); }
static void _addUnitStateMove(T &u) { u.AddUnitState(UNIT_STAT_CHASE_MOVE); }
bool EnableWalking() const { return false;}
bool _lostTarget(T &u) const { return u.getVictim() != this->GetTarget(); }
void _reachTarget(T &);
};
template<class T>
class FollowMovementGenerator : public TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >
{
public:
FollowMovementGenerator(Unit &target)
: TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >(target){}
FollowMovementGenerator(Unit &target, float offset, float angle)
: TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >(target, offset, angle) {}
~FollowMovementGenerator() {}
MovementGeneratorType GetMovementGeneratorType() { return FOLLOW_MOTION_TYPE; }
void Initialize(T &);
void Finalize(T &);
void Reset(T &);
void MovementInform(T &);
Unit* GetTarget() const;
bool GetDestination(float &x, float &y, float &z) const
{
if (i_destinationHolder.HasArrived() || !i_destinationHolder.HasDestination()) return false;
i_destinationHolder.GetDestination(x, y, z);
return true;
}
void unitSpeedChanged() { i_recalculateTravel=true; }
static void _clearUnitStateMove(T &u) { u.ClearUnitState(UNIT_STAT_FOLLOW_MOVE); }
static void _addUnitStateMove(T &u) { u.AddUnitState(UNIT_STAT_FOLLOW_MOVE); }
bool EnableWalking() const;
bool _lostTarget(T &) const { return false; }
void _reachTarget(T &) {}
private:
bool _setTargetLocation(T &);
float i_offset;
float i_angle;
DestinationHolder< Traveller<T> > i_destinationHolder;
bool i_recalculateTravel;
float i_targetX, i_targetY, i_targetZ;
void _updateSpeed(T &u);
};
#endif
@@ -17,222 +17,165 @@
*/
//Basic headers
#include "WaypointMovementGenerator.h"
#include "DestinationHolderImp.h"
//Extended headers
#include "ObjectMgr.h"
#include "World.h"
#include "MapManager.h" // for flightmaster grid preloading
//Flightmaster grid preloading
#include "MapManager.h"
//Creature-specific headers
#include "Creature.h"
#include "CreatureAI.h"
#include "CreatureGroups.h"
//Player-specific
#include "Player.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
template<class T>
void
WaypointMovementGenerator<T>::Initialize(T & /*u*/){}
template<>
void
WaypointMovementGenerator<Creature>::Finalize(Creature & /*u*/){}
template<>
void
WaypointMovementGenerator<Player>::Finalize(Player & /*u*/){}
template<class T>
void
WaypointMovementGenerator<T>::MovementInform(T & /*unit*/){}
template<>
void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit)
void WaypointMovementGenerator<Creature>::LoadPath(Creature &creature)
{
unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
if (!path_id)
path_id = creature.GetWaypointPath();
i_path = sWaypointMgr->GetPath(path_id);
if (!i_path)
{
// No movement found for entry
sLog->outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path id: %u", creature.GetName(), creature.GetEntry(), creature.GetGUIDLow(), path_id);
return;
}
StartMoveNow(creature);
}
template<>
bool WaypointMovementGenerator<Creature>::GetDestination(float &x, float &y, float &z) const
void WaypointMovementGenerator<Creature>::Initialize(Creature &creature)
{
if (i_destinationHolder.HasArrived())
return false;
LoadPath(creature);
creature.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
}
void WaypointMovementGenerator<Creature>::Finalize(Creature &creature)
{
creature.ClearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
creature.SetWalk(false);
}
void WaypointMovementGenerator<Creature>::Reset(Creature &creature)
{
creature.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
StartMoveNow(creature);
}
void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature)
{
if (!i_path || i_path->empty())
return;
if (m_isArrivalDone)
return;
creature.ClearUnitState(UNIT_STAT_ROAMING_MOVE);
m_isArrivalDone = true;
if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance)
{
sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for %u.", i_path->at(i_currentNode)->event_id, i_currentNode, creature.GetGUID());
creature.GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, &creature, NULL/*, false*/);
}
// Inform script
MovementInform(creature);
Stop(i_path->at(i_currentNode)->delay);
}
bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature)
{
if (!i_path || i_path->empty())
return false;
if (Stopped())
return true;
const WaypointData *node = i_path->at(i_currentNode);
if (m_isArrivalDone)
{
if ((i_currentNode == i_path->size() - 1) && !repeating) // If that's our last waypoint
{
creature.SetHomePosition(node->x, node->y, node->z, creature.GetOrientation());
creature.GetMotionMaster()->Initialize();
return false;
}
i_currentNode = (i_currentNode+1) % i_path->size();
}
m_isArrivalDone = false;
creature.AddUnitState(UNIT_STAT_ROAMING_MOVE);
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(!node->run);
init.Launch();
//Call for creature group update
if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature)
creature.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
i_destinationHolder.GetDestination(x, y, z);
return true;
}
template<>
bool WaypointMovementGenerator<Player>::GetDestination(float & /*x*/, float & /*y*/, float & /*z*/) const
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
{
return false;
}
template<>
void WaypointMovementGenerator<Creature>::Reset(Creature & /*unit*/)
{
StopedByPlayer = true;
i_nextMoveTime.Reset(0);
}
template<>
void WaypointMovementGenerator<Player>::Reset(Player & /*unit*/){}
template<>
void WaypointMovementGenerator<Creature>::InitTraveller(Creature &unit, const WaypointData &node)
{
node.run ? unit.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING):
unit.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
unit.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
unit.SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
// TODO: make this part of waypoint node, so that creature can walk when desired?
if (unit.canFly())
unit.SetByteFlag(UNIT_FIELD_BYTES_1, 3, 0x02);
unit.AddUnitState(UNIT_STAT_ROAMING);
}
template<>
void
WaypointMovementGenerator<Creature>::Initialize(Creature &u)
{
u.StopMoving();
//i_currentNode = -1; // uint32, become 0 in the first update
//i_nextMoveTime.Reset(0);
StopedByPlayer = false;
if (!path_id)
path_id = u.GetWaypointPath();
waypoints = sWaypointMgr->GetPath(path_id);
i_currentNode = 0;
if (waypoints && waypoints->size())
{
node = waypoints->front();
Traveller<Creature> traveller(u);
InitTraveller(u, *node);
i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
//Call for creature group update
if (u.GetFormation() && u.GetFormation()->getLeader() == &u)
u.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
}
else
node = NULL;
}
template<>
void WaypointMovementGenerator<Player>::InitTraveller(Player & /*unit*/, const WaypointData & /*node*/){}
template<class T>
bool
WaypointMovementGenerator<T>::Update(T & /*unit*/, const uint32 /*diff*/)
{
return false;
}
template<>
bool
WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 diff)
{
if (!&unit)
return true;
if (!path_id)
return false;
// Waypoint movement can be switched on/off
// This is quite handy for escort quests and other stuff
if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
if (creature.HasUnitState(UNIT_STAT_NOT_MOVE))
{
creature.ClearUnitState(UNIT_STAT_ROAMING_MOVE);
return true;
// Clear the generator if the path doesn't exist
if (!waypoints || !waypoints->size())
}
// prevent a crash at empty waypoint path.
if (!i_path || i_path->empty())
return false;
Traveller<Creature> traveller(unit);
i_nextMoveTime.Update(diff);
i_destinationHolder.UpdateTraveller(traveller, diff, true);
if (i_nextMoveTime.GetExpiry() < TIMEDIFF_NEXT_WP)
if (Stopped())
{
if (unit.IsStopped())
{
if (StopedByPlayer)
{
ASSERT(node);
InitTraveller(unit, *node);
i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
StopedByPlayer = false;
return true;
}
if (i_currentNode == waypoints->size() - 1) // If that's our last waypoint
{
if (repeating) // If the movement is repeating
i_currentNode = 0; // Start moving all over again
else
{
unit.SetHomePosition(node->x, node->y, node->z, unit.GetOrientation());
unit.GetMotionMaster()->Initialize();
return false; // Clear the waypoint movement
}
}
else
++i_currentNode;
node = waypoints->at(i_currentNode);
InitTraveller(unit, *node);
i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
//Call for creature group update
if (unit.GetFormation() && unit.GetFormation()->getLeader() == &unit)
unit.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
}
else
{
//Determine waittime
if (node->delay)
i_nextMoveTime.Reset(node->delay);
//note: disable "start" for mtmap
if (node->event_id && urand(0, 99) < node->event_chance)
unit.GetMap()->ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL/*, false*/);
i_destinationHolder.ResetTravelTime();
MovementInform(unit);
unit.UpdateWaypointID(i_currentNode);
unit.ClearUnitState(UNIT_STAT_ROAMING);
if (node->orientation)
{
unit.Relocate(node->x, node->y, node->z, node->orientation);
unit.SetFacing(node->orientation, NULL);
}
else
unit.Relocate(node->x, node->y, node->z);
}
if (CanMove(diff))
return StartMove(creature);
}
else
else
{
if (unit.IsStopped() && !i_destinationHolder.HasArrived())
if (creature.IsStopped())
Stop(STOP_TIME_FOR_PLAYER);
else if (creature.movespline->Finalized())
{
if (!StopedByPlayer)
{
i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER);
i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER);
StopedByPlayer = true;
}
}
OnArrived(creature);
return StartMove(creature);
}
}
return true;
}
void WaypointMovementGenerator<Creature>::MovementInform(Creature &creature)
{
if (creature.AI())
creature.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
}
bool WaypointMovementGenerator<Creature>::GetResetPosition(Creature&, float& x, float& y, float& z)
{
// prevent a crash at empty waypoint path.
if (!i_path || i_path->empty())
return false;
const WaypointData* node = i_path->at(i_currentNode);
x = node->x; y = node->y; z = node->z;
return true;
}
template void WaypointMovementGenerator<Player>::Initialize(Player &);
template bool WaypointMovementGenerator<Player>::Update(Player &, const uint32);
template void WaypointMovementGenerator<Player>::MovementInform(Player &);
//----------------------------------------------------//
@@ -253,71 +196,72 @@ uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const
void FlightPathMovementGenerator::Initialize(Player &player)
{
player.getHostileRefManager().setOnlineOfflineState(false);
player.AddUnitState(UNIT_STAT_IN_FLIGHT);
player.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
Traveller<Player> traveller(player);
// do not send movement, it was sent already
i_destinationHolder.SetDestination(traveller, (*i_path)[i_currentNode].x, (*i_path)[i_currentNode].y, (*i_path)[i_currentNode].z, false);
// For preloading end grid
Reset(player);
InitEndGridInfo();
player.SendMonsterMoveByPath(GetPath(), GetCurrentNode(), GetPathAtMapEnd());
}
void FlightPathMovementGenerator::Finalize(Player & player)
{
// remove flag to prevent send object build movement packets for flight state and crash (movement generator already not at top of stack)
player.ClearUnitState(UNIT_STAT_IN_FLIGHT);
float x = 0;
float y = 0;
float z = 0;
i_destinationHolder.GetLocationNow(player.GetBaseMap(), x, y, z);
player.UpdatePosition(x, y, z, player.GetOrientation());
player.Dismount();
player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
if(player.m_taxi.empty())
{
player.getHostileRefManager().setOnlineOfflineState(true);
if(player.pvpInfo.inHostileArea)
player.CastSpell(&player, 2479, true);
// update z position to ground and orientation for landing point
// this prevent cheating with landing point at lags
// when client side flight end early in comparison server side
player.StopMoving();
}
}
#define PLAYER_FLIGHT_SPEED 32.0f
void FlightPathMovementGenerator::Reset(Player & player)
{
player.getHostileRefManager().setOnlineOfflineState(false);
player.AddUnitState(UNIT_STAT_IN_FLIGHT);
player.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
Movement::MoveSplineInit init(player);
uint32 end = GetPathAtMapEnd();
for (uint32 i = GetCurrentNode(); i != end; ++i)
{
G3D::Vector3 vertice((*i_path)[i].x,(*i_path)[i].y,(*i_path)[i].z);
init.Path().push_back(vertice);
}
init.SetFirstPointId(GetCurrentNode());
init.SetFly();
init.SetVelocity(PLAYER_FLIGHT_SPEED);
init.Launch();
}
bool FlightPathMovementGenerator::Update(Player &player, const uint32 diff)
{
if (MovementInProgress())
uint32 pointId = (uint32)player.movespline->currentPathIdx();
if (pointId > i_currentNode)
{
Traveller<Player> traveller(player);
if (i_destinationHolder.UpdateTraveller(traveller, diff))
bool departureEvent = true;
do
{
i_destinationHolder.ResetUpdate(FLIGHT_TRAVEL_UPDATE);
if (i_destinationHolder.HasArrived())
{
DoEventIfAny(player, (*i_path)[i_currentNode], false);
uint32 curMap = (*i_path)[i_currentNode].mapid;
++i_currentNode;
if (MovementInProgress())
{
DoEventIfAny(player, (*i_path)[i_currentNode], true);
sLog->outStaticDebug("loading node %u for player %s", i_currentNode, player.GetName());
if ((*i_path)[i_currentNode].mapid == curMap)
{
// do not send movement, it was sent already
i_destinationHolder.SetDestination(traveller, (*i_path)[i_currentNode].x, (*i_path)[i_currentNode].y, (*i_path)[i_currentNode].z, false);
}
// check if it's time to preload the flightmaster grid at path end
if (i_currentNode == m_preloadTargetNode)
PreloadEndGrid();
return true;
}
//else HasArrived()
}
else
return true;
DoEventIfAny(player, (*i_path)[i_currentNode], departureEvent);
if (pointId == i_currentNode)
break;
if (i_currentNode == _preloadTargetNode)
PreloadEndGrid();
i_currentNode += (uint32)departureEvent;
departureEvent = !departureEvent;
}
else
return true;
while (true);
}
// we have arrived at the end of the path
return false;
return i_currentNode < (i_path->size()-1);
}
void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
@@ -336,33 +280,6 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
}
}
void FlightPathMovementGenerator::InitEndGridInfo()
{
// Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will
// be reinitialized for each flightmaster at the end of each spline (or stop) in the flight.
uint32 nodeCount = (*i_path).size(); // Get the number of nodes in the path.
m_endMapId = (*i_path)[nodeCount -1].mapid; // Get the map ID from the last node
m_preloadTargetNode = nodeCount - 3; // 2 nodes before the final node, we pre-load the grid
m_endGridX = (*i_path)[nodeCount -1].x; // Get the X position from the last node
m_endGridY = (*i_path)[nodeCount -1].y; // Get the Y position from the last node
}
void FlightPathMovementGenerator::PreloadEndGrid()
{
// used to preload the final grid where the flightmaster is
Map* endMap = sMapMgr->FindBaseNonInstanceMap(m_endMapId);
// Load the grid
if (endMap)
{
sLog->outDetail("Preloading flightmaster at grid (%f, %f) for map %u", m_endGridX, m_endGridY, m_endMapId);
endMap->LoadGrid(m_endGridX, m_endGridY);
}
else
sLog->outDetail("Unable to determine map to preload flightmaster grid");
}
void FlightPathMovementGenerator::DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure)
{
if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID)
@@ -372,6 +289,39 @@ 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;
}
void FlightPathMovementGenerator::InitEndGridInfo()
{
/*! Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will
be reinitialized for each flightmaster at the end of each spline (or stop) in the flight. */
uint32 nodeCount = (*i_path).size(); //! Number of nodes in path.
_endMapId = (*i_path)[nodeCount - 1].mapid; //! MapId of last node
_preloadTargetNode = nodeCount - 3;
_endGridX = (*i_path)[nodeCount - 1].x;
_endGridY = (*i_path)[nodeCount - 1].y;
}
void FlightPathMovementGenerator::PreloadEndGrid()
{
// used to preload the final grid where the flightmaster is
Map* endMap = sMapMgr->FindBaseNonInstanceMap(_endMapId);
// Load the grid
if (endMap)
{
sLog->outDetail("Preloading rid (%f, %f) for map %u at node index %u/%u", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path->size()-1));
endMap->LoadGrid(_endGridX, _endGridY);
}
else
sLog->outDetail("Unable to determine map to preload flightmaster grid");
}
//
// Unique1's ASTAR Pathfinding Code... For future use & reference...
@@ -26,10 +26,8 @@
*/
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "WaypointManager.h"
#include "Path.h"
#include "Traveller.h"
#include "Player.h"
@@ -44,49 +42,68 @@ template<class T, class P>
class PathMovementBase
{
public:
PathMovementBase() : i_currentNode(0) {}
PathMovementBase() : i_currentNode(0), i_path(NULL) {}
virtual ~PathMovementBase() {};
bool MovementInProgress(void) const { return i_currentNode < i_path->size(); }
// template pattern, not defined .. override required
void LoadPath(T &);
void ReloadPath(T &);
uint32 GetCurrentNode() const { return i_currentNode; }
bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x, y, z); return true; }
bool GetPosition(float& x, float& y, float& z) const { i_destinationHolder.GetLocationNowNoMicroMovement(x, y, z); return true; }
protected:
uint32 i_currentNode;
DestinationHolder< Traveller<T> > i_destinationHolder;
P i_path;
uint32 i_currentNode;
};
template<class T>
class WaypointMovementGenerator;
class WaypointMovementGenerator
: public MovementGeneratorMedium< T, WaypointMovementGenerator<T> >, public PathMovementBase<T, WaypointPath const*>
template<>
class WaypointMovementGenerator<Creature>
: public MovementGeneratorMedium< Creature, WaypointMovementGenerator<Creature> >,
public PathMovementBase<Creature, WaypointPath const*>
{
public:
WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true) :
node(NULL), path_id(_path_id), i_nextMoveTime(0), repeating(_repeating), StopedByPlayer(false) {}
WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true) : i_nextMoveTime(0), path_id(_path_id), m_isArrivalDone(false), repeating(_repeating) {}
~WaypointMovementGenerator() { i_path = NULL; }
void Initialize(Creature &);
void Finalize(Creature &);
void Reset(Creature &);
bool Update(Creature &, const uint32 &diff);
void MovementInform(Creature &);
void Initialize(T &);
void Finalize(T &);
void MovementInform(T &);
void InitTraveller(T &, const WaypointData &);
void GeneratePathId(T &);
void Reset(T &unit);
bool Update(T &, const uint32);
bool GetDestination(float &x, float &y, float &z) const;
MovementGeneratorType GetMovementGeneratorType() { return WAYPOINT_MOTION_TYPE; }
// now path movement implmementation
void LoadPath(Creature &c);
bool GetResetPosition(Creature&, float& x, float& y, float& z);
private:
WaypointData* node;
uint32 path_id;
void Stop(int32 time) { i_nextMoveTime.Reset(time);}
bool Stopped() { return !i_nextMoveTime.Passed();}
bool CanMove(int32 diff)
{
i_nextMoveTime.Update(diff);
return i_nextMoveTime.Passed();
}
void OnArrived(Creature&);
bool StartMove(Creature&);
void StartMoveNow(Creature& creature)
{
i_nextMoveTime.Reset(0);
StartMove(creature);
}
TimeTrackerSmall i_nextMoveTime;
WaypointPath const* waypoints;
bool repeating, StopedByPlayer;
bool m_isArrivalDone;
uint32 path_id;
bool repeating;
};
/** FlightPathMovementGenerator generates movement of the player for the paths
@@ -103,7 +120,7 @@ public PathMovementBase<Player, TaxiPathNodeList const*>
i_currentNode = startNode;
}
void Initialize(Player &);
void Reset(Player & /*u*/){};
void Reset(Player &);
void Finalize(Player &);
bool Update(Player &, const uint32);
MovementGeneratorType GetMovementGeneratorType() { return FLIGHT_MOTION_TYPE; }
@@ -115,17 +132,16 @@ public PathMovementBase<Player, TaxiPathNodeList const*>
void SkipCurrentNode() { ++i_currentNode; }
void DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure);
bool GetDestination(float& x, float& y, float& z) const { return PathMovementBase<Player, TaxiPathNodeList const*>::GetDestination(x, y, z); }
bool GetResetPosition(Player&, float& x, float& y, float& z);
void PreloadEndGrid();
void InitEndGridInfo();
void PreloadEndGrid();
private:
// storage for preloading the flightmaster grid at end
// before reaching final waypoint
uint32 m_endMapId;
uint32 m_preloadTargetNode;
float m_endGridX;
float m_endGridY;
float _endGridX; //! X coord of last node location
float _endGridY; //! Y coord of last node location
uint32 _endMapId; //! map Id of last node location
uint32 _preloadTargetNode; //! node index where preloading starts
};
#endif
@@ -0,0 +1,316 @@
/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "MoveSpline.h"
#include <sstream>
#include "Log.h"
namespace Movement{
extern float computeFallTime(float path_length, bool isSafeFall);
extern float computeFallElevation(float time_passed, bool isSafeFall, float start_velocy);
extern float computeFallElevation(float time_passed);
Location MoveSpline::ComputePosition() const
{
ASSERT(Initialized());
float u = 1.f;
int32 seg_time = spline.length(point_Idx,point_Idx+1);
if (seg_time > 0)
u = (time_passed - spline.length(point_Idx)) / (float)seg_time;
Location c;
c.orientation = initialOrientation;
spline.evaluate_percent(point_Idx, u, c);
if (splineflags.animation)
;// MoveSplineFlag::Animation disables falling or parabolic movement
else if (splineflags.parabolic)
computeParabolicElevation(c.z);
else if (splineflags.falling)
computeFallElevation(c.z);
if (splineflags.done && splineflags.isFacing())
{
if (splineflags.final_angle)
c.orientation = facing.angle;
else if (splineflags.final_point)
c.orientation = atan2(facing.f.y-c.y, facing.f.x-c.x);
//nothing to do for MoveSplineFlag::Final_Target flag
}
else
{
if (!splineflags.hasFlag(MoveSplineFlag::OrientationFixed|MoveSplineFlag::Falling))
{
Vector3 hermite;
spline.evaluate_derivative(point_Idx,u,hermite);
c.orientation = atan2(hermite.y, hermite.x);
}
if (splineflags.orientationInversed)
c.orientation = -c.orientation;
}
return c;
}
void MoveSpline::computeParabolicElevation(float& el) const
{
if (time_passed > effect_start_time)
{
float t_passedf = MSToSec(time_passed - effect_start_time);
float t_durationf = MSToSec(Duration() - effect_start_time); //client use not modified duration here
// -a*x*x + bx + c:
//(dur * v3->z_acceleration * dt)/2 - (v3->z_acceleration * dt * dt)/2 + Z;
el += (t_durationf - t_passedf) * 0.5f * vertical_acceleration * t_passedf;
}
}
void MoveSpline::computeFallElevation(float& el) const
{
float z_now = spline.getPoint(spline.first()).z - Movement::computeFallElevation(MSToSec(time_passed));
float final_z = FinalDestination().z;
if (z_now < final_z)
el = final_z;
else
el = z_now;
}
inline uint32 computeDuration(float length, float velocity)
{
return SecToMS(length / velocity);
}
struct FallInitializer
{
FallInitializer(float _start_elevation) : start_elevation(_start_elevation) {}
float start_elevation;
inline int32 operator()(Spline<int32>& s, int32 i)
{
return Movement::computeFallTime(start_elevation - s.getPoint(i+1).z,false) * 1000.f;
}
};
enum{
minimal_duration = 1,
};
struct CommonInitializer
{
CommonInitializer(float _velocity) : velocityInv(1000.f/_velocity), time(minimal_duration) {}
float velocityInv;
int32 time;
inline int32 operator()(Spline<int32>& s, int32 i)
{
time += (s.SegLength(i) * velocityInv);
return time;
}
};
void MoveSpline::init_spline(const MoveSplineInitArgs& args)
{
const SplineBase::EvaluationMode modes[2] = {SplineBase::ModeLinear,SplineBase::ModeCatmullrom};
if (args.flags.cyclic)
{
uint32 cyclic_point = 0;
// MoveSplineFlag::Enter_Cycle support dropped
//if (splineflags & SPLINEFLAG_ENTER_CYCLE)
//cyclic_point = 1; // shouldn't be modified, came from client
spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point);
}
else
{
spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()]);
}
// init spline timestamps
if (splineflags.falling)
{
FallInitializer init(spline.getPoint(spline.first()).z);
spline.initLengths(init);
}
else
{
CommonInitializer init(args.velocity);
spline.initLengths(init);
}
// TODO: what to do in such cases? problem is in input data (all points are at same coords)
if (spline.length() < minimal_duration)
{
sLog->outError("MoveSpline::init_spline: zero length spline, wrong input data?");
spline.set_length(spline.last(), spline.isCyclic() ? 1000 : 1);
}
point_Idx = spline.first();
}
void MoveSpline::Initialize(const MoveSplineInitArgs& args)
{
splineflags = args.flags;
facing = args.facing;
m_Id = args.splineId;
point_Idx_offset = args.path_Idx_offset;
initialOrientation = args.initialOrientation;
time_passed = 0;
vertical_acceleration = 0.f;
effect_start_time = 0;
init_spline(args);
// init parabolic / animation
// spline initialized, duration known and i able to compute parabolic acceleration
if (args.flags & (MoveSplineFlag::Parabolic | MoveSplineFlag::Animation))
{
effect_start_time = Duration() * args.time_perc;
if (args.flags.parabolic && effect_start_time < Duration())
{
float f_duration = MSToSec(Duration() - effect_start_time);
vertical_acceleration = args.parabolic_amplitude * 8.f / (f_duration * f_duration);
}
}
}
MoveSpline::MoveSpline() : m_Id(0), time_passed(0),
vertical_acceleration(0.f), effect_start_time(0), point_Idx(0), point_Idx_offset(0), initialOrientation(0.f)
{
splineflags.done = true;
}
/// ============================================================================================
bool MoveSplineInitArgs::Validate() const
{
#define CHECK(exp) \
if (!(exp))\
{\
sLog->outError("MoveSplineInitArgs::Validate: expression '%s' failed", #exp);\
return false;\
}
CHECK(path.size() > 1);
CHECK(velocity > 0.f);
CHECK(time_perc >= 0.f && time_perc <= 1.f);
//CHECK(_checkPathBounds());
return true;
#undef CHECK
}
// MONSTER_MOVE packet format limitation for not CatmullRom movement:
// each vertex offset packed into 11 bytes
bool MoveSplineInitArgs::_checkPathBounds() const
{
if (!(flags & MoveSplineFlag::Mask_CatmullRom) && path.size() > 2)
{
enum{
MAX_OFFSET = (1 << 11) / 2,
};
Vector3 middle = (path.front()+path.back()) / 2;
Vector3 offset;
for (uint32 i = 1; i < path.size()-1; ++i)
{
offset = path[i] - middle;
if (fabs(offset.x) >= MAX_OFFSET || fabs(offset.y) >= MAX_OFFSET || fabs(offset.z) >= MAX_OFFSET)
{
sLog->outError("MoveSplineInitArgs::_checkPathBounds check failed");
return false;
}
}
}
return true;
}
/// ============================================================================================
MoveSpline::UpdateResult MoveSpline::_updateState(int32& ms_time_diff)
{
if (Finalized())
{
ms_time_diff = 0;
return Result_Arrived;
}
UpdateResult result = Result_None;
int32 minimal_diff = std::min(ms_time_diff, segment_time_elapsed());
ASSERT(minimal_diff >= 0);
time_passed += minimal_diff;
ms_time_diff -= minimal_diff;
if (time_passed >= next_timestamp())
{
++point_Idx;
if (point_Idx < spline.last())
{
result = Result_NextSegment;
}
else
{
if (spline.isCyclic())
{
point_Idx = spline.first();
time_passed = time_passed % Duration();
result = Result_NextSegment;
}
else
{
_Finalize();
ms_time_diff = 0;
result = Result_Arrived;
}
}
}
return result;
}
std::string MoveSpline::ToString() const
{
std::stringstream str;
str << "MoveSpline" << std::endl;
str << "spline Id: " << GetId() << std::endl;
str << "flags: " << splineflags.ToString() << std::endl;
if (splineflags.final_angle)
str << "facing angle: " << facing.angle;
else if (splineflags.final_target)
str << "facing target: " << facing.target;
else if(splineflags.final_point)
str << "facing point: " << facing.f.x << " " << facing.f.y << " " << facing.f.z;
str << std::endl;
str << "time passed: " << time_passed << std::endl;
str << "total time: " << Duration() << std::endl;
str << "spline point Id: " << point_Idx << std::endl;
str << "path point Id: " << currentPathIdx() << std::endl;
str << spline.ToString();
return str.str();
}
void MoveSpline::_Finalize()
{
splineflags.done = true;
point_Idx = spline.last() - 1;
time_passed = Duration();
}
int32 MoveSpline::currentPathIdx() const
{
int32 point = point_Idx_offset + point_Idx - spline.first() + (int)Finalized();
if (isCyclic())
point = point % (spline.last()-spline.first());
return point;
}
}
@@ -0,0 +1,127 @@
/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TRINITYSERVER_MOVEPLINE_H
#define TRINITYSERVER_MOVEPLINE_H
#include "Spline.h"
#include "MoveSplineInitArgs.h"
namespace Movement
{
struct Location : public Vector3
{
Location() : orientation(0) {}
Location(float x, float y, float z, float o) : Vector3(x,y,z), orientation(o) {}
Location(const Vector3& v) : Vector3(v), orientation(0) {}
Location(const Vector3& v, float o) : Vector3(v), orientation(o) {}
float orientation;
};
// MoveSpline represents smooth catmullrom or linear curve and point that moves belong it
// curve can be cyclic - in this case movement will be cyclic
// point can have vertical acceleration motion componemt(used in fall, parabolic movement)
class MoveSpline
{
public:
typedef Spline<int32> MySpline;
enum UpdateResult{
Result_None = 0x01,
Result_Arrived = 0x02,
Result_NextCycle = 0x04,
Result_NextSegment = 0x08,
};
#pragma region fields
friend class PacketBuilder;
protected:
MySpline spline;
FacingInfo facing;
uint32 m_Id;
MoveSplineFlag splineflags;
int32 time_passed;
// currently duration mods are unused, but its _currently_
//float duration_mod;
//float duration_mod_next;
float vertical_acceleration;
float initialOrientation;
int32 effect_start_time;
int32 point_Idx;
int32 point_Idx_offset;
void init_spline(const MoveSplineInitArgs& args);
protected:
const MySpline::ControlArray& getPath() const { return spline.getPoints();}
void computeParabolicElevation(float& el) const;
void computeFallElevation(float& el) const;
UpdateResult _updateState(int32& ms_time_diff);
int32 next_timestamp() const { return spline.length(point_Idx+1);}
int32 segment_time_elapsed() const { return next_timestamp()-time_passed;}
int32 Duration() const { return spline.length();}
int32 timeElapsed() const { return Duration() - time_passed;}
int32 timePassed() const { return time_passed;}
public:
const MySpline& _Spline() const { return spline;}
int32 _currentSplineIdx() const { return point_Idx;}
void _Finalize();
void _Interrupt() { splineflags.done = true;}
#pragma endregion
public:
void Initialize(const MoveSplineInitArgs&);
bool Initialized() const { return !spline.empty();}
explicit MoveSpline();
template<class UpdateHandler>
void updateState(int32 difftime, UpdateHandler& handler)
{
ASSERT(Initialized());
do
handler(_updateState(difftime));
while(difftime > 0);
}
void updateState(int32 difftime)
{
ASSERT(Initialized());
do _updateState(difftime);
while(difftime > 0);
}
Location ComputePosition() const;
uint32 GetId() const { return m_Id;}
bool Finalized() const { return splineflags.done; }
bool isCyclic() const { return splineflags.cyclic;}
const Vector3 FinalDestination() const { return Initialized() ? spline.getPoint(spline.last()) : Vector3();}
const Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx+1) : Vector3();}
int32 currentPathIdx() const;
std::string ToString() const;
};
}
#endif // TRINITYSERVER_MOVEPLINE_H
@@ -0,0 +1,143 @@
/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TRINITYSERVER_MOVESPLINEFLAG_H
#define TRINITYSERVER_MOVESPLINEFLAG_H
#include "MovementTypedefs.h"
#include <string>
namespace Movement
{
#if defined( __GNUC__ )
#pragma pack(1)
#else
#pragma pack(push,1)
#endif
class MoveSplineFlag
{
public:
enum eFlags{
None = 0x00000000,
// x00-xFF(first byte) used as animation Ids storage in pair with Animation flag
Done = 0x00000100,
Falling = 0x00000200, // Affects elevation computation, can't be combined with Parabolic flag
No_Spline = 0x00000400,
Parabolic = 0x00000800, // Affects elevation computation, can't be combined with Falling flag
Walkmode = 0x00001000,
Flying = 0x00002000, // Smooth movement(Catmullrom interpolation mode), flying animation
OrientationFixed = 0x00004000, // Model orientation fixed
Final_Point = 0x00008000,
Final_Target = 0x00010000,
Final_Angle = 0x00020000,
Catmullrom = 0x00040000, // Used Catmullrom interpolation mode
Cyclic = 0x00080000, // Movement by cycled spline
Enter_Cycle = 0x00100000, // Everytimes appears with cyclic flag in monster move packet, erases first spline vertex after first cycle done
Animation = 0x00200000, // Plays animation after some time passed
Frozen = 0x00400000, // Will never arrive
Unknown5 = 0x00800000,
Unknown6 = 0x01000000,
Unknown7 = 0x02000000,
Unknown8 = 0x04000000,
OrientationInversed = 0x08000000,
Unknown10 = 0x10000000,
Unknown11 = 0x20000000,
Unknown12 = 0x40000000,
Unknown13 = 0x80000000,
// Masks
Mask_Final_Facing = Final_Point | Final_Target | Final_Angle,
// animation ids stored here, see AnimType enum, used with Animation flag
Mask_Animations = 0xFF,
// flags that shouldn't be appended into SMSG_MONSTER_MOVE\SMSG_MONSTER_MOVE_TRANSPORT packet, should be more probably
Mask_No_Monster_Move = Mask_Final_Facing | Mask_Animations | Done,
// CatmullRom interpolation mode used
Mask_CatmullRom = Flying | Catmullrom,
// Unused, not suported flags
Mask_Unused = No_Spline|Enter_Cycle|Frozen|Unknown5|Unknown6|Unknown7|Unknown8|Unknown10|Unknown11|Unknown12|Unknown13,
};
inline uint32& raw() { return (uint32&)*this;}
inline const uint32& raw() const { return (const uint32&)*this;}
MoveSplineFlag() { raw() = 0; }
MoveSplineFlag(uint32 f) { raw() = f; }
MoveSplineFlag(const MoveSplineFlag& f) { raw() = f.raw(); }
// Constant interface
bool isSmooth() const { return raw() & Mask_CatmullRom;}
bool isLinear() const { return !isSmooth();}
bool isFacing() const { return raw() & Mask_Final_Facing;}
uint8 getAnimationId() const { return animId;}
bool hasAllFlags(uint32 f) const { return (raw() & f) == f;}
bool hasFlag(uint32 f) const { return (raw() & f) != 0;}
uint32 operator & (uint32 f) const { return (raw() & f);}
uint32 operator | (uint32 f) const { return (raw() | f);}
std::string ToString() const;
// Not constant interface
void operator &= (uint32 f) { raw() &= f;}
void operator |= (uint32 f) { raw() |= f;}
void EnableAnimation(uint8 anim) { raw() = raw() & ~(Mask_Animations|Falling|Parabolic) | Animation|anim;}
void EnableParabolic() { raw() = raw() & ~(Mask_Animations|Falling|Animation) | Parabolic;}
void EnableFalling() { raw() = raw() & ~(Mask_Animations|Parabolic|Animation) | Falling;}
void EnableFlying() { raw() = raw() & ~Catmullrom | Flying; }
void EnableCatmullRom() { raw() = raw() & ~Flying | Catmullrom; }
void EnableFacingPoint() { raw() = raw() & ~Mask_Final_Facing | Final_Point;}
void EnableFacingAngle() { raw() = raw() & ~Mask_Final_Facing | Final_Angle;}
void EnableFacingTarget() { raw() = raw() & ~Mask_Final_Facing | Final_Target;}
uint8 animId : 8;
bool done : 1;
bool falling : 1;
bool no_spline : 1;
bool parabolic : 1;
bool walkmode : 1;
bool flying : 1;
bool orientationFixed : 1;
bool final_point : 1;
bool final_target : 1;
bool final_angle : 1;
bool catmullrom : 1;
bool cyclic : 1;
bool enter_cycle : 1;
bool animation : 1;
bool frozen : 1;
bool unknown5 : 1;
bool unknown6 : 1;
bool unknown7 : 1;
bool unknown8 : 1;
bool orientationInversed : 1;
bool unknown10 : 1;
bool unknown11 : 1;
bool unknown12 : 1;
bool unknown13 : 1;
};
#if defined( __GNUC__ )
#pragma pack()
#else
#pragma pack(pop)
#endif
}
#endif // TRINITYSERVER_MOVESPLINEFLAG_H
@@ -0,0 +1,119 @@
/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#include "MovementPacketBuilder.h"
#include "Unit.h"
namespace Movement
{
UnitMoveType SelectSpeedType(uint32 moveFlags)
{
if (moveFlags & MOVEMENTFLAG_FLYING)
{
if ( moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.flight >= speed_obj.flight_back*/ )
return MOVE_FLIGHT_BACK;
else
return MOVE_FLIGHT;
}
else if (moveFlags & MOVEMENTFLAG_SWIMMING)
{
if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.swim >= speed_obj.swim_back*/)
return MOVE_SWIM_BACK;
else
return MOVE_SWIM;
}
else if (moveFlags & MOVEMENTFLAG_WALKING)
{
//if ( speed_obj.run > speed_obj.walk )
return MOVE_WALK;
}
else if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.run >= speed_obj.run_back*/)
return MOVE_RUN_BACK;
return MOVE_RUN;
}
void MoveSplineInit::Launch()
{
MoveSpline& move_spline = *unit.movespline;
Location real_position(unit.GetPositionX(),unit.GetPositionY(),unit.GetPositionZ(),unit.GetOrientation());
// there is a big chane that current position is unknown if current state is not finalized, need compute it
// this also allows calculate spline position and update map position in much greater intervals
if (!move_spline.Finalized())
real_position = move_spline.ComputePosition();
if (args.path.empty())
{
// should i do the things that user should do?
MoveTo(real_position);
}
// corrent first vertex
args.path[0] = real_position;
args.initialOrientation = real_position.orientation;
uint32 moveFlags = unit.m_movementInfo.GetMovementFlags();
if (args.flags.walkmode)
moveFlags |= MOVEMENTFLAG_WALKING;
else
moveFlags &= ~MOVEMENTFLAG_WALKING;
moveFlags |= (MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD);
if (args.velocity == 0.f)
args.velocity = unit.GetSpeed(SelectSpeedType(moveFlags));
if (!args.Validate())
return;
if (moveFlags & MOVEMENTFLAG_ROOT)
moveFlags &= ~MOVEMENTFLAG_MASK_MOVING;
unit.m_movementInfo.SetMovementFlags((MovementFlags)moveFlags);
move_spline.Initialize(args);
WorldPacket data(SMSG_MONSTER_MOVE, 64);
data.append(unit.GetPackGUID());
PacketBuilder::WriteMonsterMove(move_spline, data);
unit.SendMessageToSet(&data,true);
}
MoveSplineInit::MoveSplineInit(Unit& m) : unit(m)
{
// mix existing state into new
args.flags.walkmode = unit.m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING);
args.flags.flying = unit.m_movementInfo.HasMovementFlag((MovementFlags)(MOVEMENTFLAG_FLYING|MOVEMENTFLAG_LEVITATING));
}
void MoveSplineInit::SetFacing(const Unit * target)
{
args.flags.EnableFacingTarget();
target->GetUInt64Value(OBJECT_FIELD_GUID);
//args.facing.target = target->GetObjectGuid().GetRawValue();
args.facing.target = target->GetUInt64Value(OBJECT_FIELD_GUID);
}
void MoveSplineInit::SetFacing(float angle)
{
args.facing.angle = G3D::wrap(angle, 0.f, (float)G3D::twoPi());
args.flags.EnableFacingAngle();
}
}
@@ -0,0 +1,170 @@
/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TRINITYSERVER_MOVESPLINEINIT_H
#define TRINITYSERVER_MOVESPLINEINIT_H
#include "MoveSplineInitArgs.h"
class Unit;
namespace Movement
{
enum AnimType
{
ToGround = 0, // 460 = ToGround, index of AnimationData.dbc
FlyToFly = 1, // 461 = FlyToFly?
ToFly = 2, // 458 = ToFly
FlyToGround = 3, // 463 = FlyToGround
};
/* Initializes and launches spline movement
*/
class MoveSplineInit
{
public:
explicit MoveSplineInit(Unit& m);
/* Final pass of initialization that launches spline movement.
*/
void Launch();
/* Adds movement by parabolic trajectory
* @param amplitude - the maximum height of parabola, value could be negative and positive
* @param start_time - delay between movement starting time and beginning to move by parabolic trajectory
* can't be combined with final animation
*/
void SetParabolic(float amplitude, float start_time);
/* Plays animation after movement done
* can't be combined with parabolic movement
*/
void SetAnimation(AnimType anim);
/* Adds final facing animation
* sets unit's facing to specified point/angle after all path done
* you can have only one final facing: previous will be overriden
*/
void SetFacing(float angle);
void SetFacing(Vector3 const& point);
void SetFacing(const Unit * target);
/* Initializes movement by path
* @param path - array of points, shouldn't be empty
* @param pointId - Id of fisrt point of the path. Example: when third path point will be done it will notify that pointId + 3 done
*/
void MovebyPath(const PointsArray& path, int32 pointId = 0);
/* Initializes simple A to B mition, A is current unit's position, B is destination
*/
void MoveTo(const Vector3& destination);
void MoveTo(float x, float y, float z);
/* Sets Id of fisrt point of the path. When N-th path point will be done ILisener will notify that pointId + N done
* Needed for waypoint movement where path splitten into parts
*/
void SetFirstPointId(int32 pointId) { args.path_Idx_offset = pointId; }
/* Enables CatmullRom spline interpolation mode(makes path smooth)
* if not enabled linear spline mode will be choosen. Disabled by default
*/
void SetSmooth();
/* Enables CatmullRom spline interpolation mode, enables flying animation. Disabled by default
*/
void SetFly();
/* Enables walk mode. Disabled by default
*/
void SetWalk(bool enable);
/* Makes movement cyclic. Disabled by default
*/
void SetCyclic();
/* Enables falling mode. Disabled by default
*/
void SetFall();
/* Inverses unit model orientation. Disabled by default
*/
void SetOrientationInversed();
/* Fixes unit's model rotation. Disabled by default
*/
void SetOrientationFixed(bool enable);
/* Sets the velocity (in case you want to have custom movement velocity)
* if no set, speed will be selected based on unit's speeds and current movement mode
* Has no effect if falling mode enabled
* velocity shouldn't be negative
*/
void SetVelocity(float velocity);
PointsArray& Path() { return args.path; }
protected:
MoveSplineInitArgs args;
Unit& unit;
};
inline void MoveSplineInit::SetFly() { args.flags.EnableFlying();}
inline void MoveSplineInit::SetWalk(bool enable) { args.flags.walkmode = enable;}
inline void MoveSplineInit::SetSmooth() { args.flags.EnableCatmullRom();}
inline void MoveSplineInit::SetCyclic() { args.flags.cyclic = true;}
inline void MoveSplineInit::SetFall() { args.flags.EnableFalling();}
inline void MoveSplineInit::SetVelocity(float vel){ args.velocity = vel;}
inline void MoveSplineInit::SetOrientationInversed() { args.flags.orientationInversed = true;}
inline void MoveSplineInit::SetOrientationFixed(bool enable) { args.flags.orientationFixed = enable;}
inline void MoveSplineInit::MovebyPath(const PointsArray& controls, int32 path_offset)
{
args.path_Idx_offset = path_offset;
args.path.assign(controls.begin(),controls.end());
}
inline void MoveSplineInit::MoveTo(float x, float y, float z)
{
Vector3 v(x,y,z);
MoveTo(v);
}
inline void MoveSplineInit::MoveTo(const Vector3& dest)
{
args.path_Idx_offset = 0;
args.path.resize(2);
args.path[1] = dest;
}
inline void MoveSplineInit::SetParabolic(float amplitude, float time_shift)
{
args.time_perc = time_shift;
args.parabolic_amplitude = amplitude;
args.flags.EnableParabolic();
}
inline void MoveSplineInit::SetAnimation(AnimType anim)
{
args.time_perc = 0.f;
args.flags.EnableAnimation((uint8)anim);
}
inline void MoveSplineInit::SetFacing(Vector3 const& spot)
{
args.facing.f.x = spot.x;
args.facing.f.y = spot.y;
args.facing.f.z = spot.z;
args.flags.EnableFacingPoint();
}
}
#endif // TRINITYSERVER_MOVESPLINEINIT_H
@@ -0,0 +1,67 @@
/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TRINITYSERVER_MOVESPLINEINIT_ARGS_H
#define TRINITYSERVER_MOVESPLINEINIT_ARGS_H
#include "MoveSplineFlag.h"
#include <G3D/Vector3.h>
namespace Movement
{
typedef std::vector<Vector3> PointsArray;
union FacingInfo
{
struct{
float x,y,z;
}f;
uint64 target;
float angle;
FacingInfo(float o) : angle(o) {}
FacingInfo(uint64 t) : target(t) {}
FacingInfo() {}
};
struct MoveSplineInitArgs
{
MoveSplineInitArgs(size_t path_capacity = 16) : path_Idx_offset(0),
velocity(0.f), parabolic_amplitude(0.f), time_perc(0.f), splineId(0), initialOrientation(0.f)
{
path.reserve(path_capacity);
}
PointsArray path;
FacingInfo facing;
MoveSplineFlag flags;
int32 path_Idx_offset;
float velocity;
float parabolic_amplitude;
float time_perc;
uint32 splineId;
float initialOrientation;
/** Returns true to show that the arguments were configured correctly and MoveSpline initialization will succeed. */
bool Validate() const;
private:
bool _checkPathBounds() const;
};
}
#endif // TRINITYSERVER_MOVESPLINEINIT_ARGS_H
@@ -0,0 +1,188 @@
/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "MovementPacketBuilder.h"
#include "MoveSpline.h"
#include "WorldPacket.h"
namespace Movement
{
inline void operator << (ByteBuffer& b, const Vector3& v)
{
b << v.x << v.y << v.z;
}
inline void operator >> (ByteBuffer& b, Vector3& v)
{
b >> v.x >> v.y >> v.z;
}
enum MonsterMoveType
{
MonsterMoveNormal = 0,
MonsterMoveStop = 1,
MonsterMoveFacingSpot = 2,
MonsterMoveFacingTarget = 3,
MonsterMoveFacingAngle = 4
};
void PacketBuilder::WriteCommonMonsterMovePart(const MoveSpline& move_spline, WorldPacket& data)
{
MoveSplineFlag splineflags = move_spline.splineflags;
/*if (mov.IsBoarded())
{
data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT);
data << mov.GetTransport()->Owner.GetPackGUID();
data << int8(mov.m_unused.transport_seat);
}*/
data << uint8(0);
data << move_spline.spline.getPoint(move_spline.spline.first());
data << move_spline.GetId();
switch(splineflags & MoveSplineFlag::Mask_Final_Facing)
{
default:
data << uint8(MonsterMoveNormal);
break;
case MoveSplineFlag::Final_Target:
data << uint8(MonsterMoveFacingTarget);
data << move_spline.facing.target;
break;
case MoveSplineFlag::Final_Angle:
data << uint8(MonsterMoveFacingAngle);
data << move_spline.facing.angle;
break;
case MoveSplineFlag::Final_Point:
data << uint8(MonsterMoveFacingSpot);
data << move_spline.facing.f.x << move_spline.facing.f.y << move_spline.facing.f.z;
break;
}
// add fake Enter_Cycle flag - needed for client-side cyclic movement (client will erase first spline vertex after first cycle done)
splineflags.enter_cycle = move_spline.isCyclic();
data << uint32(splineflags & ~MoveSplineFlag::Mask_No_Monster_Move);
if (splineflags.animation)
{
data << splineflags.getAnimationId();
data << move_spline.effect_start_time;
}
data << move_spline.Duration();
if (splineflags.parabolic)
{
data << move_spline.vertical_acceleration;
data << move_spline.effect_start_time;
}
}
void WriteLinearPath(const Spline<int32>& spline, ByteBuffer& data)
{
uint32 last_idx = spline.getPointCount() - 3;
const Vector3 * real_path = &spline.getPoint(1);
data << last_idx;
data << real_path[last_idx]; // destination
if (last_idx > 1)
{
Vector3 middle = (real_path[0] + real_path[last_idx]) / 2.f;
Vector3 offset;
// first and last points already appended
for(uint32 i = 1; i < last_idx; ++i)
{
offset = middle - real_path[i];
data.appendPackXYZ(offset.x, offset.y, offset.z);
}
}
}
void WriteCatmullRomPath(const Spline<int32>& spline, ByteBuffer& data)
{
uint32 count = spline.getPointCount() - 3;
data << count;
data.append<Vector3>(&spline.getPoint(2), count);
}
void WriteCatmullRomCyclicPath(const Spline<int32>& spline, ByteBuffer& data)
{
uint32 count = spline.getPointCount() - 3;
data << uint32(count + 1);
data << spline.getPoint(1); // fake point, client will erase it from the spline after first cycle done
data.append<Vector3>(&spline.getPoint(1), count);
}
void PacketBuilder::WriteMonsterMove(const MoveSpline& move_spline, WorldPacket& data)
{
WriteCommonMonsterMovePart(move_spline, data);
const Spline<int32>& spline = move_spline.spline;
MoveSplineFlag splineflags = move_spline.splineflags;
if (splineflags & MoveSplineFlag::Mask_CatmullRom)
{
if (splineflags.cyclic)
WriteCatmullRomCyclicPath(spline, data);
else
WriteCatmullRomPath(spline, data);
}
else
WriteLinearPath(spline, data);
}
void PacketBuilder::WriteCreate(const MoveSpline& move_spline, ByteBuffer& data)
{
//WriteClientStatus(mov,data);
//data.append<float>(&mov.m_float_values[SpeedWalk], SpeedMaxCount);
//if (mov.SplineEnabled())
{
MoveSplineFlag splineFlags = move_spline.splineflags;
data << splineFlags.raw();
if (splineFlags.final_angle)
{
data << move_spline.facing.angle;
}
else if (splineFlags.final_target)
{
data << move_spline.facing.target;
}
else if(splineFlags.final_point)
{
data << move_spline.facing.f.x << move_spline.facing.f.y << move_spline.facing.f.z;
}
data << move_spline.timePassed();
data << move_spline.Duration();
data << move_spline.GetId();
data << float(1.f); // splineInfo.duration_mod; added in 3.1
data << float(1.f); // splineInfo.duration_mod_next; added in 3.1
data << move_spline.vertical_acceleration; // added in 3.1
data << move_spline.effect_start_time; // added in 3.1
uint32 nodes = move_spline.getPath().size();
data << nodes;
data.append<Vector3>(&move_spline.getPath()[0], nodes);
data << uint8(move_spline.spline.mode()); // added in 3.1
data << (move_spline.isCyclic() ? Vector3::zero() : move_spline.FinalDestination());
}
}
}
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TRINITYSERVER_PACKET_BUILDER_H
#define TRINITYSERVER_PACKET_BUILDER_H
class ByteBuffer;
class WorldPacket;
namespace Movement
{
class MoveSpline;
class PacketBuilder
{
static void WriteCommonMonsterMovePart(const MoveSpline& mov, WorldPacket& data);
public:
static void WriteMonsterMove(const MoveSpline& mov, WorldPacket& data);
static void WriteCreate(const MoveSpline& mov, ByteBuffer& data);
};
}
#endif // TRINITYSERVER_PACKET_BUILDER_H
@@ -0,0 +1,81 @@
/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TRINITYSERVER_TYPEDEFS_H
#define TRINITYSERVER_TYPEDEFS_H
#include "Common.h"
namespace G3D
{
class Vector2;
class Vector3;
class Vector4;
}
namespace Movement
{
using G3D::Vector2;
using G3D::Vector3;
using G3D::Vector4;
inline uint32 SecToMS(float sec)
{
return static_cast<uint32>(sec * 1000.f);
}
inline float MSToSec(uint32 ms)
{
return ms / 1000.f;
}
#ifndef static_assert
#define CONCAT(x, y) CONCAT1 (x, y)
#define CONCAT1(x, y) x##y
#define static_assert(expr, msg) typedef char CONCAT(static_assert_failed_at_line_, __LINE__) [(expr) ? 1 : -1]
#endif
template<class T, T limit>
class counter
{
public:
counter() { init();}
void Increase()
{
if (m_counter == limit)
init();
else
++m_counter;
}
T NewId() { Increase(); return m_counter;}
T getCurrent() const { return m_counter;}
private:
void init() { m_counter = 0; }
T m_counter;
};
typedef counter<uint32, 0xFFFFFFFF> UInt32Counter;
extern double gravity;
extern float computeFallElevation(float t_passed, bool isSafeFall, float start_velocity);
}
#endif // TRINITYSERVER_TYPEDEFS_H
@@ -0,0 +1,208 @@
/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "MoveSplineFlag.h"
#include <math.h>
#include <string>
namespace Movement
{
double gravity = 19.29110527038574;
/// Velocity bounds that makes fall speed limited
float terminalVelocity = 60.148003f;
float terminalSavefallVelocity = 7.f;
const float terminal_length = float(terminalVelocity * terminalVelocity) / (2.f * gravity);
const float terminal_savefall_length = (terminalSavefallVelocity * terminalSavefallVelocity) / (2.f * gravity);
const float terminalFallTime = float(terminalVelocity/gravity); // the time that needed to reach terminalVelocity
float computeFallTime(float path_length, bool isSafeFall)
{
if (path_length < 0.f)
return 0.f;
float time;
if ( isSafeFall )
{
if (path_length >= terminal_savefall_length)
time = (path_length - terminal_savefall_length)/terminalSavefallVelocity + terminalSavefallVelocity/gravity;
else
time = sqrtf(2.f * path_length/gravity);
}
else
{
if (path_length >= terminal_length)
time = (path_length - terminal_length)/terminalVelocity + terminalFallTime;
else
time = sqrtf(2.f * path_length/gravity);
}
return time;
}
float computeFallElevation(float t_passed, bool isSafeFall, float start_velocity)
{
float termVel;
float result;
if ( isSafeFall )
termVel = terminalSavefallVelocity;
else
termVel = terminalVelocity;
if ( start_velocity > termVel )
start_velocity = termVel;
float terminal_time = terminalFallTime - start_velocity / gravity; // the time that needed to reach terminalVelocity
if ( t_passed > terminal_time )
{
result = terminalVelocity*(t_passed - terminal_time) +
start_velocity*terminal_time + gravity*terminal_time*terminal_time*0.5f;
}
else
result = t_passed * (start_velocity + t_passed * gravity * 0.5f);
return result;
}
float computeFallElevation(float t_passed)
{
float result;
if (t_passed > terminalFallTime)
{
//result = terminalVelocity * (t_passed - terminal_time) + gravity*terminal_time*terminal_time*0.5f;
// simplified view:
result = terminalVelocity * (t_passed - terminalFallTime) + terminal_length;
}
else
result = t_passed * t_passed * gravity * 0.5f;
return result;
}
#define STR(x) #x
const char * g_MovementFlag_names[]=
{
STR(Forward ),// 0x00000001,
STR(Backward ),// 0x00000002,
STR(Strafe_Left ),// 0x00000004,
STR(Strafe_Right ),// 0x00000008,
STR(Turn_Left ),// 0x00000010,
STR(Turn_Right ),// 0x00000020,
STR(Pitch_Up ),// 0x00000040,
STR(Pitch_Down ),// 0x00000080,
STR(Walk ),// 0x00000100, // Walking
STR(Ontransport ),// 0x00000200,
STR(Levitation ),// 0x00000400,
STR(Root ),// 0x00000800,
STR(Falling ),// 0x00001000,
STR(Fallingfar ),// 0x00002000,
STR(Pendingstop ),// 0x00004000,
STR(PendingSTRafestop ),// 0x00008000,
STR(Pendingforward ),// 0x00010000,
STR(Pendingbackward ),// 0x00020000,
STR(PendingSTRafeleft ),// 0x00040000,
STR(PendingSTRaferight ),// 0x00080000,
STR(Pendingroot ),// 0x00100000,
STR(Swimming ),// 0x00200000, // Appears With Fly Flag Also
STR(Ascending ),// 0x00400000, // Swim Up Also
STR(Descending ),// 0x00800000, // Swim Down Also
STR(Can_Fly ),// 0x01000000, // Can Fly In 3.3?
STR(Flying ),// 0x02000000, // Actual Flying Mode
STR(Spline_Elevation ),// 0x04000000, // Used For Flight Paths
STR(Spline_Enabled ),// 0x08000000, // Used For Flight Paths
STR(Waterwalking ),// 0x10000000, // Prevent Unit From Falling Through Water
STR(Safe_Fall ),// 0x20000000, // Active Rogue Safe Fall Spell (Passive)
STR(Hover ),// 0x40000000
STR(Unknown13 ),// 0x80000000
STR(Unk1 ),
STR(Unk2 ),
STR(Unk3 ),
STR(Fullspeedturning ),
STR(Fullspeedpitching ),
STR(Allow_Pitching ),
STR(Unk4 ),
STR(Unk5 ),
STR(Unk6 ),
STR(Unk7 ),
STR(Interp_Move ),
STR(Interp_Turning ),
STR(Interp_Pitching ),
STR(Unk8 ),
STR(Unk9 ),
STR(Unk10 ),
};
const char * g_SplineFlag_names[32]=
{
STR(AnimBit1 ),// 0x00000001,
STR(AnimBit2 ),// 0x00000002,
STR(AnimBit3 ),// 0x00000004,
STR(AnimBit4 ),// 0x00000008,
STR(AnimBit5 ),// 0x00000010,
STR(AnimBit6 ),// 0x00000020,
STR(AnimBit7 ),// 0x00000040,
STR(AnimBit8 ),// 0x00000080,
STR(Done ),// 0x00000100,
STR(Falling ),// 0x00000200, // Not Compartible With Trajectory Movement
STR(No_Spline ),// 0x00000400,
STR(Trajectory ),// 0x00000800, // Not Compartible With Fall Movement
STR(Walkmode ),// 0x00001000,
STR(Flying ),// 0x00002000, // Smooth Movement(Catmullrom Interpolation Mode), Flying Animation
STR(Knockback ),// 0x00004000, // Model Orientation Fixed
STR(Final_Point ),// 0x00008000,
STR(Final_Target ),// 0x00010000,
STR(Final_Angle ),// 0x00020000,
STR(Catmullrom ),// 0x00040000, // Used Catmullrom Interpolation Mode
STR(Cyclic ),// 0x00080000, // Movement By Cycled Spline
STR(Enter_Cycle ),// 0x00100000, // Everytime Appears With Cyclic Flag In Monster Move Packet
STR(Animation ),// 0x00200000, // Animationid (0...3), Uint32 Time, Not Compartible With Trajectory And Fall Movement
STR(Unknown4 ),// 0x00400000, // Disables Movement By Path
STR(Unknown5 ),// 0x00800000,
STR(Unknown6 ),// 0x01000000,
STR(Unknown7 ),// 0x02000000,
STR(Unknown8 ),// 0x04000000,
STR(OrientationInversed ),// 0x08000000, // Appears With Runmode Flag, Nodes ),// 1, Handles Orientation
STR(Unknown10 ),// 0x10000000,
STR(Unknown11 ),// 0x20000000,
STR(Unknown12 ),// 0x40000000,
STR(Unknown13 ),// 0x80000000,
};
template<class Flags, int N>
void print_flags(Flags t, const char* (&names)[N], std::string& str)
{
for (int i = 0; i < N; ++i)
{
if ((t & (Flags)(1 << i)) && names[i] != NULL)
str.append(" ").append(names[i]);
}
}
std::string MoveSplineFlag::ToString() const
{
std::string str;
print_flags(raw(),g_SplineFlag_names,str);
return str;
}
}
+307
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
{
ASSERT(index >= index_lo && index < index_hi);
result = points[index] + (points[index+1] - points[index]) * u;
}
void SplineBase::EvaluateCatmullRom( index_type index, float t, Vector3& result) const
{
ASSERT(index >= index_lo && index < index_hi);
C_Evaluate(&points[index - 1], t, s_catmullRomCoeffs, result);
}
void SplineBase::EvaluateBezier3(index_type index, float t, Vector3& result) const
{
index *= 3u;
ASSERT(index >= index_lo && index < index_hi);
C_Evaluate(&points[index], t, s_Bezier3Coeffs, result);
}
void SplineBase::EvaluateDerivativeLinear(index_type index, float, Vector3& result) const
{
ASSERT(index >= index_lo && index < index_hi);
result = points[index+1] - points[index];
}
void SplineBase::EvaluateDerivativeCatmullRom(index_type index, float t, Vector3& result) const
{
ASSERT(index >= index_lo && index < index_hi);
C_Evaluate_Derivative(&points[index - 1], t, s_catmullRomCoeffs, result);
}
void SplineBase::EvaluateDerivativeBezier3(index_type index, float t, Vector3& result) const
{
index *= 3u;
ASSERT(index >= index_lo && index < index_hi);
C_Evaluate_Derivative(&points[index], t, s_Bezier3Coeffs, result);
}
float SplineBase::SegLengthLinear(index_type index) const
{
ASSERT(index >= index_lo && index < index_hi);
return (points[index] - points[index+1]).length();
}
float SplineBase::SegLengthCatmullRom( index_type index ) const
{
ASSERT(index >= index_lo && index < index_hi);
Vector3 curPos, nextPos;
const Vector3 * p = &points[index - 1];
curPos = nextPos = p[1];
index_type i = 1;
double length = 0;
while (i <= STEPS_PER_SEGMENT)
{
C_Evaluate(p, float(i) / float(STEPS_PER_SEGMENT), s_catmullRomCoeffs, nextPos);
length += (nextPos - curPos).length();
curPos = nextPos;
++i;
}
return length;
}
float SplineBase::SegLengthBezier3(index_type index) const
{
index *= 3u;
ASSERT(index >= index_lo && index < index_hi);
Vector3 curPos, nextPos;
const Vector3 * p = &points[index];
C_Evaluate(p, 0.f, s_Bezier3Coeffs, nextPos);
curPos = nextPos;
index_type i = 1;
double length = 0;
while (i <= STEPS_PER_SEGMENT)
{
C_Evaluate(p, float(i) / float(STEPS_PER_SEGMENT), s_Bezier3Coeffs, nextPos);
length += (nextPos - curPos).length();
curPos = nextPos;
++i;
}
return length;
}
#pragma endregion
void SplineBase::init_spline(const Vector3 * controls, index_type count, EvaluationMode m)
{
m_mode = m;
cyclic = false;
(this->*initializers[m_mode])(controls, count, cyclic, 0);
}
void SplineBase::init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point)
{
m_mode = m;
cyclic = true;
(this->*initializers[m_mode])(controls, count, cyclic, cyclic_point);
}
void SplineBase::InitLinear(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point)
{
ASSERT(count >= 2);
const int real_size = count + 1;
points.resize(real_size);
memcpy(&points[0],controls, sizeof(Vector3) * count);
// first and last two indexes are space for special 'virtual points'
// these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work
if (cyclic)
points[count] = controls[cyclic_point];
else
points[count] = controls[count-1];
index_lo = 0;
index_hi = cyclic ? count : (count - 1);
}
void SplineBase::InitCatmullRom(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point)
{
const int real_size = count + (cyclic ? (1+2) : (1+1));
points.resize(real_size);
int lo_index = 1;
int high_index = lo_index + count - 1;
memcpy(&points[lo_index],controls, sizeof(Vector3) * count);
// first and last two indexes are space for special 'virtual points'
// these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work
if (cyclic)
{
if (cyclic_point == 0)
points[0] = controls[count-1];
else
points[0] = controls[0].lerp(controls[1], -1);
points[high_index+1] = controls[cyclic_point];
points[high_index+2] = controls[cyclic_point+1];
}
else
{
points[0] = controls[0].lerp(controls[1], -1);
points[high_index+1] = controls[count-1];
}
index_lo = lo_index;
index_hi = high_index + (cyclic ? 1 : 0);
}
void SplineBase::InitBezier3(const Vector3* controls, index_type count, bool /*cyclic*/, index_type /*cyclic_point*/)
{
index_type c = count / 3u * 3u;
index_type t = c / 3u;
points.resize(c);
memcpy(&points[0],controls, sizeof(Vector3) * c);
index_lo = 0;
index_hi = t-1;
//mov_assert(points.size() % 3 == 0);
}
void SplineBase::clear()
{
index_lo = 0;
index_hi = 0;
points.clear();
}
std::string SplineBase::ToString() const
{
std::stringstream str;
const char * mode_str[ModesEnd] = {"Linear", "CatmullRom", "Bezier3", "Uninitialized"};
index_type count = this->points.size();
str << "mode: " << mode_str[mode()] << std::endl;
str << "points count: " << count << std::endl;
for (index_type i = 0; i < count; ++i)
str << "point " << i << " : " << points[i].toString() << std::endl;
return str.str();
}
}
+212
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 TRINITYSERVER_SPLINE_H
#define TRINITYSERVER_SPLINE_H
#include "MovementTypedefs.h"
#include <G3D/Vector3.h>
namespace Movement {
class SplineBase
{
public:
typedef int index_type;
typedef std::vector<Vector3> ControlArray;
enum EvaluationMode
{
ModeLinear,
ModeCatmullrom,
ModeBezier3_Unused,
UninitializedMode,
ModesEnd
};
#pragma region fields
protected:
ControlArray points;
index_type index_lo;
index_type index_hi;
uint8 m_mode;
bool cyclic;
enum{
// could be modified, affects segment length evaluation precision
// lesser value saves more performance in cost of lover precision
// minimal value is 1
// client's value is 20, blizzs use 2-3 steps to compute length
STEPS_PER_SEGMENT = 3,
};
static_assert(STEPS_PER_SEGMENT > 0, "shouldn't be lesser than 1");
protected:
void EvaluateLinear(index_type, float, Vector3&) const;
void EvaluateCatmullRom(index_type, float, Vector3&) const;
void EvaluateBezier3(index_type, float, Vector3&) const;
typedef void (SplineBase::*EvaluationMethtod)(index_type,float,Vector3&) const;
static EvaluationMethtod evaluators[ModesEnd];
void EvaluateDerivativeLinear(index_type, float, Vector3&) const;
void EvaluateDerivativeCatmullRom(index_type, float, Vector3&) const;
void EvaluateDerivativeBezier3(index_type, float, Vector3&) const;
static EvaluationMethtod derivative_evaluators[ModesEnd];
float SegLengthLinear(index_type) const;
float SegLengthCatmullRom(index_type) const;
float SegLengthBezier3(index_type) const;
typedef float (SplineBase::*SegLenghtMethtod)(index_type) const;
static SegLenghtMethtod seglengths[ModesEnd];
void InitLinear(const Vector3*, index_type, bool, index_type);
void InitCatmullRom(const Vector3*, index_type, bool, index_type);
void InitBezier3(const Vector3*, index_type, bool, index_type);
typedef void (SplineBase::*InitMethtod)(const Vector3*, index_type, bool, index_type);
static InitMethtod initializers[ModesEnd];
void UninitializedSpline() const { ASSERT(false);}
#pragma endregion
public:
explicit SplineBase() : m_mode(UninitializedMode), index_lo(0), index_hi(0), cyclic(false) {}
/** Caclulates the position for given segment Idx, and percent of segment length t
@param t - percent of segment length, assumes that t in range [0, 1]
@param Idx - spline segment index, should be in range [first, last)
*/
void evaluate_percent(index_type Idx, float u, Vector3& c) const {(this->*evaluators[m_mode])(Idx,u,c);}
/** Caclulates derivation in index Idx, and percent of segment length t
@param Idx - spline segment index, should be in range [first, last)
@param t - percent of spline segment length, assumes that t in range [0, 1]
*/
void evaluate_derivative(index_type Idx, float u, Vector3& hermite) const {(this->*derivative_evaluators[m_mode])(Idx,u,hermite);}
/** Bounds for spline indexes. All indexes should be in range [first, last). */
index_type first() const { return index_lo;}
index_type last() const { return index_hi;}
bool empty() const { return index_lo == index_hi;}
EvaluationMode mode() const { return (EvaluationMode)m_mode;}
bool isCyclic() const { return cyclic;}
const ControlArray& getPoints() const { return points;}
index_type getPointCount() const { return points.size();}
const Vector3& getPoint(index_type i) const { return points[i];}
/** Initializes spline. Don't call other methods while spline not initialized. */
void init_spline(const Vector3 * controls, index_type count, EvaluationMode m);
void init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point);
/** As i can see there are a lot of ways how spline can be initialized
would be no harm to have some custom initializers. */
template<class Init> inline void init_spline(Init& initializer)
{
initializer(m_mode,cyclic,points,index_lo,index_hi);
}
void clear();
/** Calculates distance between [i; i+1] points, assumes that index i is in bounds. */
float SegLength(index_type i) const { return (this->*seglengths[m_mode])(i);}
std::string ToString() const;
};
template<typename length_type>
class Spline : public SplineBase
{
public:
typedef length_type LengthType;
typedef std::vector<length_type> LengthArray;
#pragma region fields
protected:
LengthArray lengths;
index_type computeIndexInBounds(length_type length) const;
#pragma endregion
public:
explicit Spline(){}
/** Calculates the position for given t
@param t - percent of spline's length, assumes that t in range [0, 1]. */
void evaluate_percent(float t, Vector3 & c) const;
/** Calculates derivation for given t
@param t - percent of spline's length, assumes that t in range [0, 1]. */
void evaluate_derivative(float t, Vector3& hermite) const;
/** Calculates the position for given segment Idx, and percent of segment length t
@param t = partial_segment_length / whole_segment_length
@param Idx - spline segment index, should be in range [first, last). */
void evaluate_percent(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_percent(Idx,u,c);}
/** Caclulates derivation for index Idx, and percent of segment length t
@param Idx - spline segment index, should be in range [first, last)
@param t - percent of spline segment length, assumes that t in range [0, 1]. */
void evaluate_derivative(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_derivative(Idx,u,c);}
// Assumes that t in range [0, 1]
index_type computeIndexInBounds(float t) const;
void computeIndex(float t, index_type& out_idx, float& out_u) const;
/** Initializes spline. Don't call other methods while spline not initialized. */
void init_spline(const Vector3 * controls, index_type count, EvaluationMode m) { SplineBase::init_spline(controls,count,m);}
void init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point) { SplineBase::init_cyclic_spline(controls,count,m,cyclic_point);}
/** Initializes lengths with SplineBase::SegLength method. */
void initLengths();
/** Initializes lengths in some custom way
Note that value returned by cacher must be greater or equal to previous value. */
template<class T> inline void initLengths(T& cacher)
{
index_type i = index_lo;
lengths.resize(index_hi+1);
length_type prev_length = 0, new_length = 0;
while(i < index_hi)
{
new_length = cacher(*this, i);
lengths[++i] = new_length;
ASSERT(prev_length <= new_length);
prev_length = new_length;
}
}
/** Returns length of the whole spline. */
length_type length() const { return lengths[index_hi];}
/** Returns length between given nodes. */
length_type length(index_type first, index_type last) const { return lengths[last]-lengths[first];}
length_type length(index_type Idx) const { return lengths[Idx];}
void set_length(index_type i, length_type length) { lengths[i] = length;}
void clear();
};
}
#include "SplineImpl.h"
#endif // TRINITYSERVER_SPLINE_H
@@ -0,0 +1,97 @@
/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
namespace Movement
{
template<typename length_type> void Spline<length_type>::evaluate_percent( float t, Vector3 & c ) const
{
index_type Index;
float u;
computeIndex(t, Index, u);
evaluate_percent(Index, u, c);
}
template<typename length_type> void Spline<length_type>::evaluate_derivative(float t, Vector3& hermite) const
{
index_type Index;
float u;
computeIndex(t, Index, u);
evaluate_derivative(Index, u, hermite);
}
template<typename length_type> SplineBase::index_type Spline<length_type>::computeIndexInBounds(length_type length_) const
{
// Temporary disabled: causes infinite loop with t = 1.f
/*
index_type hi = index_hi;
index_type lo = index_lo;
index_type i = lo + (float)(hi - lo) * t;
while ((lengths[i] > length) || (lengths[i + 1] <= length))
{
if (lengths[i] > length)
hi = i - 1; // too big
else if (lengths[i + 1] <= length)
lo = i + 1; // too small
i = (hi + lo) / 2;
}*/
index_type i = index_lo;
index_type N = index_hi;
while (i+1 < N && lengths[i+1] < length_)
++i;
return i;
}
template<typename length_type> void Spline<length_type>::computeIndex(float t, index_type& index, float& u) const
{
ASSERT(t >= 0.f && t <= 1.f);
length_type length_ = t * length();
index = computeIndexInBounds(length_);
ASSERT(index < index_hi);
u = (length_ - length(index)) / (float)length(index, index+1);
}
template<typename length_type> SplineBase::index_type Spline<length_type>::computeIndexInBounds( float t ) const
{
ASSERT(t >= 0.f && t <= 1.f);
return computeIndexInBounds(t * length());
}
template<typename length_type> void Spline<length_type>::initLengths()
{
index_type i = index_lo;
length_type length = 0;
lengths.resize(index_hi+1);
while(i < index_hi )
{
length += SegLength(i);
lengths[++i] = length;
}
}
template<typename length_type> void Spline<length_type>::clear()
{
SplineBase::clear();
lengths.clear();
}
}
-152
View File
@@ -1,152 +0,0 @@
/*
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRINITY_TRAVELLER_H
#define TRINITY_TRAVELLER_H
#include "Creature.h"
#include "Player.h"
#include <cassert>
/** Traveller is a wrapper for units (creatures or players) that
* travel from point A to point B using the destination holder.
*/
#define PLAYER_FLIGHT_SPEED 32.0f
template<class T>
struct Traveller
{
T &i_traveller;
Traveller(T &t) : i_traveller(t) {}
Traveller(const Traveller &obj) : i_traveller(obj) {}
Traveller& operator=(const Traveller &obj)
{
this.i_traveller = obj.i_traveller;
return *this;
}
operator T&(void) { return i_traveller; }
operator const T&(void) { return i_traveller; }
float GetPositionX() const { return i_traveller.GetPositionX(); }
float GetPositionY() const { return i_traveller.GetPositionY(); }
float GetPositionZ() const { return i_traveller.GetPositionZ(); }
T& GetTraveller(void) { return i_traveller; }
float Speed(void) { ASSERT(false); return 0.0f; }
float GetMoveDestinationTo(float x, float y, float z);
uint32 GetTotalTrevelTimeTo(float x, float y, float z);
void Relocation(float x, float y, float z, float orientation) {}
void Relocation(float x, float y, float z) { Relocation(x, y, z, i_traveller.GetOrientation()); }
void MoveTo(float x, float y, float z, uint32 t) {}
};
template<class T>
inline uint32 Traveller<T>::GetTotalTrevelTimeTo(float x, float y, float z)
{
float dist = GetMoveDestinationTo(x, y, z);
float speed = Speed();
if (speed < 0.0f)
return 0xfffffffe; // almost infinity-unit should stop
else
speed *= 0.001f; // speed is in seconds so convert from second to millisecond
return static_cast<uint32>(dist/speed);
}
// specialization for creatures
template<>
inline float Traveller<Creature>::Speed()
{
if (i_traveller.HasUnitState(UNIT_STAT_CHARGING))
return i_traveller.m_TempSpeed;
else if (i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_WALKING))
return i_traveller.GetSpeed(MOVE_WALK);
else if (i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_FLYING))
return i_traveller.GetSpeed(MOVE_FLIGHT);
else
return i_traveller.GetSpeed(MOVE_RUN);
}
template<>
inline void Traveller<Creature>::Relocation(float x, float y, float z, float orientation)
{
i_traveller.UpdatePosition(x, y, z, orientation);
}
template<>
inline float Traveller<Creature>::GetMoveDestinationTo(float x, float y, float z)
{
float dx = x - GetPositionX();
float dy = y - GetPositionY();
float dz = z - GetPositionZ();
//if (i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_FLYING))
return sqrt((dx*dx) + (dy*dy) + (dz*dz));
//else //Walking on the ground
// return sqrt((dx*dx) + (dy*dy));
}
template<>
inline void Traveller<Creature>::MoveTo(float x, float y, float z, uint32 t)
{
//i_traveller.AI_SendMoveToPacket(x, y, z, t, i_traveller.GetUnitMovementFlags(), 0);
i_traveller.SendMonsterMove(x, y, z, t);
}
// specialization for players
template<>
inline float Traveller<Player>::Speed()
{
if (i_traveller.HasUnitState(UNIT_STAT_CHARGING))
return i_traveller.m_TempSpeed;
else if (i_traveller.isInFlight())
return PLAYER_FLIGHT_SPEED;
else
return i_traveller.GetSpeed(i_traveller.m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING) ? MOVE_WALK : MOVE_RUN);
}
template<>
inline float Traveller<Player>::GetMoveDestinationTo(float x, float y, float z)
{
float dx = x - GetPositionX();
float dy = y - GetPositionY();
float dz = z - GetPositionZ();
//if (i_traveller.isInFlight())
return sqrt((dx*dx) + (dy*dy) + (dz*dz));
//else //Walking on the ground
// return sqrt((dx*dx) + (dy*dy));
}
template<>
inline void Traveller<Player>::Relocation(float x, float y, float z, float orientation)
{
i_traveller.UpdatePosition(x, y, z, orientation);
}
template<>
inline void Traveller<Player>::MoveTo(float x, float y, float z, uint32 t)
{
//Only send MOVEMENTFLAG_WALKING, client has strange issues with other move flags
i_traveller.SendMonsterMove(x, y, z, t);
}
typedef Traveller<Creature> CreatureTraveller;
typedef Traveller<Player> PlayerTraveller;
#endif
+8 -2
View File
@@ -475,8 +475,14 @@ void Map::ScriptsProcess()
// Source or target must be Creature.
if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
cSource->SendMonsterMoveWithSpeed(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, step.script->MoveTo.TravelTime);
cSource->GetMap()->CreatureRelocation(cSource, step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, 0);
Unit * unit = (Unit*)cSource;
if (step.script->MoveTo.TravelTime != 0)
{
float speed = unit->GetDistance(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ) / ((float)step.script->MoveTo.TravelTime * 0.001f);
unit->MonsterMoveWithSpeed(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, speed);
}
else
unit->NearTeleportTo(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, unit->GetOrientation());
}
break;
@@ -27,7 +27,6 @@
#include "UpdateMask.h"
#include "Path.h"
#include "WaypointMovementGenerator.h"
#include "DestinationHolderImp.h"
void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPacket & recv_data)
{
@@ -4761,11 +4761,7 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
break;
case 46361: // Reinforced Net
if (caster)
{
float currentGroundLevel = target->GetBaseMap()->GetHeight(target->GetPositionX(), target->GetPositionY(), MAX_HEIGHT);
if (target->GetPositionZ() > currentGroundLevel)
target->GetMotionMaster()->MoveFall(currentGroundLevel);
}
target->GetMotionMaster()->MoveFall();
break;
case 46699: // Requires No Ammo
if (target->GetTypeId() == TYPEID_PLAYER)
+3 -14
View File
@@ -3363,22 +3363,11 @@ void Spell::EffectDistract(SpellEffIndex /*effIndex*/)
if (unitTarget->HasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING))
return;
float angle = unitTarget->GetAngle(m_targets.GetDst());
unitTarget->SetFacingTo(unitTarget->GetAngle(m_targets.GetDst()));
unitTarget->ClearUnitState(UNIT_STAT_MOVING);
if (unitTarget->GetTypeId() == TYPEID_PLAYER)
{
// For players just turn them
unitTarget->ToPlayer()->UpdatePosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
unitTarget->ToPlayer()->SendTeleportAckPacket();
}
else
{
// Set creature Distracted, Stop it, And turn it
unitTarget->SetOrientation(angle);
unitTarget->StopMoving();
if (unitTarget->GetTypeId() == TYPEID_UNIT)
unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS);
unitTarget->SendMovementFlagUpdate();
}
}
void Spell::EffectPickPocket(SpellEffIndex /*effIndex*/)
+2 -3
View File
@@ -1036,15 +1036,14 @@ public:
}
if (/*creature->GetMotionMaster()->empty() ||*/
creature->GetMotionMaster()->GetCurrentMovementGeneratorType () != TARGETED_MOTION_TYPE)
creature->GetMotionMaster()->GetCurrentMovementGeneratorType () != FOLLOW_MOTION_TYPE)
{
handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName());
handler->SetSentErrorMessage(true);
return false;
}
TargetedMovementGenerator<Creature> const* mgen
= static_cast<TargetedMovementGenerator<Creature> const*>((creature->GetMotionMaster()->top()));
FollowMovementGenerator<Creature> const* mgen = static_cast<FollowMovementGenerator<Creature> const*>((creature->GetMotionMaster()->top()));
if (mgen->GetTarget() != player)
{
@@ -1009,7 +1009,7 @@ public:
me->SetInFront(car);
me->SendMovementFlagUpdate();
car->Relocate(car->GetPositionX(), car->GetPositionY(), me->GetPositionZ() + 1);
car->SendMonsterStop();
car->StopMoving();
car->RemoveAura(SPELL_CART_DRAG);
}
me->MonsterSay(SAY_SCARLET_MINER2, LANG_UNIVERSAL, 0);
@@ -325,7 +325,7 @@ class boss_akilzon : public CreatureScript
if (target)
{
target->SetUnitMovementFlags(MOVEMENTFLAG_LEVITATING);
target->SendMonsterMove(x, y, me->GetPositionZ()+15, 0);
target->MonsterMoveWithSpeed(x, y, me->GetPositionZ()+15, 0);
}
Unit* Cloud = me->SummonTrigger(x, y, me->GetPositionZ()+16, 0, 15000);
if (Cloud)
@@ -109,7 +109,7 @@ public:
{
if (Creature* target = Unit::GetCreature(*summoned, targetGUID))
{
target->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0);
target->MonsterMoveWithSpeed(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0);
target->SetPosition(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0.0f);
summoned->CastSpell(target, SPELL_RIBBON_OF_SOULS, false);
}
@@ -186,7 +186,7 @@ public:
if (EventMove_Timer <= diff)
{
me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
me->SendMonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW, 5000);
me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW, me->GetDistance(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW) / (5000 * 0.001f));
me->SetPosition(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW, me->GetOrientation());
EventMove = false;
} else EventMove_Timer -= diff;
@@ -592,11 +592,8 @@ public:
me->GetMotionMaster()->MoveIdle();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
//At hit the ground
me->GetPosition(x, y, z);
z = me->GetMap()->GetHeight(x, y, z, true, 50);
me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH);
me->GetMotionMaster()->MoveFall(z, 0);
//me->FallGround(); //need correct vmap use (i believe it isn't working properly right now)
me->GetMotionMaster()->MoveFall();
}
}
}
@@ -610,7 +607,6 @@ public:
case 0:
me->RemoveAurasDueToSpell(SPELL_FROST_SPHERE);
me->SetDisplayId(11686);
me->Relocate(x, y, z, me->GetOrientation());
DoCast(SPELL_PERMAFROST_VISUAL);
DoCast(SPELL_PERMAFROST);
me->SetFloatValue(OBJECT_FIELD_SCALE_X, 2.0f);
@@ -201,7 +201,7 @@ class mob_corrupted_soul_fragment : public CreatureScript
void MovementInform(uint32 type, uint32 id)
{
if (type != TARGETED_MOTION_TYPE)
if (type != CHASE_MOTION_TYPE)
return;
if (instance)
@@ -1159,7 +1159,7 @@ class npc_ball_of_flame : public CreatureScript
void MovementInform(uint32 type, uint32 id)
{
if (type == TARGETED_MOTION_TYPE && id == GUID_LOPART(_chaseGUID) && _chaseGUID)
if (type == CHASE_MOTION_TYPE && id == GUID_LOPART(_chaseGUID) && _chaseGUID)
{
me->RemoveAurasDueToSpell(SPELL_BALL_OF_FLAMES_PERIODIC);
DoCast(me, SPELL_FLAMES);
@@ -608,7 +608,7 @@ class npc_high_overlord_saurfang_icc : public CreatureScript
me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
me->SendMovementFlagUpdate();
me->Relocate(me->GetPositionX(), me->GetPositionY(), 539.2917f);
me->SendMonsterMove(me->GetPositionX(), me->GetPositionY(), 539.2917f, SPLINEFLAG_FALLING, 0, 0.0f);
me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), 539.2917f, 0.0f);
for (std::list<Creature*>::iterator itr = _guardList.begin(); itr != _guardList.end(); ++itr)
(*itr)->AI()->DoAction(ACTION_DESPAWN);
break;
@@ -815,7 +815,7 @@ class npc_muradin_bronzebeard_icc : public CreatureScript
me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
me->SendMovementFlagUpdate();
me->Relocate(me->GetPositionX(), me->GetPositionY(), 539.2917f);
me->SendMonsterMove(me->GetPositionX(), me->GetPositionY(), 539.2917f, SPLINEFLAG_FALLING, 0, 0.0f);
me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), 539.2917f, 0.0f);
for (std::list<Creature*>::iterator itr = _guardList.begin(); itr != _guardList.end(); ++itr)
(*itr)->AI()->DoAction(ACTION_DESPAWN);
break;
@@ -508,7 +508,7 @@ class boss_the_lich_king : public CreatureScript
if (fabs(ground_Z - z) < 0.1f)
return;
me->GetMotionMaster()->MoveFall(ground_Z);
me->GetMotionMaster()->MoveFall();
}
void EnterCombat(Unit* target)
@@ -801,7 +801,7 @@ class boss_the_lich_king : public CreatureScript
events.ScheduleEvent(EVENT_INTRO_TALK_1, 9000, 0, PHASE_INTRO);
break;
case POINT_CENTER_1:
me->SetFacing(0.0f);
me->SetFacingTo(0.0f);
Talk(SAY_LK_REMORSELESS_WINTER);
SendMusicToPlayers(MUSIC_SPECIAL);
me->SetReactState(REACT_PASSIVE);
@@ -818,7 +818,7 @@ class boss_the_lich_king : public CreatureScript
events.ScheduleEvent(EVENT_SOUL_REAPER, 94000, 0, PHASE_TWO);
break;
case POINT_CENTER_2:
me->SetFacing(0.0f);
me->SetFacingTo(0.0f);
Talk(SAY_LK_REMORSELESS_WINTER);
SendMusicToPlayers(MUSIC_SPECIAL);
me->SetReactState(REACT_PASSIVE);
@@ -1047,14 +1047,14 @@ class boss_the_lich_king : public CreatureScript
break;
case EVENT_OUTRO_TALK_3:
if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING)))
me->SetFacing(0.0f, tirion);
me->SetFacingToObject(tirion);
Talk(SAY_LK_OUTRO_3);
break;
case EVENT_OUTRO_MOVE_CENTER:
me->GetMotionMaster()->MovePoint(POINT_LK_OUTRO_1, CenterPosition);
break;
case EVENT_OUTRO_TALK_4:
me->SetFacing(0.01745329f);
me->SetFacingTo(0.01745329f);
Talk(SAY_LK_OUTRO_4);
break;
case EVENT_OUTRO_RAISE_DEAD:
@@ -1070,7 +1070,7 @@ class boss_the_lich_king : public CreatureScript
case EVENT_OUTRO_TALK_6:
Talk(SAY_LK_OUTRO_6);
if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING)))
tirion->SetFacing(0.0f, me);
tirion->SetFacingToObject(me);
me->ClearUnitState(UNIT_STAT_CASTING);
DoCastAOE(SPELL_SUMMON_BROKEN_FROSTMOURNE_3);
SetEquipmentSlots(false, EQUIP_UNEQUIP);
@@ -1222,7 +1222,7 @@ class npc_tirion_fordring_tft : public CreatureScript
void SpellHit(Unit* /*caster*/, SpellInfo const* spell)
{
if (spell->Id == SPELL_ICE_LOCK)
me->SetFacing(3.085098f);
me->SetFacingTo(3.085098f);
else if (spell->Id == SPELL_BROKEN_FROSTMOURNE_KNOCK)
SetEquipmentSlots(true); // remove glow on ashbringer
}
@@ -1285,7 +1285,7 @@ class npc_tirion_fordring_tft : public CreatureScript
SetEquipmentSlots(false, EQUIP_ASHBRINGER_GLOWING);
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING)))
{
me->SetFacing(0.0f, lichKing);
me->SetFacingToObject(lichKing);
lichKing->AI()->DoAction(ACTION_PLAY_MUSIC);
}
break;
@@ -1621,7 +1621,7 @@ class npc_strangulate_vehicle : public CreatureScript
void IsSummonedBy(Unit* summoner)
{
me->SetFacing(0.0f, summoner);
me->SetFacingToObject(summoner);
DoCast(summoner, SPELL_HARVEST_SOUL_VEHICLE);
_events.Reset();
_events.ScheduleEvent(EVENT_MOVE_TO_LICH_KING, 2000);
@@ -1789,7 +1789,7 @@ class npc_terenas_menethil : public CreatureScript
_events.Reset();
_events.SetPhase(PHASE_OUTRO);
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING)))
me->SetFacing(0.0f, lichKing);
me->SetFacingToObject(lichKing);
_events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_1, 2000, 0, PHASE_OUTRO);
_events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_2, 14000, 0, PHASE_OUTRO);
@@ -1264,7 +1264,7 @@ struct npc_argent_captainAI : public ScriptedAI
void EnterEvadeMode()
{
// not yet following
if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != TARGETED_MOTION_TYPE || IsUndead)
if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != CHASE_MOTION_TYPE || IsUndead)
{
ScriptedAI::EnterEvadeMode();
return;
@@ -838,7 +838,7 @@ public:
return;
}
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE)
me->GetMotionMaster()->MoveFollow(malygos, 0.0f, 0.0f);
}
}
@@ -243,7 +243,7 @@ public:
{
if (m_uiPause_Timer <= uiDiff)
{
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE)
if (me->getVictim())
me->GetMotionMaster()->MoveChase(me->getVictim());
@@ -421,7 +421,7 @@ public:
// me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); //Set in DB
if (me->IsNonMeleeSpellCasted(false))
me->InterruptNonMeleeSpells(false);
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
me->GetMotionMaster()->MovementExpired();
m_bIsFrozen = true;
}
@@ -174,7 +174,7 @@ public:
bIsSlam = false;
//and correct movement, if not already
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE)
{
if (me->getVictim())
me->GetMotionMaster()->MoveChase(me->getVictim());
@@ -634,7 +634,7 @@ class boss_stormcaller_brundir : public CreatureScript
// Prevent to have Brundir somewhere in the air when he die in Air phase
if (me->GetPositionZ() > FLOOR_Z)
me->GetMotionMaster()->MoveFall(FLOOR_Z);
me->GetMotionMaster()->MoveFall();
}
void KilledUnit(Unit* /*who*/)
@@ -288,7 +288,7 @@ public:
me->Dismount();
if (Creature* pGrauf = me->SummonCreature(CREATURE_GRAUF, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3*IN_MILLISECONDS))
{
pGrauf->GetMotionMaster()->MoveFall(0);
pGrauf->GetMotionMaster()->MoveFall();
pGrauf->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH);
}
me->GetMotionMaster()->MoveJump(Location[4].GetPositionX(), Location[4].GetPositionY(), Location[4].GetPositionZ(), 5.0f, 10.0f);
@@ -249,22 +249,16 @@ public:
if (Phase == SACRIFICING)
SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE);
me->GetPosition(x, y, z);
z = me->GetMap()->GetHeight(x, y, z, true, 50);
damage = 0;
Phase = SVALADEAD;
me->InterruptNonMeleeSpells(true);
me->RemoveAllAuras();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
me->SetHealth(1);
if (me->GetPositionZ() > z)
{
damage = 0;
Phase = SVALADEAD;
me->InterruptNonMeleeSpells(true);
me->RemoveAllAuras();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
me->SetHealth(1);
SetCombatMovement(false);
me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH);
me->GetMotionMaster()->MoveFall(z, 1);
}
SetCombatMovement(false);
me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH);
me->GetMotionMaster()->MoveFall();
}
}
@@ -274,10 +268,7 @@ public:
return;
if (pointId == 1)
{
me->Relocate(x, y, z, me->GetOrientation());
me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
}
}
void JustDied(Unit* killer)
@@ -187,7 +187,7 @@ public:
//expire movement, will prevent from running right back to victim after cast
//(but should MoveChase be used again at a certain time or should he not move?)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
me->GetMotionMaster()->MovementExpired();
DoCast(me, SPELL_BLINK);
@@ -1982,7 +1982,7 @@ void boss_illidan_stormrage::boss_illidan_stormrageAI::HandleTalkSequence()
Akama->GetMotionMaster()->Clear(false);
// Akama->GetMotionMaster()->MoveIdle();
Akama->SetPosition(x, y, z, 0.0f);
Akama->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_NONE, 0); // Illidan must not die until Akama arrives.
Akama->MonsterMoveWithSpeed(x, y, z, 0); // Illidan must not die until Akama arrives.
Akama->GetMotionMaster()->MoveChase(me);
}
@@ -151,7 +151,7 @@ public:
m_bPerformingGroundSlam = false;
//and correct movement, if not already
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE)
{
if (me->getVictim())
me->GetMotionMaster()->MoveChase(me->getVictim());
@@ -820,7 +820,7 @@ class boss_kaelthas : public CreatureScript
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveIdle();
me->SetPosition(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0);
me->SendMonsterMove(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0, 0, 0);
me->MonsterMoveWithSpeed(afGravityPos[0], afGravityPos[1], afGravityPos[2], 1);
me->InterruptNonMeleeSpells(false);
DoCast(me, SPELL_FULLPOWER);
@@ -887,7 +887,7 @@ class boss_kaelthas : public CreatureScript
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveIdle();
me->SetPosition(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0);
me->SendMonsterMove(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0, MOVEMENTFLAG_NONE, 0);
me->MonsterMoveWithSpeed(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0);
// 1) Kael'thas will portal the whole raid right into his body
for (i = me->getThreatManager().getThreatList().begin(); i!= me->getThreatManager().getThreatList().end(); ++i)
+1 -1
View File
@@ -179,7 +179,7 @@ public:
globalCooldown = GENERIC_CREATURE_COOLDOWN;
} //If no spells available and we arn't moving run to target
else if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE)
else if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE)
{
//Cancel our current spell and then mutate new movement generator
me->InterruptNonMeleeSpells(false);
+1 -1
View File
@@ -133,7 +133,7 @@ struct TimeTrackerSmall
{
public:
TimeTrackerSmall(uint32 expiry)
TimeTrackerSmall(uint32 expiry = 0)
: i_expiryTime(expiry)
{
}