DoAfterArgs.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. using Content.Shared.FixedPoint;
  2. using Robust.Shared.Serialization;
  3. namespace Content.Shared.DoAfter;
  4. [Serializable, NetSerializable]
  5. [DataDefinition]
  6. public sealed partial class DoAfterArgs
  7. {
  8. /// <summary>
  9. /// The entity invoking do_after
  10. /// </summary>
  11. [NonSerialized]
  12. [DataField("user", required: true)]
  13. public EntityUid User;
  14. public NetEntity NetUser;
  15. /// <summary>
  16. /// How long does the do_after require to complete
  17. /// </summary>
  18. [DataField(required: true)]
  19. public TimeSpan Delay;
  20. /// <summary>
  21. /// Applicable target (if relevant)
  22. /// </summary>
  23. [NonSerialized]
  24. [DataField]
  25. public EntityUid? Target;
  26. public NetEntity? NetTarget;
  27. /// <summary>
  28. /// Entity used by the User on the Target.
  29. /// </summary>
  30. [NonSerialized]
  31. [DataField("using")]
  32. public EntityUid? Used;
  33. public NetEntity? NetUsed;
  34. /// <summary>
  35. /// Whether the progress bar for this DoAfter should be hidden from other players.
  36. /// </summary>
  37. [DataField]
  38. public bool Hidden;
  39. #region Event options
  40. /// <summary>
  41. /// The event that will get raised when the DoAfter has finished. If null, this will simply raise a <see cref="SimpleDoAfterEvent"/>
  42. /// </summary>
  43. [DataField(required: true)]
  44. public DoAfterEvent Event = default!;
  45. /// <summary>
  46. /// This option determines how frequently the DoAfterAttempt event will get raised. Defaults to never raising the
  47. /// event.
  48. /// </summary>
  49. [DataField("attemptEventFrequency")]
  50. public AttemptFrequency AttemptFrequency;
  51. /// <summary>
  52. /// Entity which will receive the directed event. If null, no directed event will be raised.
  53. /// </summary>
  54. [NonSerialized]
  55. [DataField]
  56. public EntityUid? EventTarget;
  57. public NetEntity? NetEventTarget;
  58. /// <summary>
  59. /// Should the DoAfter event broadcast? If this is false, then <see cref="EventTarget"/> should be a valid entity.
  60. /// </summary>
  61. [DataField]
  62. public bool Broadcast;
  63. #endregion
  64. #region Break/Cancellation Options
  65. // Break the chains
  66. /// <summary>
  67. /// Whether or not this do after requires the user to have hands.
  68. /// </summary>
  69. [DataField]
  70. public bool NeedHand;
  71. /// <summary>
  72. /// Whether we need to keep our active hand as is (i.e. can't change hand or change item). This also covers
  73. /// requiring the hand to be free (if applicable). This does nothing if <see cref="NeedHand"/> is false.
  74. /// </summary>
  75. [DataField]
  76. public bool BreakOnHandChange = true;
  77. /// <summary>
  78. /// Whether the do-after should get interrupted if we drop the
  79. /// active item we started the do-after with
  80. /// This does nothing if <see cref="NeedHand"/> is false.
  81. /// </summary>
  82. [DataField]
  83. public bool BreakOnDropItem = true;
  84. /// <summary>
  85. /// If do_after stops when the user or target moves
  86. /// </summary>
  87. [DataField]
  88. public bool BreakOnMove;
  89. /// <summary>
  90. /// Whether to break on movement when the user is weightless.
  91. /// This does nothing if <see cref="BreakOnMove"/> is false.
  92. /// </summary>
  93. [DataField]
  94. public bool BreakOnWeightlessMove = true;
  95. /// <summary>
  96. /// Threshold for user and target movement
  97. /// </summary>
  98. [DataField]
  99. public float MovementThreshold = 0.3f;
  100. /// <summary>
  101. /// Threshold for distance user from the used OR target entities.
  102. /// </summary>
  103. [DataField]
  104. public float? DistanceThreshold;
  105. /// <summary>
  106. /// Whether damage will cancel the DoAfter. See also <see cref="DamageThreshold"/>.
  107. /// </summary>
  108. [DataField]
  109. public bool BreakOnDamage;
  110. /// <summary>
  111. /// Threshold for user damage. This damage has to be dealt in a single event, not over time.
  112. /// </summary>
  113. [DataField]
  114. public FixedPoint2 DamageThreshold = 1;
  115. /// <summary>
  116. /// If true, this DoAfter will be canceled if the user can no longer interact with the target.
  117. /// </summary>
  118. [DataField]
  119. public bool RequireCanInteract = true;
  120. #endregion
  121. #region Duplicates
  122. /// <summary>
  123. /// If true, this will prevent duplicate DoAfters from being started See also <see cref="DuplicateConditions"/>.
  124. /// </summary>
  125. /// <remarks>
  126. /// Note that this will block even if the duplicate is cancelled because either DoAfter had
  127. /// <see cref="CancelDuplicate"/> enabled.
  128. /// </remarks>
  129. [DataField]
  130. public bool BlockDuplicate = true;
  131. //TODO: User pref to not cancel on second use on specific doafters
  132. /// <summary>
  133. /// If true, this will cancel any duplicate DoAfters when attempting to add a new DoAfter. See also
  134. /// <see cref="DuplicateConditions"/>.
  135. /// </summary>
  136. [DataField]
  137. public bool CancelDuplicate = true;
  138. /// <summary>
  139. /// These flags determine what DoAfter properties are used to determine whether one DoAfter is a duplicate of
  140. /// another.
  141. /// </summary>
  142. /// <remarks>
  143. /// Note that both DoAfters may have their own conditions, and they will be considered duplicated if either set
  144. /// of conditions is satisfied.
  145. /// </remarks>
  146. [DataField]
  147. public DuplicateConditions DuplicateCondition = DuplicateConditions.All;
  148. #endregion
  149. /// <summary>
  150. /// Additional conditions that need to be met. Return false to cancel.
  151. /// </summary>
  152. [NonSerialized]
  153. [Obsolete("Use checkEvent instead")]
  154. public Func<bool>? ExtraCheck;
  155. #region Constructors
  156. /// <summary>
  157. /// Creates a new set of DoAfter arguments.
  158. /// </summary>
  159. /// <param name="user">The user that will perform the DoAfter</param>
  160. /// <param name="delay">The time it takes for the DoAfter to complete</param>
  161. /// <param name="event">The event that will be raised when the DoAfter has ended (completed or cancelled).</param>
  162. /// <param name="eventTarget">The entity at which the event will be directed. If null, the event will not be directed.</param>
  163. /// <param name="target">The entity being targeted by the DoAFter. Not the same as <see cref="EventTarget"/></param>.
  164. /// <param name="used">The entity being used during the DoAfter. E.g., a tool</param>
  165. public DoAfterArgs(
  166. IEntityManager entManager,
  167. EntityUid user,
  168. TimeSpan delay,
  169. DoAfterEvent @event,
  170. EntityUid? eventTarget,
  171. EntityUid? target = null,
  172. EntityUid? used = null)
  173. {
  174. User = user;
  175. Delay = delay;
  176. Target = target;
  177. Used = used;
  178. EventTarget = eventTarget;
  179. Event = @event;
  180. NetUser = entManager.GetNetEntity(User);
  181. NetTarget = entManager.GetNetEntity(Target);
  182. NetUsed = entManager.GetNetEntity(Used);
  183. }
  184. private DoAfterArgs()
  185. {
  186. }
  187. /// <summary>
  188. /// Creates a new set of DoAfter arguments.
  189. /// </summary>
  190. /// <param name="user">The user that will perform the DoAfter</param>
  191. /// <param name="seconds">The time it takes for the DoAfter to complete, in seconds</param>
  192. /// <param name="event">The event that will be raised when the DoAfter has ended (completed or cancelled).</param>
  193. /// <param name="eventTarget">The entity at which the event will be directed. If null, the event will not be directed.</param>
  194. /// <param name="target">The entity being targeted by the DoAfter. Not the same as <see cref="EventTarget"/></param>.
  195. /// <param name="used">The entity being used during the DoAfter. E.g., a tool</param>
  196. public DoAfterArgs(
  197. IEntityManager entManager,
  198. EntityUid user,
  199. float seconds,
  200. DoAfterEvent @event,
  201. EntityUid? eventTarget,
  202. EntityUid? target = null,
  203. EntityUid? used = null)
  204. : this(entManager, user, TimeSpan.FromSeconds(seconds), @event, eventTarget, target, used)
  205. {
  206. }
  207. #endregion
  208. //The almighty pyramid returns.......
  209. public DoAfterArgs(DoAfterArgs other)
  210. {
  211. User = other.User;
  212. Delay = other.Delay;
  213. Target = other.Target;
  214. Used = other.Used;
  215. Hidden = other.Hidden;
  216. EventTarget = other.EventTarget;
  217. Broadcast = other.Broadcast;
  218. NeedHand = other.NeedHand;
  219. BreakOnHandChange = other.BreakOnHandChange;
  220. BreakOnDropItem = other.BreakOnDropItem;
  221. BreakOnMove = other.BreakOnMove;
  222. BreakOnWeightlessMove = other.BreakOnWeightlessMove;
  223. MovementThreshold = other.MovementThreshold;
  224. DistanceThreshold = other.DistanceThreshold;
  225. BreakOnDamage = other.BreakOnDamage;
  226. DamageThreshold = other.DamageThreshold;
  227. RequireCanInteract = other.RequireCanInteract;
  228. AttemptFrequency = other.AttemptFrequency;
  229. BlockDuplicate = other.BlockDuplicate;
  230. CancelDuplicate = other.CancelDuplicate;
  231. DuplicateCondition = other.DuplicateCondition;
  232. // Networked
  233. NetUser = other.NetUser;
  234. NetTarget = other.NetTarget;
  235. NetUsed = other.NetUsed;
  236. NetEventTarget = other.NetEventTarget;
  237. Event = other.Event.Clone();
  238. }
  239. }
  240. /// <summary>
  241. /// See <see cref="DoAfterArgs.DuplicateCondition"/>.
  242. /// </summary>
  243. [Flags]
  244. public enum DuplicateConditions : byte
  245. {
  246. /// <summary>
  247. /// This DoAfter will consider any other DoAfter with the same user to be a duplicate.
  248. /// </summary>
  249. None = 0,
  250. /// <summary>
  251. /// Requires that <see cref="Used"/> refers to the same entity in order to be considered a duplicate.
  252. /// </summary>
  253. /// <remarks>
  254. /// E.g., if all checks are enabled for stripping, then stripping different articles of clothing on the same
  255. /// mob would be allowed. If instead this check were disabled, then any stripping actions on the same target
  256. /// would be considered duplicates, so you would only be able to take one piece of clothing at a time.
  257. /// </remarks>
  258. SameTool = 1 << 1,
  259. /// <summary>
  260. /// Requires that <see cref="Target"/> refers to the same entity in order to be considered a duplicate.
  261. /// </summary>
  262. /// <remarks>
  263. /// E.g., if all checks are enabled for mining, then using the same pickaxe to mine different rocks will be
  264. /// allowed. If instead this check were disabled, then the trying to mine a different rock with the same
  265. /// pickaxe would be considered a duplicate DoAfter.
  266. /// </remarks>
  267. SameTarget = 1 << 2,
  268. /// <summary>
  269. /// Requires that the <see cref="Event"/> types match in order to be considered a duplicate.
  270. /// </summary>
  271. /// <remarks>
  272. /// If your DoAfter should block other unrelated DoAfters involving the same set of entities, you may want
  273. /// to disable this condition. E.g. force feeding a donk pocket and forcefully giving someone a donk pocket
  274. /// should be mutually exclusive, even though the DoAfters have unrelated effects.
  275. /// </remarks>
  276. SameEvent = 1 << 3,
  277. All = SameTool | SameTarget | SameEvent,
  278. }
  279. public enum AttemptFrequency : byte
  280. {
  281. /// <summary>
  282. /// Never raise the attempt event.
  283. /// </summary>
  284. Never = 0,
  285. /// <summary>
  286. /// Raises the attempt event when the DoAfter is about to start or end.
  287. /// </summary>
  288. StartAndEnd = 1,
  289. /// <summary>
  290. /// Raise the attempt event every tick while the DoAfter is running.
  291. /// </summary>
  292. EveryTick = 2
  293. }