UplinkSystem.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. using System.Linq;
  2. using Content.Server.Store.Systems;
  3. using Content.Server.StoreDiscount.Systems;
  4. using Content.Shared.FixedPoint;
  5. using Content.Shared.Hands.EntitySystems;
  6. using Content.Shared.Implants;
  7. using Content.Shared.Inventory;
  8. using Content.Shared.Mind;
  9. using Content.Shared.PDA;
  10. using Content.Shared.Store;
  11. using Content.Shared.Store.Components;
  12. using Robust.Shared.Prototypes;
  13. namespace Content.Server.Traitor.Uplink;
  14. public sealed class UplinkSystem : EntitySystem
  15. {
  16. [Dependency] private readonly InventorySystem _inventorySystem = default!;
  17. [Dependency] private readonly SharedHandsSystem _handsSystem = default!;
  18. [Dependency] private readonly IPrototypeManager _proto = default!;
  19. [Dependency] private readonly StoreSystem _store = default!;
  20. [Dependency] private readonly SharedSubdermalImplantSystem _subdermalImplant = default!;
  21. [Dependency] private readonly SharedMindSystem _mind = default!;
  22. [ValidatePrototypeId<CurrencyPrototype>]
  23. public const string TelecrystalCurrencyPrototype = "Telecrystal";
  24. private const string FallbackUplinkImplant = "UplinkImplant";
  25. private const string FallbackUplinkCatalog = "UplinkUplinkImplanter";
  26. /// <summary>
  27. /// Adds an uplink to the target
  28. /// </summary>
  29. /// <param name="user">The person who is getting the uplink</param>
  30. /// <param name="balance">The amount of currency on the uplink. If null, will just use the amount specified in the preset.</param>
  31. /// <param name="uplinkEntity">The entity that will actually have the uplink functionality. Defaults to the PDA if null.</param>
  32. /// <param name="giveDiscounts">Marker that enables discounts for uplink items.</param>
  33. /// <returns>Whether or not the uplink was added successfully</returns>
  34. public bool AddUplink(
  35. EntityUid user,
  36. FixedPoint2 balance,
  37. EntityUid? uplinkEntity = null,
  38. bool giveDiscounts = false)
  39. {
  40. // Try to find target item if none passed
  41. uplinkEntity ??= FindUplinkTarget(user);
  42. if (uplinkEntity == null)
  43. return ImplantUplink(user, balance, giveDiscounts);
  44. EnsureComp<UplinkComponent>(uplinkEntity.Value);
  45. SetUplink(user, uplinkEntity.Value, balance, giveDiscounts);
  46. // TODO add BUI. Currently can't be done outside of yaml -_-
  47. // ^ What does this even mean?
  48. return true;
  49. }
  50. /// <summary>
  51. /// Configure TC for the uplink
  52. /// </summary>
  53. private void SetUplink(EntityUid user, EntityUid uplink, FixedPoint2 balance, bool giveDiscounts)
  54. {
  55. if (!_mind.TryGetMind(user, out var mind, out _))
  56. return;
  57. var store = EnsureComp<StoreComponent>(uplink);
  58. store.AccountOwner = mind;
  59. store.Balance.Clear();
  60. _store.TryAddCurrency(new Dictionary<string, FixedPoint2> { { TelecrystalCurrencyPrototype, balance } },
  61. uplink,
  62. store);
  63. var uplinkInitializedEvent = new StoreInitializedEvent(
  64. TargetUser: mind,
  65. Store: uplink,
  66. UseDiscounts: giveDiscounts,
  67. Listings: _store.GetAvailableListings(mind, uplink, store)
  68. .ToArray());
  69. RaiseLocalEvent(ref uplinkInitializedEvent);
  70. }
  71. /// <summary>
  72. /// Implant an uplink as a fallback measure if the traitor had no PDA
  73. /// </summary>
  74. private bool ImplantUplink(EntityUid user, FixedPoint2 balance, bool giveDiscounts)
  75. {
  76. var implantProto = new string(FallbackUplinkImplant);
  77. if (!_proto.TryIndex<ListingPrototype>(FallbackUplinkCatalog, out var catalog))
  78. return false;
  79. if (!catalog.Cost.TryGetValue(TelecrystalCurrencyPrototype, out var cost))
  80. return false;
  81. if (balance < cost) // Can't use Math functions on FixedPoint2
  82. balance = 0;
  83. else
  84. balance = balance - cost;
  85. var implant = _subdermalImplant.AddImplant(user, implantProto);
  86. if (!HasComp<StoreComponent>(implant))
  87. return false;
  88. SetUplink(user, implant.Value, balance, giveDiscounts);
  89. return true;
  90. }
  91. /// <summary>
  92. /// Finds the entity that can hold an uplink for a user.
  93. /// Usually this is a pda in their pda slot, but can also be in their hands. (but not pockets or inside bag, etc.)
  94. /// </summary>
  95. public EntityUid? FindUplinkTarget(EntityUid user)
  96. {
  97. // Try to find PDA in inventory
  98. if (_inventorySystem.TryGetContainerSlotEnumerator(user, out var containerSlotEnumerator))
  99. {
  100. while (containerSlotEnumerator.MoveNext(out var pdaUid))
  101. {
  102. if (!pdaUid.ContainedEntity.HasValue)
  103. continue;
  104. if (HasComp<PdaComponent>(pdaUid.ContainedEntity.Value) || HasComp<StoreComponent>(pdaUid.ContainedEntity.Value))
  105. return pdaUid.ContainedEntity.Value;
  106. }
  107. }
  108. // Also check hands
  109. foreach (var item in _handsSystem.EnumerateHeld(user))
  110. {
  111. if (HasComp<PdaComponent>(item) || HasComp<StoreComponent>(item))
  112. return item;
  113. }
  114. return null;
  115. }
  116. }