diff options
84 files changed, 3325 insertions, 1912 deletions
diff --git a/sql/updates/world/2011_01_14_03_world_trinity_string.sql b/sql/updates/world/2011_01_14_03_world_trinity_string.sql new file mode 100644 index 00000000000..7dab007f774 --- /dev/null +++ b/sql/updates/world/2011_01_14_03_world_trinity_string.sql @@ -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'); diff --git a/src/server/game/AI/CoreAI/GuardAI.cpp b/src/server/game/AI/CoreAI/GuardAI.cpp index 54061274408..b78fec7c142 100755 --- a/src/server/game/AI/CoreAI/GuardAI.cpp +++ b/src/server/game/AI/CoreAI/GuardAI.cpp @@ -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(); } diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index 60151e4865a..015e20415b1 100755 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -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; } diff --git a/src/server/game/AI/EventAI/CreatureEventAI.cpp b/src/server/game/AI/EventAI/CreatureEventAI.cpp index c7590ebb512..c507262bd3f 100755 --- a/src/server/game/AI/EventAI/CreatureEventAI.cpp +++ b/src/server/game/AI/EventAI/CreatureEventAI.cpp @@ -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(); } } diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index e3518cb6921..1b6fde6d132 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -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]) diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp index 1e0b212dd45..53747d0c799 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp @@ -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(); } diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 9cea61c0d2b..4328eafc962 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -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; diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 117a8f680ee..658e9a15cc8 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -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 diff --git a/src/server/game/Chat/Commands/Level3.cpp b/src/server/game/Chat/Commands/Level3.cpp index d23a429471f..cb3eb825354 100755 --- a/src/server/game/Chat/Commands/Level3.cpp +++ b/src/server/game/Chat/Commands/Level3.cpp @@ -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()); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index ff627f78ea0..23865dd9e41 100755 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -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); +} diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index adad02653bf..05339f1da53 100755 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -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); diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp index abf82dc5919..f440fd497fc 100755 --- a/src/server/game/Entities/Creature/CreatureGroups.cpp +++ b/src/server/game/Entities/Creature/CreatureGroups.cpp @@ -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) { diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 22f001d0224..fd094938da8 100755 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1869,4 +1869,4 @@ void GameObject::SetLootState(LootState s) { m_lootState = s; AI()->OnStateChanged(s); -}
\ No newline at end of file +} diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 3cd02d05a90..5c034f1a42a 100755 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -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*/) diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 3f78ec662e8..4cc298e4349 100755 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -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 diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 7f7facfaff1..46f903ee71a 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -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()); } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 21c87a993dc..aa1d4e8185e 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -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); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 2d6e8f1b724..63aa7771063 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -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); -} - -void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime, Player* player) -{ - if (!transitTime) - { - if (GetTypeId() == TYPEID_PLAYER) - { - Traveller<Player> traveller(*(Player*)this); - transitTime = traveller.GetTotalTrevelTimeTo(x, y, z); - } - else - { - Traveller<Creature> traveller(*ToCreature()); - transitTime = traveller.GetTotalTrevelTimeTo(x, y, z); - } - } - //float orientation = (float)atan2((double)dy, (double)dx); - SendMonsterMove(x, y, z, transitTime, player); + Movement::MoveSplineInit init(*this); + init.MoveTo(x,y,z); + init.SetVelocity(speed); + init.Launch(); } -void Unit::SetFacing(float ori, WorldObject* obj) +void Unit::UpdateSplineMovement(uint32 t_diff) { - 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); -} + enum{ + POSITION_UPDATE_DELAY = 400, + }; -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()); + if (movespline->Finalized()) + return; - data << uint8(0); // new in 3.1 - data << GetPositionX() << GetPositionY() << GetPositionZ(); - data << getMSTime(); + movespline->updateState(t_diff); + bool arrived = movespline->Finalized(); - data << uint8(0); - data << moveData.SplineFlag; + if (arrived) + DisableSpline(); - if (moveData.SplineFlag & SPLINEFLAG_ANIMATIONTIER) + m_movesplineTimer.Update(t_diff); + if (m_movesplineTimer.Passed() || arrived) { - data << uint8(moveData.AnimationState); - data << uint32(0); - } + m_movesplineTimer.Reset(POSITION_UPDATE_DELAY); + Movement::Location loc = movespline->ComputePosition(); - data << moveData.Time; - - if (moveData.SplineFlag & SPLINEFLAG_TRAJECTORY) - { - data << moveData.SpeedZ; - data << uint32(0); // walk time after jump + if (GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->UpdatePosition(loc.x,loc.y,loc.z,loc.orientation); + else + GetMap()->CreatureRelocation((Creature*)this,loc.x,loc.y,loc.z,loc.orientation); } - - 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) +void Unit::DisableSpline() { - 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)); +} diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 5a6b34bc380..b64a2e210bc 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -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 diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index b2f8e5608a7..df5ec540427 100755 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -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 diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 9f6b936541e..f3b45bd8f37 100755 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -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); diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index afb5aa5660f..0fb28008c1e 100755 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -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" diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 66610adc1f0..e751dbf92fe 100755 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -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, diff --git a/src/server/game/Movement/DestinationHolder.cpp b/src/server/game/Movement/DestinationHolder.cpp deleted file mode 100755 index 4b763112968..00000000000 --- a/src/server/game/Movement/DestinationHolder.cpp +++ /dev/null @@ -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" - diff --git a/src/server/game/Movement/DestinationHolder.h b/src/server/game/Movement/DestinationHolder.h deleted file mode 100755 index 5ae4ee88ce3..00000000000 --- a/src/server/game/Movement/DestinationHolder.h +++ /dev/null @@ -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 - diff --git a/src/server/game/Movement/DestinationHolderImp.h b/src/server/game/Movement/DestinationHolderImp.h deleted file mode 100755 index 4d6e6f0c741..00000000000 --- a/src/server/game/Movement/DestinationHolderImp.h +++ /dev/null @@ -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 - diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 6660da146f0..2656d882009 100755 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -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; + sLog->outStaticDebug("Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", i_owner->GetEntry(), id, x, y, z); - 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; + sLog->outStaticDebug("Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", i_owner->GetEntry(), id, x, y, z); - 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) - { - 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 + 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("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; } diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index a972c3b06ce..00f1701e591 100755 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -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); diff --git a/src/server/game/Movement/MovementGenerator.cpp b/src/server/game/Movement/MovementGenerator.cpp index 103b8876959..73921ea86ff 100755 --- a/src/server/game/Movement/MovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerator.cpp @@ -21,4 +21,3 @@ MovementGenerator::~MovementGenerator() { } - diff --git a/src/server/game/Movement/MovementGenerator.h b/src/server/game/Movement/MovementGenerator.h index 06450d938ae..dd9ba32f337 100755 --- a/src/server/game/Movement/MovementGenerator.h +++ b/src/server/game/Movement/MovementGenerator.h @@ -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> diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp index bf5c8bafc49..ac09f2d403a 100755 --- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp @@ -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; - } - - // 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 + i_waypoints[idx][0] = x + wanderX; + i_waypoints[idx][1] = y + wanderY; + + // 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)) + unit.AddUnitState(UNIT_STAT_CONFUSED_MOVE); + + if (unit.movespline->Finalized()) { - if (i_destinationHolder.HasArrived()) - { - // arrived, stop and wait a bit - unit.ClearUnitState(UNIT_STAT_MOVE); - - i_nextMove = urand(1, MAX_CONF_WAYPOINTS); - i_nextMoveTime.Reset(urand(100, 1000)); - } + 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); diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h index d3981ee2dcf..b9f96bb785d 100755 --- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h @@ -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 diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp index d2b3fcee384..458e6f9a62c 100755 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp @@ -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); -} - -template<> -bool FleeingMovementGenerator<Creature>::GetDestination(float &x, float &y, float &z) const -{ - if (i_destinationHolder.HasArrived()) - return false; + owner.AddUnitState(UNIT_STAT_FLEEING_MOVE); - 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_FLEEING_MOVE); +} + +template<> +void FleeingMovementGenerator<Creature>::Finalize(Creature &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); + 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; 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 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); } diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h index 4d4631fe932..750db52bb5a 100755 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h @@ -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 diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp index 16153dd6ccb..84997d6d1ae 100755 --- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp @@ -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; } diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h index ba34899dee5..c724edc91ff 100755 --- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h @@ -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 diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp index af2207ae141..505615c07b8 100755 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp @@ -20,84 +20,83 @@ #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*/) { } 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(); + //} +} diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h index 2504f1a38e3..e47f3d93450 100755 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h @@ -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 diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp index 981ec031cf9..0205b734058 100755 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp @@ -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); - const float range = (float)rand_norm()*wander_distance; - const float distanceX = range * cos(angle); - const float distanceY = range * sin(angle); + 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); - nx = X + distanceX; - ny = Y + distanceY; + destX = respX + distanceX; + destY = respY + distanceY; - // prevent invalid coordinates generation - Trinity::NormalizeMapCoord(nx); - Trinity::NormalizeMapCoord(ny); + // prevent invalid coordinates generation + Trinity::NormalizeMapCoord(destX); + Trinity::NormalizeMapCoord(destY); - dist = (nx - X)*(nx - X) + (ny - Y)*(ny - Y); + travelDistZ = distanceX*distanceX + distanceY*distanceY; - if (i == 5) - { - nz = Z; - break; - } + if (is_air_ok) // 3D system above ground and above water (flying mode) + { + // 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); + + // 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); - 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 + // 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); + + if (fabs(destZ - respZ) > travelDistZ) // Map check { - dist = dist >= 100.0f ? 10.0f : sqrtf(dist); // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE) + // Vmap Horizontal or above + destZ = map->GetHeight(destX, destY, respZ - 2.0f, true); - // 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; +} diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h index 816e325f3b1..67161b6fc29 100755 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h @@ -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 diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index e0ca5231000..bded2fd512c 100755 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -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 (stop) - { - owner.GetPosition(x, y, z); - i_destinationHolder.SetDestination(traveller, x, y, z); - i_destinationHolder.StartTravel(traveller, false); - owner.StopMoving(); - return false; - } - } + if (!owner.movespline->Finalized()) + return; - 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); + // nothing to do for Player +} - _setTargetLocation(owner); +template<> +void TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::UpdateFinalDistance(float /*fDistance*/) +{ + // nothing to do for Player } -template<class T> -void -TargetedMovementGenerator<T>::Finalize(T &owner) +template<> +void TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::UpdateFinalDistance(float fDistance) { - owner.ClearUnitState(UNIT_STAT_CHASE); + i_offset = fDistance; + i_recalculateTravel = true; } -template<class T> -void -TargetedMovementGenerator<T>::Reset(T &owner) +template<> +void TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<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<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()) + if (static_cast<D*>(this)->_lostTarget(owner)) + { + D::_clearUnitStateMove(owner); return true; + } - Traveller<T> traveller(owner); - - if (!i_destinationHolder.HasDestination()) - _setTargetLocation(owner); - else if (owner.IsStopped() && !i_destinationHolder.HasArrived()) + i_recheckDistance.Update(time_diff); + if (i_recheckDistance.Passed()) { - owner.AddUnitState(UNIT_STAT_CHASE); - i_destinationHolder.StartTravel(traveller); - return true; + 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); } - if (i_destinationHolder.UpdateTraveller(traveller, time_diff)) + if (owner.movespline->Finalized()) { - // put targeted movement generators on a higher priority - //if (owner.GetObjectSize()) - //i_destinationHolder.ResetUpdate(50); + static_cast<D*>(this)->MovementInform(owner); + if (i_angle == 0.f && !owner.HasInArc(0.01f, i_target.getTarget())) + owner.SetInFront(i_target.getTarget()); - // target moved - if (i_targetX != i_target->GetPositionX() || i_targetY != i_target->GetPositionY() - || i_targetZ != i_target->GetPositionZ()) + if (!i_targetReached) { - if (_setTargetLocation(owner) || !owner.HasUnitState(UNIT_STAT_FOLLOW)) - owner.SetInFront(i_target.getTarget()); - i_target->GetPosition(i_targetX, i_targetY, i_targetZ); + i_targetReached = true; + static_cast<D*>(this)->_reachTarget(owner); } + } + else + { + if (i_recalculateTravel) + _setTargetLocation(owner); + } + return true; +} - if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel) - { - i_recalculateTravel = false; - //Angle update will take place into owner.StopMoving() - owner.SetInFront(i_target.getTarget()); +//-----------------------------------------------// +template<class T> +void ChaseMovementGenerator<T>::_reachTarget(T &owner) +{ + if (owner.IsWithinMeleeRange(this->i_target.getTarget())) + owner.Attack(this->i_target.getTarget(),true); +} - owner.StopMoving(); - if (owner.IsWithinMeleeRange(i_target.getTarget()) && !owner.HasUnitState(UNIT_STAT_FOLLOW)) - owner.Attack(i_target.getTarget(), true); - } - } +template<> +void ChaseMovementGenerator<Player>::Initialize(Player &owner) +{ + owner.AddUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE); + _setTargetLocation(owner); +} - // Implemented for PetAI to handle resetting flags when pet owner reached - if (i_destinationHolder.HasArrived()) - MovementInform(owner); +template<> +void ChaseMovementGenerator<Creature>::Initialize(Creature &owner) +{ + owner.SetWalk(false); + owner.AddUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE); + _setTargetLocation(owner); +} - return true; +template<class T> +void ChaseMovementGenerator<T>::Finalize(T &owner) +{ + owner.ClearUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE); } template<class T> -Unit* -TargetedMovementGenerator<T>::GetTarget() const +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 i_target.getTarget(); + 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 TargetedMovementGenerator<T>::MovementInform(T & /*unit*/) +void FollowMovementGenerator<T>::Finalize(T &owner) { + owner.ClearUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE); + _updateSpeed(owner); } -template <> void TargetedMovementGenerator<Creature>::MovementInform(Creature &unit) +template<class T> +void FollowMovementGenerator<T>::Reset(T &owner) +{ + Initialize(owner); +} + +template<class T> +void FollowMovementGenerator<T>::MovementInform(T & /*unit*/) { - // Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle - unit.AI()->MovementInform(TARGETED_MOTION_TYPE, i_target.getTarget()->GetGUIDLow()); } -template void TargetedMovementGenerator<Player>::MovementInform(Player&); // Not implemented for players -template TargetedMovementGenerator<Player>::TargetedMovementGenerator(Unit &target, float offset, float angle); -template TargetedMovementGenerator<Creature>::TargetedMovementGenerator(Unit &target, float offset, float angle); -template bool TargetedMovementGenerator<Player>::_setTargetLocation(Player &); -template bool TargetedMovementGenerator<Creature>::_setTargetLocation(Creature &); -template void TargetedMovementGenerator<Player>::Initialize(Player &); -template void TargetedMovementGenerator<Creature>::Initialize(Creature &); -template void TargetedMovementGenerator<Player>::Finalize(Player &); -template void TargetedMovementGenerator<Creature>::Finalize(Creature &); -template void TargetedMovementGenerator<Player>::Reset(Player &); -template void TargetedMovementGenerator<Creature>::Reset(Creature &); -template bool TargetedMovementGenerator<Player>::Update(Player &, const uint32); -template bool TargetedMovementGenerator<Creature>::Update(Creature &, const uint32); -template Unit* TargetedMovementGenerator<Player>::GetTarget() const; -template Unit* TargetedMovementGenerator<Creature>::GetTarget() const; +template<> +void FollowMovementGenerator<Creature>::MovementInform(Creature &unit) +{ + // Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle + if (unit.AI()) + unit.AI()->MovementInform(FOLLOW_MOTION_TYPE, i_target.getTarget()->GetGUIDLow()); +} +//-----------------------------------------------// +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); diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h index edb4fca8fce..785d12ba6d2 100755 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h @@ -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 &); + void MovementInform(T &){} - Unit* GetTarget() const; + 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 &); +}; - 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; - } +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() {} - void unitSpeedChanged() { i_recalculateTravel=true; } - private: + MovementGeneratorType GetMovementGeneratorType() { return FOLLOW_MOTION_TYPE; } - bool _setTargetLocation(T &); + void Initialize(T &); + void Finalize(T &); + void Reset(T &); + void MovementInform(T &); - float i_offset; - float i_angle; - DestinationHolder< Traveller<T> > i_destinationHolder; - bool i_recalculateTravel; - float i_targetX, i_targetY, i_targetZ; + 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: + void _updateSpeed(T &u); }; + #endif diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index f88ed249aca..ea858eaba84 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -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*/){} +void WaypointMovementGenerator<Creature>::LoadPath(Creature &creature) +{ + if (!path_id) + path_id = creature.GetWaypointPath(); -template<> -void -WaypointMovementGenerator<Player>::Finalize(Player & /*u*/){} + i_path = sWaypointMgr->GetPath(path_id); -template<class T> -void -WaypointMovementGenerator<T>::MovementInform(T & /*unit*/){} + 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; + } -template<> -void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit) -{ - unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); + 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; - - i_destinationHolder.GetDestination(x, y, z); - return true; + LoadPath(creature); + creature.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); } -template<> -bool WaypointMovementGenerator<Player>::GetDestination(float & /*x*/, float & /*y*/, float & /*z*/) const +void WaypointMovementGenerator<Creature>::Finalize(Creature &creature) { - return false; + creature.ClearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); + creature.SetWalk(false); } -template<> -void WaypointMovementGenerator<Creature>::Reset(Creature & /*unit*/) +void WaypointMovementGenerator<Creature>::Reset(Creature &creature) { - StopedByPlayer = true; - i_nextMoveTime.Reset(0); + creature.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); + StartMoveNow(creature); } -template<> -void WaypointMovementGenerator<Player>::Reset(Player & /*unit*/){} - -template<> -void WaypointMovementGenerator<Creature>::InitTraveller(Creature &unit, const WaypointData &node) +void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature) { - node.run ? unit.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING): - unit.AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + if (!i_path || i_path->empty()) + return; + if (m_isArrivalDone) + return; - unit.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); - unit.SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + creature.ClearUnitState(UNIT_STAT_ROAMING_MOVE); + m_isArrivalDone = true; - // 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); + 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*/); + } - unit.AddUnitState(UNIT_STAT_ROAMING); + // Inform script + MovementInform(creature); + Stop(i_path->at(i_currentNode)->delay); } -template<> -void -WaypointMovementGenerator<Creature>::Initialize(Creature &u) +bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature) { - 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()) + if (!i_path || i_path->empty()) + return false; + if (Stopped()) + return true; + + const WaypointData *node = i_path->at(i_currentNode); + + if (m_isArrivalDone) { - 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); + 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(); } - else - node = NULL; -} -template<> -void WaypointMovementGenerator<Player>::InitTraveller(Player & /*unit*/, const WaypointData & /*node*/){} + m_isArrivalDone = false; -template<class T> -bool -WaypointMovementGenerator<T>::Update(T & /*unit*/, const uint32 /*diff*/) -{ - return false; -} + creature.AddUnitState(UNIT_STAT_ROAMING_MOVE); + + Movement::MoveSplineInit init(creature); + init.MoveTo(node->x, node->y, node->z); -template<> -bool -WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 diff) -{ - if (!&unit) - return true; + if (node->orientation != 100 && node->delay != 0) + init.SetFacing(node->orientation); - if (!path_id) - return false; + 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); + + return true; +} +bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) +{ // 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,42 +280,48 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport() } } +void FlightPathMovementGenerator::DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure) +{ + if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID) + { + sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.index, node.path, player.GetName()); + player.GetMap()->ScriptsStart(sEventScripts, eventid, &player, &player); + } +} + +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(); // 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 + /*! 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(m_endMapId); + Map* endMap = sMapMgr->FindBaseNonInstanceMap(_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); + 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"); } -void FlightPathMovementGenerator::DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure) -{ - if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID) - { - sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.index, node.path, player.GetName()); - player.GetMap()->ScriptsStart(sEventScripts, eventid, &player, &player); - } -} - // // Unique1's ASTAR Pathfinding Code... For future use & reference... diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h index 230630936ff..aa6d327db3b 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h @@ -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) {} - - 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; + 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 &); + 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 diff --git a/src/server/game/Movement/Spline/MoveSpline.cpp b/src/server/game/Movement/Spline/MoveSpline.cpp new file mode 100644 index 00000000000..4eaa6b57b36 --- /dev/null +++ b/src/server/game/Movement/Spline/MoveSpline.cpp @@ -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; +} +} diff --git a/src/server/game/Movement/Spline/MoveSpline.h b/src/server/game/Movement/Spline/MoveSpline.h new file mode 100644 index 00000000000..4b8dbcc8ee3 --- /dev/null +++ b/src/server/game/Movement/Spline/MoveSpline.h @@ -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 diff --git a/src/server/game/Movement/Spline/MoveSplineFlag.h b/src/server/game/Movement/Spline/MoveSplineFlag.h new file mode 100644 index 00000000000..de91f63c30a --- /dev/null +++ b/src/server/game/Movement/Spline/MoveSplineFlag.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 diff --git a/src/server/game/Movement/Spline/MoveSplineInit.cpp b/src/server/game/Movement/Spline/MoveSplineInit.cpp new file mode 100644 index 00000000000..885ade57653 --- /dev/null +++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp @@ -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(); + } +} diff --git a/src/server/game/Movement/Spline/MoveSplineInit.h b/src/server/game/Movement/Spline/MoveSplineInit.h new file mode 100644 index 00000000000..7ef6cd7a120 --- /dev/null +++ b/src/server/game/Movement/Spline/MoveSplineInit.h @@ -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 diff --git a/src/server/game/Movement/Spline/MoveSplineInitArgs.h b/src/server/game/Movement/Spline/MoveSplineInitArgs.h new file mode 100644 index 00000000000..26fbbdd0fcc --- /dev/null +++ b/src/server/game/Movement/Spline/MoveSplineInitArgs.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 diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp new file mode 100644 index 00000000000..73fdbf4c2f6 --- /dev/null +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp @@ -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()); + } + } +} diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.h b/src/server/game/Movement/Spline/MovementPacketBuilder.h new file mode 100644 index 00000000000..92a414e9b3b --- /dev/null +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.h @@ -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 diff --git a/src/server/game/Movement/Spline/MovementTypedefs.h b/src/server/game/Movement/Spline/MovementTypedefs.h new file mode 100644 index 00000000000..01c8a5b7e7b --- /dev/null +++ b/src/server/game/Movement/Spline/MovementTypedefs.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 diff --git a/src/server/game/Movement/Spline/MovementUtil.cpp b/src/server/game/Movement/Spline/MovementUtil.cpp new file mode 100644 index 00000000000..f0ed01c4676 --- /dev/null +++ b/src/server/game/Movement/Spline/MovementUtil.cpp @@ -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; + } +} diff --git a/src/server/game/Movement/Spline/Spline.cpp b/src/server/game/Movement/Spline/Spline.cpp new file mode 100644 index 00000000000..14c1bd0c117 --- /dev/null +++ b/src/server/game/Movement/Spline/Spline.cpp @@ -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(); +} + +} diff --git a/src/server/game/Movement/Spline/Spline.h b/src/server/game/Movement/Spline/Spline.h new file mode 100644 index 00000000000..28876b220d4 --- /dev/null +++ b/src/server/game/Movement/Spline/Spline.h @@ -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 diff --git a/src/server/game/Movement/Spline/SplineImpl.h b/src/server/game/Movement/Spline/SplineImpl.h new file mode 100644 index 00000000000..eded2d8c903 --- /dev/null +++ b/src/server/game/Movement/Spline/SplineImpl.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(); +} + +} diff --git a/src/server/game/Movement/Traveller.h b/src/server/game/Movement/Traveller.h deleted file mode 100755 index 641278ee37a..00000000000 --- a/src/server/game/Movement/Traveller.h +++ /dev/null @@ -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 - diff --git a/src/server/game/Scripting/MapScripts.cpp b/src/server/game/Scripting/MapScripts.cpp index 71195538256..7757e1a1a35 100755 --- a/src/server/game/Scripting/MapScripts.cpp +++ b/src/server/game/Scripting/MapScripts.cpp @@ -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; diff --git a/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp b/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp index 81481bdef31..3533b153bd8 100755 --- a/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp @@ -27,7 +27,6 @@ #include "UpdateMask.h" #include "Path.h" #include "WaypointMovementGenerator.h" -#include "DestinationHolderImp.h" void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPacket & recv_data) { diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 1d3c657f50a..535253f4e13 100755 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -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) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 2c33488f76c..eaf5f4e1d31 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -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*/) diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 54dac404f03..1b6a6c6fdcf 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -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) { diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp index 999f3fda2e4..a7d1c3ad8ba 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -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); diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp index d04d7af5c80..eee6b08d834 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp @@ -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) diff --git a/src/server/scripts/EasternKingdoms/undercity.cpp b/src/server/scripts/EasternKingdoms/undercity.cpp index f1c0fba2e29..fe9c40e6dbd 100644 --- a/src/server/scripts/EasternKingdoms/undercity.cpp +++ b/src/server/scripts/EasternKingdoms/undercity.cpp @@ -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; diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index bc6145252d2..8e34a318d6c 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -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); diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp index bc06a92ef07..d444160b8f2 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp @@ -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) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp index 3b15bba5c5d..94a3da2672b 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp @@ -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); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index 8396b6e6c85..31b3786a360 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -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; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index f2657e5b2ef..5029dbcceee 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -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); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index ab3046806db..6bd8f3cba7d 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -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; diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index 8e995a9b260..052fa3ba4a5 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -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); } } diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp index 194c2a36862..1fc724c8b6c 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp @@ -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; } diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp index 4ee71367b55..d1aba800094 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp @@ -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()); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp index 68435fffb1b..2c7532fcf70 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp @@ -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*/) diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp index 1bedd7e19e9..d5cd79b25f1 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp @@ -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); diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp index 9cab1de197c..436336ec5b8 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp @@ -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) diff --git a/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp b/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp index 81211b6e3d9..aa63f1adf18 100644 --- a/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp +++ b/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp @@ -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); diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp index b23b7bcd1ac..c17b6d5baf3 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp @@ -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); } diff --git a/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp b/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp index 33196b1213a..b7604c41794 100644 --- a/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp +++ b/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp @@ -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()); diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp index 974d81ef914..a45576f8884 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp @@ -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) diff --git a/src/server/scripts/World/guards.cpp b/src/server/scripts/World/guards.cpp index d562542a7d7..9bc511931b9 100644 --- a/src/server/scripts/World/guards.cpp +++ b/src/server/scripts/World/guards.cpp @@ -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); diff --git a/src/server/shared/Utilities/Timer.h b/src/server/shared/Utilities/Timer.h index 4dae8ac30d2..4d3f02f6688 100755 --- a/src/server/shared/Utilities/Timer.h +++ b/src/server/shared/Utilities/Timer.h @@ -133,7 +133,7 @@ struct TimeTrackerSmall { public: - TimeTrackerSmall(uint32 expiry) + TimeTrackerSmall(uint32 expiry = 0) : i_expiryTime(expiry) { } |