SpawnItemsOnUseSystem.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. using Content.Server.Administration.Logs;
  2. using Content.Server.Cargo.Systems;
  3. using Content.Server.Storage.Components;
  4. using Content.Shared.Database;
  5. using Content.Shared.Hands.EntitySystems;
  6. using Content.Shared.Interaction.Events;
  7. using Robust.Shared.Audio.Systems;
  8. using Robust.Shared.Map;
  9. using Robust.Shared.Random;
  10. using static Content.Shared.Storage.EntitySpawnCollection;
  11. namespace Content.Server.Storage.EntitySystems
  12. {
  13. public sealed class SpawnItemsOnUseSystem : EntitySystem
  14. {
  15. [Dependency] private readonly IRobustRandom _random = default!;
  16. [Dependency] private readonly IAdminLogManager _adminLogger = default!;
  17. [Dependency] private readonly SharedHandsSystem _hands = default!;
  18. [Dependency] private readonly PricingSystem _pricing = default!;
  19. [Dependency] private readonly SharedAudioSystem _audio = default!;
  20. [Dependency] private readonly SharedTransformSystem _transform = default!;
  21. public override void Initialize()
  22. {
  23. base.Initialize();
  24. SubscribeLocalEvent<SpawnItemsOnUseComponent, UseInHandEvent>(OnUseInHand);
  25. SubscribeLocalEvent<SpawnItemsOnUseComponent, PriceCalculationEvent>(CalculatePrice, before: new[] { typeof(PricingSystem) });
  26. }
  27. private void CalculatePrice(EntityUid uid, SpawnItemsOnUseComponent component, ref PriceCalculationEvent args)
  28. {
  29. var ungrouped = CollectOrGroups(component.Items, out var orGroups);
  30. foreach (var entry in ungrouped)
  31. {
  32. var protUid = Spawn(entry.PrototypeId, MapCoordinates.Nullspace);
  33. // Calculate the average price of the possible spawned items
  34. args.Price += _pricing.GetPrice(protUid) * entry.SpawnProbability * entry.GetAmount(getAverage: true);
  35. EntityManager.DeleteEntity(protUid);
  36. }
  37. foreach (var group in orGroups)
  38. {
  39. foreach (var entry in group.Entries)
  40. {
  41. var protUid = Spawn(entry.PrototypeId, MapCoordinates.Nullspace);
  42. // Calculate the average price of the possible spawned items
  43. args.Price += _pricing.GetPrice(protUid) *
  44. (entry.SpawnProbability / group.CumulativeProbability) *
  45. entry.GetAmount(getAverage: true);
  46. EntityManager.DeleteEntity(protUid);
  47. }
  48. }
  49. args.Handled = true;
  50. }
  51. private void OnUseInHand(EntityUid uid, SpawnItemsOnUseComponent component, UseInHandEvent args)
  52. {
  53. if (args.Handled)
  54. return;
  55. // If starting with zero or less uses, this component is a no-op
  56. if (component.Uses <= 0)
  57. return;
  58. var coords = Transform(args.User).Coordinates;
  59. var spawnEntities = GetSpawns(component.Items, _random);
  60. EntityUid? entityToPlaceInHands = null;
  61. foreach (var proto in spawnEntities)
  62. {
  63. entityToPlaceInHands = Spawn(proto, coords);
  64. _adminLogger.Add(LogType.EntitySpawn, LogImpact.Low, $"{ToPrettyString(args.User)} used {ToPrettyString(uid)} which spawned {ToPrettyString(entityToPlaceInHands.Value)}");
  65. }
  66. // The entity is often deleted, so play the sound at its position rather than parenting
  67. if (component.Sound != null)
  68. _audio.PlayPvs(component.Sound, coords);
  69. component.Uses--;
  70. // Delete entity only if component was successfully used
  71. if (component.Uses <= 0)
  72. {
  73. // Don't delete the entity in the event bus, so we queue it for deletion.
  74. // We need the free hand for the new item, so we send it to nullspace.
  75. _transform.DetachEntity(uid, Transform(uid));
  76. QueueDel(uid);
  77. }
  78. if (entityToPlaceInHands != null)
  79. _hands.PickupOrDrop(args.User, entityToPlaceInHands.Value);
  80. args.Handled = true;
  81. }
  82. }
  83. }