RevenantSystem.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. using System.Numerics;
  2. using Content.Server.Actions;
  3. using Content.Server.GameTicking;
  4. using Content.Server.Store.Components;
  5. using Content.Server.Store.Systems;
  6. using Content.Shared.Alert;
  7. using Content.Shared.Damage;
  8. using Content.Shared.DoAfter;
  9. using Content.Shared.Examine;
  10. using Content.Shared.Eye;
  11. using Content.Shared.FixedPoint;
  12. using Content.Shared.Interaction;
  13. using Content.Shared.Maps;
  14. using Content.Shared.Mobs.Systems;
  15. using Content.Shared.Physics;
  16. using Content.Shared.Popups;
  17. using Content.Shared.Revenant;
  18. using Content.Shared.Revenant.Components;
  19. using Content.Shared.StatusEffect;
  20. using Content.Shared.Store.Components;
  21. using Content.Shared.Stunnable;
  22. using Content.Shared.Tag;
  23. using Robust.Server.GameObjects;
  24. using Robust.Shared.Prototypes;
  25. using Robust.Shared.Random;
  26. namespace Content.Server.Revenant.EntitySystems;
  27. public sealed partial class RevenantSystem : EntitySystem
  28. {
  29. [Dependency] private readonly IRobustRandom _random = default!;
  30. [Dependency] private readonly ActionsSystem _action = default!;
  31. [Dependency] private readonly AlertsSystem _alerts = default!;
  32. [Dependency] private readonly DamageableSystem _damage = default!;
  33. [Dependency] private readonly EntityLookupSystem _lookup = default!;
  34. [Dependency] private readonly GameTicker _ticker = default!;
  35. [Dependency] private readonly MobStateSystem _mobState = default!;
  36. [Dependency] private readonly PhysicsSystem _physics = default!;
  37. [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
  38. [Dependency] private readonly SharedEyeSystem _eye = default!;
  39. [Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
  40. [Dependency] private readonly SharedInteractionSystem _interact = default!;
  41. [Dependency] private readonly SharedPopupSystem _popup = default!;
  42. [Dependency] private readonly SharedStunSystem _stun = default!;
  43. [Dependency] private readonly StoreSystem _store = default!;
  44. [Dependency] private readonly TagSystem _tag = default!;
  45. [Dependency] private readonly VisibilitySystem _visibility = default!;
  46. [ValidatePrototypeId<EntityPrototype>]
  47. private const string RevenantShopId = "ActionRevenantShop";
  48. public override void Initialize()
  49. {
  50. base.Initialize();
  51. SubscribeLocalEvent<RevenantComponent, ComponentStartup>(OnStartup);
  52. SubscribeLocalEvent<RevenantComponent, MapInitEvent>(OnMapInit);
  53. SubscribeLocalEvent<RevenantComponent, RevenantShopActionEvent>(OnShop);
  54. SubscribeLocalEvent<RevenantComponent, DamageChangedEvent>(OnDamage);
  55. SubscribeLocalEvent<RevenantComponent, ExaminedEvent>(OnExamine);
  56. SubscribeLocalEvent<RevenantComponent, StatusEffectAddedEvent>(OnStatusAdded);
  57. SubscribeLocalEvent<RevenantComponent, StatusEffectEndedEvent>(OnStatusEnded);
  58. SubscribeLocalEvent<RoundEndTextAppendEvent>(_ => MakeVisible(true));
  59. SubscribeLocalEvent<RevenantComponent, GetVisMaskEvent>(OnRevenantGetVis);
  60. InitializeAbilities();
  61. }
  62. private void OnRevenantGetVis(Entity<RevenantComponent> ent, ref GetVisMaskEvent args)
  63. {
  64. args.VisibilityMask |= (int)VisibilityFlags.Ghost;
  65. }
  66. private void OnStartup(EntityUid uid, RevenantComponent component, ComponentStartup args)
  67. {
  68. //update the icon
  69. ChangeEssenceAmount(uid, 0, component);
  70. //default the visuals
  71. _appearance.SetData(uid, RevenantVisuals.Corporeal, false);
  72. _appearance.SetData(uid, RevenantVisuals.Harvesting, false);
  73. _appearance.SetData(uid, RevenantVisuals.Stunned, false);
  74. if (_ticker.RunLevel == GameRunLevel.PostRound && TryComp<VisibilityComponent>(uid, out var visibility))
  75. {
  76. _visibility.AddLayer((uid, visibility), (int) VisibilityFlags.Ghost, false);
  77. _visibility.RemoveLayer((uid, visibility), (int) VisibilityFlags.Normal, false);
  78. _visibility.RefreshVisibility(uid, visibility);
  79. }
  80. //ghost vision
  81. _eye.RefreshVisibilityMask(uid);
  82. }
  83. private void OnMapInit(EntityUid uid, RevenantComponent component, MapInitEvent args)
  84. {
  85. _action.AddAction(uid, ref component.Action, RevenantShopId);
  86. }
  87. private void OnStatusAdded(EntityUid uid, RevenantComponent component, StatusEffectAddedEvent args)
  88. {
  89. if (args.Key == "Stun")
  90. _appearance.SetData(uid, RevenantVisuals.Stunned, true);
  91. }
  92. private void OnStatusEnded(EntityUid uid, RevenantComponent component, StatusEffectEndedEvent args)
  93. {
  94. if (args.Key == "Stun")
  95. _appearance.SetData(uid, RevenantVisuals.Stunned, false);
  96. }
  97. private void OnExamine(EntityUid uid, RevenantComponent component, ExaminedEvent args)
  98. {
  99. if (args.Examiner == args.Examined)
  100. {
  101. args.PushMarkup(Loc.GetString("revenant-essence-amount",
  102. ("current", component.Essence.Int()), ("max", component.EssenceRegenCap.Int())));
  103. }
  104. }
  105. private void OnDamage(EntityUid uid, RevenantComponent component, DamageChangedEvent args)
  106. {
  107. if (!HasComp<CorporealComponent>(uid) || args.DamageDelta == null)
  108. return;
  109. var essenceDamage = args.DamageDelta.GetTotal().Float() * component.DamageToEssenceCoefficient * -1;
  110. ChangeEssenceAmount(uid, essenceDamage, component);
  111. }
  112. public bool ChangeEssenceAmount(EntityUid uid, FixedPoint2 amount, RevenantComponent? component = null, bool allowDeath = true, bool regenCap = false)
  113. {
  114. if (!Resolve(uid, ref component))
  115. return false;
  116. if (!allowDeath && component.Essence + amount <= 0)
  117. return false;
  118. component.Essence += amount;
  119. Dirty(uid, component);
  120. if (regenCap)
  121. FixedPoint2.Min(component.Essence, component.EssenceRegenCap);
  122. if (TryComp<StoreComponent>(uid, out var store))
  123. _store.UpdateUserInterface(uid, uid, store);
  124. _alerts.ShowAlert(uid, component.EssenceAlert);
  125. if (component.Essence <= 0)
  126. {
  127. Spawn(component.SpawnOnDeathPrototype, Transform(uid).Coordinates);
  128. QueueDel(uid);
  129. }
  130. return true;
  131. }
  132. private bool TryUseAbility(EntityUid uid, RevenantComponent component, FixedPoint2 abilityCost, Vector2 debuffs)
  133. {
  134. if (component.Essence <= abilityCost)
  135. {
  136. _popup.PopupEntity(Loc.GetString("revenant-not-enough-essence"), uid, uid);
  137. return false;
  138. }
  139. var tileref = Transform(uid).Coordinates.GetTileRef();
  140. if (tileref != null)
  141. {
  142. if(_physics.GetEntitiesIntersectingBody(uid, (int) CollisionGroup.Impassable).Count > 0)
  143. {
  144. _popup.PopupEntity(Loc.GetString("revenant-in-solid"), uid, uid);
  145. return false;
  146. }
  147. }
  148. ChangeEssenceAmount(uid, -abilityCost, component, false);
  149. _statusEffects.TryAddStatusEffect<CorporealComponent>(uid, "Corporeal", TimeSpan.FromSeconds(debuffs.Y), false);
  150. _stun.TryStun(uid, TimeSpan.FromSeconds(debuffs.X), false);
  151. return true;
  152. }
  153. private void OnShop(EntityUid uid, RevenantComponent component, RevenantShopActionEvent args)
  154. {
  155. if (!TryComp<StoreComponent>(uid, out var store))
  156. return;
  157. _store.ToggleUi(uid, uid, store);
  158. }
  159. public void MakeVisible(bool visible)
  160. {
  161. var query = EntityQueryEnumerator<RevenantComponent, VisibilityComponent>();
  162. while (query.MoveNext(out var uid, out _, out var vis))
  163. {
  164. if (visible)
  165. {
  166. _visibility.AddLayer((uid, vis), (int) VisibilityFlags.Normal, false);
  167. _visibility.RemoveLayer((uid, vis), (int) VisibilityFlags.Ghost, false);
  168. }
  169. else
  170. {
  171. _visibility.AddLayer((uid, vis), (int) VisibilityFlags.Ghost, false);
  172. _visibility.RemoveLayer((uid, vis), (int) VisibilityFlags.Normal, false);
  173. }
  174. _visibility.RefreshVisibility(uid, vis);
  175. }
  176. }
  177. public override void Update(float frameTime)
  178. {
  179. base.Update(frameTime);
  180. var query = EntityQueryEnumerator<RevenantComponent>();
  181. while (query.MoveNext(out var uid, out var rev))
  182. {
  183. rev.Accumulator += frameTime;
  184. if (rev.Accumulator <= 1)
  185. continue;
  186. rev.Accumulator -= 1;
  187. if (rev.Essence < rev.EssenceRegenCap)
  188. {
  189. ChangeEssenceAmount(uid, rev.EssencePerSecond, rev, regenCap: true);
  190. }
  191. }
  192. }
  193. }