PageRenderTime 25ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 1ms

/dev/Ultima/World/Entities/Mobiles/Animations/MobileAnimation.cs

https://gitlab.com/swak/UltimaXNA
C# | 272 lines | 213 code | 25 blank | 34 comment | 59 complexity | 91a89ee71c315eee41bf2805b72feca4 MD5 | raw file
  1. /***************************************************************************
  2. * MobileAnimation.cs
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. ***************************************************************************/
  10. #region usings
  11. using UltimaXNA.Core.Diagnostics.Tracing;
  12. using UltimaXNA.Core.Resources;
  13. using UltimaXNA.Ultima.Data;
  14. using UltimaXNA.Ultima.Resources;
  15. using UltimaXNA.Ultima.World.Entities.Mobiles;
  16. using UltimaXNA.Ultima.World.Entities;
  17. #endregion
  18. namespace UltimaXNA.Ultima.World.Entities.Mobiles.Animations
  19. {
  20. /// <summary>
  21. /// Maintains and updates a mobile's animations. Receives animations from server, and when moving, updates the movement animation.
  22. /// TODO: This class needs a serious refactor.
  23. /// </summary>
  24. public class MobileAnimation
  25. {
  26. private Mobile Parent = null;
  27. private MobileAction m_action;
  28. private bool m_actionCanBeInteruptedByStand = false;
  29. private int m_actionIndex;
  30. public int ActionIndex
  31. {
  32. get
  33. {
  34. if (Parent.Body == 5 || Parent.Body == 6) // birds have weird action indexes. not sure if this is correct.
  35. if (m_actionIndex > 8)
  36. return m_actionIndex + 8;
  37. return m_actionIndex;
  38. }
  39. }
  40. public bool IsAnimating
  41. {
  42. get
  43. {
  44. if ((!m_actionCanBeInteruptedByStand) &&
  45. (m_action == MobileAction.None ||
  46. m_action == MobileAction.Stand ||
  47. m_action == MobileAction.Walk ||
  48. m_action == MobileAction.Run))
  49. return false;
  50. return true;
  51. }
  52. }
  53. public bool IsStanding
  54. {
  55. get
  56. {
  57. return (m_action == MobileAction.Stand);
  58. }
  59. }
  60. private float m_animationFrame = 0f;
  61. public float AnimationFrame
  62. {
  63. get
  64. {
  65. if (m_animationFrame >= m_FrameCount)
  66. return m_FrameCount - 0.1f;
  67. else
  68. return m_animationFrame;
  69. }
  70. }
  71. // We use these variables to 'hold' the last frame of an animation before
  72. // switching to Stand Action.
  73. private bool m_IsAnimatationPaused = false;
  74. private int m_AnimationPausedMS = 0;
  75. private int PauseAnimationMS
  76. {
  77. get
  78. {
  79. if (Parent.IsClientEntity)
  80. return 100;
  81. else
  82. return 350;
  83. }
  84. }
  85. public MobileAnimation(Mobile parent)
  86. {
  87. Parent = parent;
  88. }
  89. public void Update(double frameMS)
  90. {
  91. // create a local copy of ms since last update.
  92. int msSinceLastUpdate = (int)frameMS;
  93. // If we are holding the current animation, then we should wait until our hold time is over
  94. // before switching to the queued Stand animation.
  95. if (m_IsAnimatationPaused)
  96. {
  97. m_AnimationPausedMS -= msSinceLastUpdate;
  98. if (m_AnimationPausedMS >= 0)
  99. {
  100. // we are still holding. Do not update the current Animation frame.
  101. return;
  102. }
  103. else
  104. {
  105. // hold time is over, continue to Stand animation.
  106. UnPauseAnimation();
  107. m_action = MobileAction.Stand;
  108. m_actionIndex = ActionTranslator.GetActionIndex(Parent, MobileAction.Stand);
  109. m_animationFrame = 0f;
  110. m_FrameCount = 1;
  111. m_FrameDelay = 0;
  112. }
  113. }
  114. if (m_action != MobileAction.None)
  115. {
  116. float msPerFrame = ((900f * (m_FrameDelay + 1)) / m_FrameCount);
  117. // Mounted movement is ~2x normal frame rate
  118. if (Parent.IsMounted && ((m_action == MobileAction.Walk) || (m_action == MobileAction.Run)))
  119. msPerFrame /= 2.272727f;
  120. if (msPerFrame < 0)
  121. return;
  122. m_animationFrame += (float)(frameMS / msPerFrame);
  123. if (Settings.Audio.FootStepSoundOn)
  124. {
  125. if (m_action == MobileAction.Walk || m_action == MobileAction.Run)
  126. MobileSounds.DoFootstepSounds(Parent as Mobile, m_animationFrame / m_FrameCount);
  127. else
  128. MobileSounds.ResetFootstepSounds(Parent as Mobile);
  129. }
  130. // When animations reach their last frame, if we are queueing to stand, then
  131. // hold the animation on the last frame.
  132. if (m_animationFrame >= m_FrameCount)
  133. {
  134. if (m_repeatCount > 0)
  135. {
  136. m_animationFrame -= m_FrameCount;
  137. m_repeatCount--;
  138. }
  139. else
  140. {
  141. // any requested actions are ended.
  142. m_actionCanBeInteruptedByStand = false;
  143. // Hold the last frame of the current action if animation is not Stand.
  144. if (m_action == MobileAction.Stand)
  145. {
  146. m_animationFrame = 0;
  147. }
  148. else
  149. {
  150. // for most animations, hold the last frame. For Move animations, cycle through.
  151. if (m_action == MobileAction.Run || m_action == MobileAction.Walk)
  152. m_animationFrame -= m_FrameCount;
  153. else
  154. m_animationFrame = m_FrameCount - 0.001f;
  155. PauseAnimation();
  156. }
  157. }
  158. }
  159. }
  160. }
  161. /// <summary>
  162. /// Immediately clears all animation data, sets mobile action to stand.
  163. /// </summary>
  164. public void Clear()
  165. {
  166. m_action = MobileAction.Stand;
  167. m_animationFrame = 0;
  168. m_FrameCount = 1;
  169. m_FrameDelay = 0;
  170. m_IsAnimatationPaused = true;
  171. m_repeatCount = 0;
  172. m_actionIndex = ActionTranslator.GetActionIndex(Parent, MobileAction.Stand);
  173. }
  174. public void UpdateAnimation()
  175. {
  176. animate(m_action, m_actionIndex, 0, false, false, 0, false);
  177. }
  178. public void Animate(MobileAction action)
  179. {
  180. int actionIndex = ActionTranslator.GetActionIndex(Parent, action);
  181. animate(action, actionIndex, 0, false, false, 0, false);
  182. }
  183. public void Animate(int requestedIndex, int frameCount, int repeatCount, bool reverse, bool repeat, int delay)
  184. {
  185. // note that frameCount is NOT used. Not sure if this counts as a bug.
  186. MobileAction action = ActionTranslator.GetActionFromIndex(Parent.Body, requestedIndex);
  187. int actionIndex = ActionTranslator.GetActionIndex(Parent, action, requestedIndex);
  188. animate(action, actionIndex, repeatCount, reverse, repeat, delay, true);
  189. }
  190. private int m_FrameCount, m_FrameDelay, m_repeatCount;
  191. private void animate(MobileAction action, int actionIndex, int repeatCount, bool reverse, bool repeat, int delay, bool isRequestedAction)
  192. {
  193. if (m_action == action)
  194. {
  195. if (m_IsAnimatationPaused)
  196. {
  197. UnPauseAnimation();
  198. }
  199. }
  200. if (isRequestedAction)
  201. m_actionCanBeInteruptedByStand = true;
  202. if ((m_action != action) || (m_actionIndex != actionIndex))
  203. {
  204. // If we are switching from any action to a stand action, then hold the last frame of the
  205. // current animation for a moment. Only Stand actions are held; thus when any hold ends,
  206. // then we know we were holding for a Stand action.
  207. if (!(m_action == MobileAction.None) && (action == MobileAction.Stand && m_action != MobileAction.Stand))
  208. {
  209. if (m_action != MobileAction.None)
  210. PauseAnimation();
  211. }
  212. else
  213. {
  214. m_action = action;
  215. UnPauseAnimation();
  216. m_actionIndex = actionIndex;
  217. m_animationFrame = 0f;
  218. // get the frames of the base body - we need to count the number of frames in this animation.
  219. IResourceProvider provider = ServiceRegistry.GetService<IResourceProvider>();
  220. int body = Parent.Body, hue = 0;
  221. IAnimationFrame[] frames = provider.GetAnimation(body, ref hue, actionIndex, (int)Parent.DrawFacing);
  222. if (frames != null)
  223. {
  224. m_FrameCount = frames.Length;
  225. m_FrameDelay = delay;
  226. if (repeat == false)
  227. m_repeatCount = 0;
  228. else
  229. m_repeatCount = repeatCount;
  230. }
  231. }
  232. }
  233. }
  234. private void PauseAnimation()
  235. {
  236. if (!m_IsAnimatationPaused)
  237. {
  238. m_IsAnimatationPaused = true;
  239. m_AnimationPausedMS = PauseAnimationMS;
  240. }
  241. }
  242. private void UnPauseAnimation()
  243. {
  244. m_IsAnimatationPaused = false;
  245. }
  246. }
  247. }