mirror of
https://github.com/ACEmulator/ACE
synced 2026-08-17 12:26:06 -04:00
251 lines
7.4 KiB
C#
251 lines
7.4 KiB
C#
using System.Collections.Generic;
|
|
|
|
using ACE.Entity.Enum;
|
|
|
|
namespace ACE.Server.Physics.Animation
|
|
{
|
|
public class MotionTableManager
|
|
{
|
|
public PhysicsObj PhysicsObj;
|
|
public MotionTable Table;
|
|
public MotionState State;
|
|
public uint AnimationCounter;
|
|
public LinkedList<AnimNode> PendingAnimations;
|
|
|
|
public MotionTableManager()
|
|
{
|
|
Init();
|
|
}
|
|
|
|
public MotionTableManager(uint mtableID)
|
|
{
|
|
Init();
|
|
|
|
if (mtableID != 0)
|
|
SetMotionTableID(mtableID);
|
|
}
|
|
|
|
public void AnimationDone(bool success)
|
|
{
|
|
var node = PendingAnimations.First;
|
|
if (node != null)
|
|
{
|
|
AnimationCounter++;
|
|
do
|
|
{
|
|
var entry = node.Value;
|
|
|
|
if (entry.NumAnims > AnimationCounter)
|
|
break;
|
|
|
|
if ((entry.Motion & (uint)CommandMask.Action) != 0)
|
|
State.remove_action_head();
|
|
|
|
var motionID = entry.Motion;
|
|
PhysicsObj.MotionDone(motionID, success);
|
|
AnimationCounter -= entry.NumAnims;
|
|
|
|
if (PendingAnimations.First != null)
|
|
PendingAnimations.RemoveFirst();
|
|
|
|
if (PhysicsObj.WeenieObj != null)
|
|
PhysicsObj.WeenieObj.OnMotionDone(motionID, success);
|
|
|
|
node = PendingAnimations.First;
|
|
}
|
|
while (node != null);
|
|
|
|
if (AnimationCounter != 0 && node == null)
|
|
AnimationCounter = 0;
|
|
}
|
|
}
|
|
|
|
public void CheckForCompletedMotions()
|
|
{
|
|
while (PendingAnimations.First != null)
|
|
{
|
|
var pendingAnimation = PendingAnimations.First;
|
|
|
|
if (pendingAnimation.Value.NumAnims != 0)
|
|
return;
|
|
|
|
var motionID = pendingAnimation.Value.Motion;
|
|
|
|
if ((motionID & (uint)CommandMask.Action) != 0)
|
|
State.remove_action_head();
|
|
|
|
PhysicsObj.MotionDone(motionID, true);
|
|
|
|
if (PendingAnimations.First != null)
|
|
PendingAnimations.Remove(pendingAnimation);
|
|
|
|
if (PhysicsObj.WeenieObj != null)
|
|
PhysicsObj.WeenieObj.OnMotionDone(motionID, true);
|
|
}
|
|
}
|
|
|
|
public static MotionTableManager Create(uint mtableID)
|
|
{
|
|
return new MotionTableManager(mtableID);
|
|
}
|
|
|
|
public uint GetMotionTableID(uint mtableID)
|
|
{
|
|
return Table == null ? 0u : Table.ID;
|
|
}
|
|
|
|
public void Init()
|
|
{
|
|
State = new MotionState();
|
|
PendingAnimations = new LinkedList<AnimNode>();
|
|
}
|
|
|
|
public void HandleEnterWorld(Sequence sequence)
|
|
{
|
|
sequence.remove_all_link_animations();
|
|
while (PendingAnimations.Count > 0)
|
|
AnimationDone(false);
|
|
}
|
|
|
|
public void HandleExitWorld()
|
|
{
|
|
while (PendingAnimations.Count > 0)
|
|
AnimationDone(false);
|
|
}
|
|
|
|
public WeenieError PerformMovement(MovementStruct mvs, Sequence seq)
|
|
{
|
|
if (Table == null) return WeenieError.NoAnimationTable;
|
|
|
|
uint counter = 0;
|
|
switch (mvs.Type)
|
|
{
|
|
case MovementType.InterpretedCommand:
|
|
if (!Table.DoObjectMotion(mvs.Motion, State, seq, mvs.Params.Speed, ref counter))
|
|
return WeenieError.NoMtableData;
|
|
|
|
add_to_queue(mvs.Motion, counter, seq);
|
|
return WeenieError.None;
|
|
|
|
case MovementType.StopInterpretedCommand:
|
|
if (!Table.StopObjectMotion(mvs.Motion, mvs.Params.Speed, State, seq, ref counter))
|
|
return WeenieError.NoMtableData;
|
|
|
|
add_to_queue((uint)MotionCommand.Ready, counter, seq);
|
|
return WeenieError.None;
|
|
|
|
case MovementType.StopCompletely:
|
|
Table.StopObjectCompletely(State, seq, ref counter);
|
|
add_to_queue((uint)MotionCommand.Ready, counter, seq);
|
|
return WeenieError.None;
|
|
|
|
default:
|
|
return WeenieError.None; // ??
|
|
}
|
|
}
|
|
|
|
public bool SetMotionTableID(uint mtableID)
|
|
{
|
|
Table = MotionTable.Get(mtableID);
|
|
return Table != null;
|
|
}
|
|
|
|
public void SetPhysicsObject(PhysicsObj obj)
|
|
{
|
|
PhysicsObj = obj;
|
|
}
|
|
|
|
public void UseTime()
|
|
{
|
|
CheckForCompletedMotions();
|
|
}
|
|
|
|
public void add_to_queue(uint motion, uint num_anims, Sequence sequence)
|
|
{
|
|
PendingAnimations.AddLast(new AnimNode(motion, num_anims));
|
|
remove_redundant_links(sequence);
|
|
}
|
|
|
|
public void initialize_state(Sequence sequence)
|
|
{
|
|
uint numAnims = 0;
|
|
|
|
if (Table != null)
|
|
Table.SetDefaultState(State, sequence, ref numAnims);
|
|
|
|
add_to_queue((uint)MotionCommand.Ready, numAnims, sequence);
|
|
}
|
|
|
|
public void remove_redundant_links(Sequence sequence)
|
|
{
|
|
var node = PendingAnimations.Last;
|
|
|
|
while (node != null)
|
|
{
|
|
var entry = node.Value;
|
|
|
|
if (entry.NumAnims != 0)
|
|
{
|
|
if ((entry.Motion & (uint)CommandMask.SubState) == 0 || (entry.Motion & (uint)CommandMask.Modifier) != 0)
|
|
{
|
|
if ((entry.Motion & (uint)CommandMask.Style) == 0)
|
|
return;
|
|
|
|
if (remove_redundant_links_inner(node, sequence, true))
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (remove_redundant_links_inner(node, sequence, false))
|
|
return;
|
|
}
|
|
}
|
|
node = node.Previous;
|
|
}
|
|
}
|
|
|
|
public bool remove_redundant_links_inner(LinkedListNode<AnimNode> node, Sequence sequence, bool first)
|
|
{
|
|
var entry = node.Value;
|
|
var prev = node.Previous;
|
|
|
|
var motion = first ? 0x70000000 : 0xB0000000;
|
|
|
|
while (prev != null)
|
|
{
|
|
var prevEntry = prev.Value;
|
|
|
|
if (entry.Motion == prevEntry.Motion && (first || prevEntry.NumAnims != 0))
|
|
{
|
|
trancuate_animation_list(prev, sequence);
|
|
return true;
|
|
}
|
|
|
|
if (prevEntry.NumAnims != 0 && (prevEntry.Motion & motion) != 0)
|
|
return true;
|
|
|
|
prev = prev.Previous;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void trancuate_animation_list(LinkedListNode<AnimNode> node, Sequence sequence)
|
|
{
|
|
if (node == null) return;
|
|
|
|
uint totalAnims = 0;
|
|
var entry = PendingAnimations.Last;
|
|
|
|
while (entry != node)
|
|
{
|
|
if (entry == null) return;
|
|
|
|
totalAnims += entry.Value.NumAnims;
|
|
entry.Value.NumAnims = 0;
|
|
entry = entry.Previous;
|
|
}
|
|
sequence.remove_link_animations(totalAnims);
|
|
}
|
|
}
|
|
}
|