DoorComponent.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. using Content.Shared.Damage;
  2. using Content.Shared.Doors.Systems;
  3. using Content.Shared.Tools;
  4. using JetBrains.Annotations;
  5. using Robust.Shared.Audio;
  6. using Robust.Shared.GameStates;
  7. using Robust.Shared.Prototypes;
  8. using Robust.Shared.Serialization;
  9. using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
  10. using Robust.Shared.Timing;
  11. using DrawDepthTag = Robust.Shared.GameObjects.DrawDepth;
  12. namespace Content.Shared.Doors.Components;
  13. [RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
  14. public sealed partial class DoorComponent : Component
  15. {
  16. /// <summary>
  17. /// The current state of the door -- whether it is open, closed, opening, or closing.
  18. /// </summary>
  19. /// <remarks>
  20. /// This should never be set directly, use <see cref="SharedDoorSystem.SetState(EntityUid, DoorState, DoorComponent?)"/> instead.
  21. /// </remarks>
  22. [ViewVariables(VVAccess.ReadWrite)]
  23. [DataField, AutoNetworkedField]
  24. [Access(typeof(SharedDoorSystem))]
  25. public DoorState State = DoorState.Closed;
  26. #region Timing
  27. // if you want do dynamically adjust these times, you need to add networking for them. So for now, they are all
  28. // read-only.
  29. /// <summary>
  30. /// Closing time until impassable. Total time is this plus <see cref="CloseTimeTwo"/>.
  31. /// </summary>
  32. [DataField]
  33. public TimeSpan CloseTimeOne = TimeSpan.FromSeconds(0.4f);
  34. /// <summary>
  35. /// Closing time until fully closed. Total time is this plus <see cref="CloseTimeOne"/>.
  36. /// </summary>
  37. [DataField]
  38. public TimeSpan CloseTimeTwo = TimeSpan.FromSeconds(0.2f);
  39. /// <summary>
  40. /// Opening time until passable. Total time is this plus <see cref="OpenTimeTwo"/>.
  41. /// </summary>
  42. [DataField]
  43. public TimeSpan OpenTimeOne = TimeSpan.FromSeconds(0.4f);
  44. /// <summary>
  45. /// Opening time until fully open. Total time is this plus <see cref="OpenTimeOne"/>.
  46. /// </summary>
  47. [DataField]
  48. public TimeSpan OpenTimeTwo = TimeSpan.FromSeconds(0.2f);
  49. /// <summary>
  50. /// Interval between deny sounds & visuals;
  51. /// </summary>
  52. [DataField]
  53. public TimeSpan DenyDuration = TimeSpan.FromSeconds(0.45f);
  54. [DataField]
  55. public TimeSpan EmagDuration = TimeSpan.FromSeconds(0.8f);
  56. /// <summary>
  57. /// When the door is active, this is the time when the state will next update.
  58. /// </summary>
  59. [AutoNetworkedField, ViewVariables]
  60. public TimeSpan? NextStateChange;
  61. /// <summary>
  62. /// Whether the door is currently partially closed or open. I.e., when the door is "closing" and is already opaque,
  63. /// but not yet actually closed.
  64. /// </summary>
  65. [DataField, AutoNetworkedField]
  66. public bool Partial;
  67. #endregion
  68. #region Sounds
  69. /// <summary>
  70. /// Sound to play when the door opens.
  71. /// </summary>
  72. [DataField("openSound")]
  73. public SoundSpecifier? OpenSound;
  74. /// <summary>
  75. /// Sound to play when the door closes.
  76. /// </summary>
  77. [DataField("closeSound")]
  78. public SoundSpecifier? CloseSound;
  79. /// <summary>
  80. /// Sound to play if the door is denied.
  81. /// </summary>
  82. [DataField("denySound")]
  83. public SoundSpecifier? DenySound;
  84. /// <summary>
  85. /// Sound to play when door has been emagged or possibly electrically tampered
  86. /// </summary>
  87. [DataField("sparkSound")]
  88. public SoundSpecifier SparkSound = new SoundCollectionSpecifier("sparks");
  89. #endregion
  90. #region Crushing
  91. /// <summary>
  92. /// This is how long a door-crush will stun you. This also determines how long it takes the door to open up
  93. /// again. Total stun time is actually given by this plus <see cref="OpenTimeOne"/>.
  94. /// </summary>
  95. [DataField]
  96. public TimeSpan DoorStunTime = TimeSpan.FromSeconds(2f);
  97. [DataField]
  98. public DamageSpecifier? CrushDamage;
  99. /// <summary>
  100. /// If false, this door is incapable of crushing entities. This just determines whether it will apply damage and
  101. /// stun, not whether it can close despite entities being in the way.
  102. /// </summary>
  103. [DataField, AutoNetworkedField]
  104. public bool CanCrush = true;
  105. /// <summary>
  106. /// Whether to check for colliding entities before closing. This may be overridden by other system by subscribing to
  107. /// <see cref="BeforeDoorClosedEvent"/>. For example, hacked airlocks will set this to false.
  108. /// </summary>
  109. [DataField, AutoNetworkedField]
  110. public bool PerformCollisionCheck = true;
  111. /// <summary>
  112. /// List of EntityUids of entities we're currently crushing. Cleared in OnPartialOpen().
  113. /// </summary>
  114. [DataField, AutoNetworkedField]
  115. public HashSet<EntityUid> CurrentlyCrushing = new();
  116. #endregion
  117. #region Graphics
  118. /// <summary>
  119. /// The key used when playing door opening/closing/emagging/deny animations.
  120. /// </summary>
  121. public const string AnimationKey = "door_animation";
  122. /// <summary>
  123. /// The sprite state used for the door when it's open.
  124. /// </summary>
  125. [DataField]
  126. [ViewVariables(VVAccess.ReadWrite)]
  127. public string OpenSpriteState = "open";
  128. /// <summary>
  129. /// The sprite states used for the door while it's open.
  130. /// </summary>
  131. [ViewVariables(VVAccess.ReadOnly)]
  132. public List<(DoorVisualLayers, string)> OpenSpriteStates = default!;
  133. /// <summary>
  134. /// The sprite state used for the door when it's closed.
  135. /// </summary>
  136. [DataField]
  137. [ViewVariables(VVAccess.ReadWrite)]
  138. public string ClosedSpriteState = "closed";
  139. /// <summary>
  140. /// The sprite states used for the door while it's closed.
  141. /// </summary>
  142. [ViewVariables(VVAccess.ReadOnly)]
  143. public List<(DoorVisualLayers, string)> ClosedSpriteStates = default!;
  144. /// <summary>
  145. /// The sprite state used for the door when it's opening.
  146. /// </summary>
  147. [DataField]
  148. public string OpeningSpriteState = "opening";
  149. /// <summary>
  150. /// The sprite state used for the door when it's closing.
  151. /// </summary>
  152. [DataField]
  153. public string ClosingSpriteState = "closing";
  154. /// <summary>
  155. /// The sprite state used for the door when it's being emagged.
  156. /// </summary>
  157. [DataField]
  158. public string EmaggingSpriteState = "sparks";
  159. /// <summary>
  160. /// The sprite state used for the door when it's open.
  161. /// </summary>
  162. [DataField]
  163. public float OpeningAnimationTime = 0.8f;
  164. /// <summary>
  165. /// The sprite state used for the door when it's open.
  166. /// </summary>
  167. [DataField]
  168. public float ClosingAnimationTime = 0.8f;
  169. /// <summary>
  170. /// The sprite state used for the door when it's open.
  171. /// </summary>
  172. [DataField]
  173. public float EmaggingAnimationTime = 1.5f;
  174. /// <summary>
  175. /// The animation used when the door opens.
  176. /// </summary>
  177. public object OpeningAnimation = default!;
  178. /// <summary>
  179. /// The animation used when the door closes.
  180. /// </summary>
  181. public object ClosingAnimation = default!;
  182. /// <summary>
  183. /// The animation used when the door denies access.
  184. /// </summary>
  185. public object DenyingAnimation = default!;
  186. /// <summary>
  187. /// The animation used when the door is emagged.
  188. /// </summary>
  189. public object EmaggingAnimation = default!;
  190. #endregion Graphics
  191. #region Serialization
  192. /// <summary>
  193. /// Time until next state change. Because apparently <see cref="IGameTiming.CurTime"/> might not get saved/restored.
  194. /// </summary>
  195. [DataField]
  196. private float? SecondsUntilStateChange
  197. {
  198. [UsedImplicitly]
  199. get
  200. {
  201. if (NextStateChange == null)
  202. {
  203. return null;
  204. }
  205. var curTime = IoCManager.Resolve<IGameTiming>().CurTime;
  206. return (float)(NextStateChange.Value - curTime).TotalSeconds;
  207. }
  208. set
  209. {
  210. if (value == null || value.Value > 0)
  211. return;
  212. NextStateChange = IoCManager.Resolve<IGameTiming>().CurTime + TimeSpan.FromSeconds(value.Value);
  213. }
  214. }
  215. #endregion
  216. [DataField, ViewVariables(VVAccess.ReadWrite)]
  217. public bool CanPry = true;
  218. [DataField]
  219. public ProtoId<ToolQualityPrototype> PryingQuality = "Prying";
  220. /// <summary>
  221. /// Default time that the door should take to pry open.
  222. /// </summary>
  223. [DataField, ViewVariables(VVAccess.ReadWrite)]
  224. public float PryTime = 1.5f;
  225. [DataField]
  226. public bool ChangeAirtight = true;
  227. /// <summary>
  228. /// Whether the door blocks light.
  229. /// </summary>
  230. [ViewVariables(VVAccess.ReadWrite)]
  231. [DataField]
  232. public bool Occludes = true;
  233. /// <summary>
  234. /// Whether the door will open when it is bumped into.
  235. /// </summary>
  236. [ViewVariables(VVAccess.ReadWrite)]
  237. [DataField]
  238. public bool BumpOpen = true;
  239. /// <summary>
  240. /// Whether the door will open when it is activated or clicked.
  241. /// </summary>
  242. [ViewVariables(VVAccess.ReadWrite)]
  243. [DataField]
  244. public bool ClickOpen = true;
  245. [DataField(customTypeSerializer: typeof(ConstantSerializer<DrawDepthTag>))]
  246. public int OpenDrawDepth = (int) DrawDepth.DrawDepth.Doors;
  247. [DataField(customTypeSerializer: typeof(ConstantSerializer<DrawDepthTag>))]
  248. public int ClosedDrawDepth = (int) DrawDepth.DrawDepth.Doors;
  249. }
  250. [Serializable, NetSerializable]
  251. public enum DoorState : byte
  252. {
  253. Closed,
  254. Closing,
  255. Open,
  256. Opening,
  257. Welded,
  258. Denying,
  259. Emagging
  260. }
  261. [Serializable, NetSerializable]
  262. public enum DoorVisuals : byte
  263. {
  264. State,
  265. BoltLights,
  266. EmergencyLights,
  267. ClosedLights,
  268. BaseRSI,
  269. }
  270. public enum DoorVisualLayers : byte
  271. {
  272. Base,
  273. BaseUnlit,
  274. BaseBolted,
  275. BaseEmergencyAccess,
  276. }