Core/Movement: Implement spline movement subsystem.

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

Technical changes:

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

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

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

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

Do not forget to re-run CMake before compiling.
This commit is contained in:
Machiavelli
2012-01-14 15:36:07 +01:00
parent 798677ca54
commit dbbac0bdaa
84 changed files with 3356 additions and 1943 deletions
@@ -592,11 +592,8 @@ public:
me->GetMotionMaster()->MoveIdle();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
//At hit the ground
me->GetPosition(x, y, z);
z = me->GetMap()->GetHeight(x, y, z, true, 50);
me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH);
me->GetMotionMaster()->MoveFall(z, 0);
//me->FallGround(); //need correct vmap use (i believe it isn't working properly right now)
me->GetMotionMaster()->MoveFall();
}
}
}
@@ -610,7 +607,6 @@ public:
case 0:
me->RemoveAurasDueToSpell(SPELL_FROST_SPHERE);
me->SetDisplayId(11686);
me->Relocate(x, y, z, me->GetOrientation());
DoCast(SPELL_PERMAFROST_VISUAL);
DoCast(SPELL_PERMAFROST);
me->SetFloatValue(OBJECT_FIELD_SCALE_X, 2.0f);
@@ -201,7 +201,7 @@ class mob_corrupted_soul_fragment : public CreatureScript
void MovementInform(uint32 type, uint32 id)
{
if (type != TARGETED_MOTION_TYPE)
if (type != CHASE_MOTION_TYPE)
return;
if (instance)
@@ -1159,7 +1159,7 @@ class npc_ball_of_flame : public CreatureScript
void MovementInform(uint32 type, uint32 id)
{
if (type == TARGETED_MOTION_TYPE && id == GUID_LOPART(_chaseGUID) && _chaseGUID)
if (type == CHASE_MOTION_TYPE && id == GUID_LOPART(_chaseGUID) && _chaseGUID)
{
me->RemoveAurasDueToSpell(SPELL_BALL_OF_FLAMES_PERIODIC);
DoCast(me, SPELL_FLAMES);
@@ -608,7 +608,7 @@ class npc_high_overlord_saurfang_icc : public CreatureScript
me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
me->SendMovementFlagUpdate();
me->Relocate(me->GetPositionX(), me->GetPositionY(), 539.2917f);
me->SendMonsterMove(me->GetPositionX(), me->GetPositionY(), 539.2917f, SPLINEFLAG_FALLING, 0, 0.0f);
me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), 539.2917f, 0.0f);
for (std::list<Creature*>::iterator itr = _guardList.begin(); itr != _guardList.end(); ++itr)
(*itr)->AI()->DoAction(ACTION_DESPAWN);
break;
@@ -815,7 +815,7 @@ class npc_muradin_bronzebeard_icc : public CreatureScript
me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
me->SendMovementFlagUpdate();
me->Relocate(me->GetPositionX(), me->GetPositionY(), 539.2917f);
me->SendMonsterMove(me->GetPositionX(), me->GetPositionY(), 539.2917f, SPLINEFLAG_FALLING, 0, 0.0f);
me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), 539.2917f, 0.0f);
for (std::list<Creature*>::iterator itr = _guardList.begin(); itr != _guardList.end(); ++itr)
(*itr)->AI()->DoAction(ACTION_DESPAWN);
break;
@@ -508,7 +508,7 @@ class boss_the_lich_king : public CreatureScript
if (fabs(ground_Z - z) < 0.1f)
return;
me->GetMotionMaster()->MoveFall(ground_Z);
me->GetMotionMaster()->MoveFall();
}
void EnterCombat(Unit* target)
@@ -801,7 +801,7 @@ class boss_the_lich_king : public CreatureScript
events.ScheduleEvent(EVENT_INTRO_TALK_1, 9000, 0, PHASE_INTRO);
break;
case POINT_CENTER_1:
me->SetFacing(0.0f);
me->SetFacingTo(0.0f);
Talk(SAY_LK_REMORSELESS_WINTER);
SendMusicToPlayers(MUSIC_SPECIAL);
me->SetReactState(REACT_PASSIVE);
@@ -818,7 +818,7 @@ class boss_the_lich_king : public CreatureScript
events.ScheduleEvent(EVENT_SOUL_REAPER, 94000, 0, PHASE_TWO);
break;
case POINT_CENTER_2:
me->SetFacing(0.0f);
me->SetFacingTo(0.0f);
Talk(SAY_LK_REMORSELESS_WINTER);
SendMusicToPlayers(MUSIC_SPECIAL);
me->SetReactState(REACT_PASSIVE);
@@ -1047,14 +1047,14 @@ class boss_the_lich_king : public CreatureScript
break;
case EVENT_OUTRO_TALK_3:
if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING)))
me->SetFacing(0.0f, tirion);
me->SetFacingToObject(tirion);
Talk(SAY_LK_OUTRO_3);
break;
case EVENT_OUTRO_MOVE_CENTER:
me->GetMotionMaster()->MovePoint(POINT_LK_OUTRO_1, CenterPosition);
break;
case EVENT_OUTRO_TALK_4:
me->SetFacing(0.01745329f);
me->SetFacingTo(0.01745329f);
Talk(SAY_LK_OUTRO_4);
break;
case EVENT_OUTRO_RAISE_DEAD:
@@ -1070,7 +1070,7 @@ class boss_the_lich_king : public CreatureScript
case EVENT_OUTRO_TALK_6:
Talk(SAY_LK_OUTRO_6);
if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING)))
tirion->SetFacing(0.0f, me);
tirion->SetFacingToObject(me);
me->ClearUnitState(UNIT_STAT_CASTING);
DoCastAOE(SPELL_SUMMON_BROKEN_FROSTMOURNE_3);
SetEquipmentSlots(false, EQUIP_UNEQUIP);
@@ -1222,7 +1222,7 @@ class npc_tirion_fordring_tft : public CreatureScript
void SpellHit(Unit* /*caster*/, SpellInfo const* spell)
{
if (spell->Id == SPELL_ICE_LOCK)
me->SetFacing(3.085098f);
me->SetFacingTo(3.085098f);
else if (spell->Id == SPELL_BROKEN_FROSTMOURNE_KNOCK)
SetEquipmentSlots(true); // remove glow on ashbringer
}
@@ -1285,7 +1285,7 @@ class npc_tirion_fordring_tft : public CreatureScript
SetEquipmentSlots(false, EQUIP_ASHBRINGER_GLOWING);
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING)))
{
me->SetFacing(0.0f, lichKing);
me->SetFacingToObject(lichKing);
lichKing->AI()->DoAction(ACTION_PLAY_MUSIC);
}
break;
@@ -1621,7 +1621,7 @@ class npc_strangulate_vehicle : public CreatureScript
void IsSummonedBy(Unit* summoner)
{
me->SetFacing(0.0f, summoner);
me->SetFacingToObject(summoner);
DoCast(summoner, SPELL_HARVEST_SOUL_VEHICLE);
_events.Reset();
_events.ScheduleEvent(EVENT_MOVE_TO_LICH_KING, 2000);
@@ -1789,7 +1789,7 @@ class npc_terenas_menethil : public CreatureScript
_events.Reset();
_events.SetPhase(PHASE_OUTRO);
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING)))
me->SetFacing(0.0f, lichKing);
me->SetFacingToObject(lichKing);
_events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_1, 2000, 0, PHASE_OUTRO);
_events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_2, 14000, 0, PHASE_OUTRO);
@@ -1264,7 +1264,7 @@ struct npc_argent_captainAI : public ScriptedAI
void EnterEvadeMode()
{
// not yet following
if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != TARGETED_MOTION_TYPE || IsUndead)
if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != CHASE_MOTION_TYPE || IsUndead)
{
ScriptedAI::EnterEvadeMode();
return;
@@ -838,7 +838,7 @@ public:
return;
}
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE)
me->GetMotionMaster()->MoveFollow(malygos, 0.0f, 0.0f);
}
}
@@ -243,7 +243,7 @@ public:
{
if (m_uiPause_Timer <= uiDiff)
{
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE)
if (me->getVictim())
me->GetMotionMaster()->MoveChase(me->getVictim());
@@ -421,7 +421,7 @@ public:
// me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); //Set in DB
if (me->IsNonMeleeSpellCasted(false))
me->InterruptNonMeleeSpells(false);
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
me->GetMotionMaster()->MovementExpired();
m_bIsFrozen = true;
}
@@ -174,7 +174,7 @@ public:
bIsSlam = false;
//and correct movement, if not already
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE)
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE)
{
if (me->getVictim())
me->GetMotionMaster()->MoveChase(me->getVictim());
@@ -634,7 +634,7 @@ class boss_stormcaller_brundir : public CreatureScript
// Prevent to have Brundir somewhere in the air when he die in Air phase
if (me->GetPositionZ() > FLOOR_Z)
me->GetMotionMaster()->MoveFall(FLOOR_Z);
me->GetMotionMaster()->MoveFall();
}
void KilledUnit(Unit* /*who*/)
@@ -288,7 +288,7 @@ public:
me->Dismount();
if (Creature* pGrauf = me->SummonCreature(CREATURE_GRAUF, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3*IN_MILLISECONDS))
{
pGrauf->GetMotionMaster()->MoveFall(0);
pGrauf->GetMotionMaster()->MoveFall();
pGrauf->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH);
}
me->GetMotionMaster()->MoveJump(Location[4].GetPositionX(), Location[4].GetPositionY(), Location[4].GetPositionZ(), 5.0f, 10.0f);
@@ -249,22 +249,16 @@ public:
if (Phase == SACRIFICING)
SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE);
me->GetPosition(x, y, z);
z = me->GetMap()->GetHeight(x, y, z, true, 50);
damage = 0;
Phase = SVALADEAD;
me->InterruptNonMeleeSpells(true);
me->RemoveAllAuras();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
me->SetHealth(1);
if (me->GetPositionZ() > z)
{
damage = 0;
Phase = SVALADEAD;
me->InterruptNonMeleeSpells(true);
me->RemoveAllAuras();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
me->SetHealth(1);
SetCombatMovement(false);
me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH);
me->GetMotionMaster()->MoveFall(z, 1);
}
SetCombatMovement(false);
me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH);
me->GetMotionMaster()->MoveFall();
}
}
@@ -274,10 +268,7 @@ public:
return;
if (pointId == 1)
{
me->Relocate(x, y, z, me->GetOrientation());
me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
}
}
void JustDied(Unit* killer)