SharedBodySystem.Organs.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. using System.Diagnostics.CodeAnalysis;
  2. using Content.Shared.Body.Components;
  3. using Content.Shared.Body.Events;
  4. using Content.Shared.Body.Organ;
  5. using Content.Shared.Body.Part;
  6. using Robust.Shared.Containers;
  7. namespace Content.Shared.Body.Systems;
  8. public partial class SharedBodySystem
  9. {
  10. private void AddOrgan(
  11. Entity<OrganComponent> organEnt,
  12. EntityUid bodyUid,
  13. EntityUid parentPartUid)
  14. {
  15. organEnt.Comp.Body = bodyUid;
  16. var addedEv = new OrganAddedEvent(parentPartUid);
  17. RaiseLocalEvent(organEnt, ref addedEv);
  18. if (organEnt.Comp.Body is not null)
  19. {
  20. var addedInBodyEv = new OrganAddedToBodyEvent(bodyUid, parentPartUid);
  21. RaiseLocalEvent(organEnt, ref addedInBodyEv);
  22. }
  23. Dirty(organEnt, organEnt.Comp);
  24. }
  25. private void RemoveOrgan(Entity<OrganComponent> organEnt, EntityUid parentPartUid)
  26. {
  27. var removedEv = new OrganRemovedEvent(parentPartUid);
  28. RaiseLocalEvent(organEnt, ref removedEv);
  29. if (organEnt.Comp.Body is { Valid: true } bodyUid)
  30. {
  31. var removedInBodyEv = new OrganRemovedFromBodyEvent(bodyUid, parentPartUid);
  32. RaiseLocalEvent(organEnt, ref removedInBodyEv);
  33. }
  34. organEnt.Comp.Body = null;
  35. Dirty(organEnt, organEnt.Comp);
  36. }
  37. /// <summary>
  38. /// Creates the specified organ slot on the parent entity.
  39. /// </summary>
  40. private OrganSlot? CreateOrganSlot(Entity<BodyPartComponent?> parentEnt, string slotId)
  41. {
  42. if (!Resolve(parentEnt, ref parentEnt.Comp, logMissing: false))
  43. return null;
  44. Containers.EnsureContainer<ContainerSlot>(parentEnt, GetOrganContainerId(slotId));
  45. var slot = new OrganSlot(slotId);
  46. parentEnt.Comp.Organs.Add(slotId, slot);
  47. return slot;
  48. }
  49. /// <summary>
  50. /// Attempts to create the specified organ slot on the specified parent if it exists.
  51. /// </summary>
  52. public bool TryCreateOrganSlot(
  53. EntityUid? parent,
  54. string slotId,
  55. [NotNullWhen(true)] out OrganSlot? slot,
  56. BodyPartComponent? part = null)
  57. {
  58. slot = null;
  59. if (parent is null || !Resolve(parent.Value, ref part, logMissing: false))
  60. {
  61. return false;
  62. }
  63. Containers.EnsureContainer<ContainerSlot>(parent.Value, GetOrganContainerId(slotId));
  64. slot = new OrganSlot(slotId);
  65. return part.Organs.TryAdd(slotId, slot.Value);
  66. }
  67. /// <summary>
  68. /// Returns whether the slotId exists on the partId.
  69. /// </summary>
  70. public bool CanInsertOrgan(
  71. EntityUid partId,
  72. string slotId,
  73. BodyPartComponent? part = null)
  74. {
  75. return Resolve(partId, ref part) && part.Organs.ContainsKey(slotId);
  76. }
  77. /// <summary>
  78. /// Returns whether the specified organ slot exists on the partId.
  79. /// </summary>
  80. public bool CanInsertOrgan(
  81. EntityUid partId,
  82. OrganSlot slot,
  83. BodyPartComponent? part = null)
  84. {
  85. return CanInsertOrgan(partId, slot.Id, part);
  86. }
  87. public bool InsertOrgan(
  88. EntityUid partId,
  89. EntityUid organId,
  90. string slotId,
  91. BodyPartComponent? part = null,
  92. OrganComponent? organ = null)
  93. {
  94. if (!Resolve(organId, ref organ, logMissing: false)
  95. || !Resolve(partId, ref part, logMissing: false)
  96. || !CanInsertOrgan(partId, slotId, part))
  97. {
  98. return false;
  99. }
  100. var containerId = GetOrganContainerId(slotId);
  101. return Containers.TryGetContainer(partId, containerId, out var container)
  102. && Containers.Insert(organId, container);
  103. }
  104. /// <summary>
  105. /// Removes the organ if it is inside of a body part.
  106. /// </summary>
  107. public bool RemoveOrgan(EntityUid organId, OrganComponent? organ = null)
  108. {
  109. if (!Containers.TryGetContainingContainer((organId, null, null), out var container))
  110. return false;
  111. var parent = container.Owner;
  112. return HasComp<BodyPartComponent>(parent)
  113. && Containers.Remove(organId, container);
  114. }
  115. /// <summary>
  116. /// Tries to add this organ to any matching slot on this body part.
  117. /// </summary>
  118. public bool AddOrganToFirstValidSlot(
  119. EntityUid partId,
  120. EntityUid organId,
  121. BodyPartComponent? part = null,
  122. OrganComponent? organ = null)
  123. {
  124. if (!Resolve(partId, ref part, logMissing: false)
  125. || !Resolve(organId, ref organ, logMissing: false))
  126. {
  127. return false;
  128. }
  129. foreach (var slotId in part.Organs.Keys)
  130. {
  131. InsertOrgan(partId, organId, slotId, part, organ);
  132. return true;
  133. }
  134. return false;
  135. }
  136. /// <summary>
  137. /// Returns a list of Entity<<see cref="T"/>, <see cref="OrganComponent"/>>
  138. /// for each organ of the body
  139. /// </summary>
  140. /// <typeparam name="T">The component that we want to return</typeparam>
  141. /// <param name="entity">The body to check the organs of</param>
  142. public List<Entity<T, OrganComponent>> GetBodyOrganEntityComps<T>(
  143. Entity<BodyComponent?> entity)
  144. where T : IComponent
  145. {
  146. if (!Resolve(entity, ref entity.Comp))
  147. return new List<Entity<T, OrganComponent>>();
  148. var query = GetEntityQuery<T>();
  149. var list = new List<Entity<T, OrganComponent>>(3);
  150. foreach (var organ in GetBodyOrgans(entity.Owner, entity.Comp))
  151. {
  152. if (query.TryGetComponent(organ.Id, out var comp))
  153. list.Add((organ.Id, comp, organ.Component));
  154. }
  155. return list;
  156. }
  157. /// <summary>
  158. /// Tries to get a list of ValueTuples of <see cref="T"/> and OrganComponent on each organs
  159. /// in the given body.
  160. /// </summary>
  161. /// <param name="uid">The body entity id to check on.</param>
  162. /// <param name="comps">The list of components.</param>
  163. /// <param name="body">The body to check for organs on.</param>
  164. /// <typeparam name="T">The component to check for.</typeparam>
  165. /// <returns>Whether any were found.</returns>
  166. public bool TryGetBodyOrganEntityComps<T>(
  167. Entity<BodyComponent?> entity,
  168. [NotNullWhen(true)] out List<Entity<T, OrganComponent>>? comps)
  169. where T : IComponent
  170. {
  171. if (!Resolve(entity.Owner, ref entity.Comp))
  172. {
  173. comps = null;
  174. return false;
  175. }
  176. comps = GetBodyOrganEntityComps<T>(entity);
  177. if (comps.Count != 0)
  178. return true;
  179. comps = null;
  180. return false;
  181. }
  182. }