RandomSentienceRule.cs 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. using System.Linq;
  2. using Content.Shared.Dataset;
  3. using Content.Server.Ghost.Roles.Components;
  4. using Content.Server.StationEvents.Components;
  5. using Content.Shared.GameTicking.Components;
  6. using Content.Shared.Random.Helpers;
  7. using Robust.Shared.Prototypes;
  8. using Robust.Shared.Random;
  9. namespace Content.Server.StationEvents.Events;
  10. public sealed class RandomSentienceRule : StationEventSystem<RandomSentienceRuleComponent>
  11. {
  12. [Dependency] private readonly IPrototypeManager _prototype = default!;
  13. [Dependency] private readonly IRobustRandom _random = default!;
  14. protected override void Started(EntityUid uid, RandomSentienceRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
  15. {
  16. if (!TryGetRandomStation(out var station))
  17. return;
  18. var targetList = new List<Entity<SentienceTargetComponent>>();
  19. var query = EntityQueryEnumerator<SentienceTargetComponent, TransformComponent>();
  20. while (query.MoveNext(out var targetUid, out var target, out var xform))
  21. {
  22. if (StationSystem.GetOwningStation(targetUid, xform) != station)
  23. continue;
  24. targetList.Add((targetUid, target));
  25. }
  26. var toMakeSentient = _random.Next(component.MinSentiences, component.MaxSentiences);
  27. var groups = new HashSet<string>();
  28. for (var i = 0; i < toMakeSentient && targetList.Count > 0; i++)
  29. {
  30. // weighted random to pick a sentience target
  31. var totalWeight = targetList.Sum(x => x.Comp.Weight);
  32. // This initial target should never be picked.
  33. // It's just so that target doesn't need to be nullable and as a safety fallback for id floating point errors ever mess up the comparison in the foreach.
  34. var target = targetList[0];
  35. var chosenWeight = _random.NextFloat(totalWeight);
  36. var currentWeight = 0.0;
  37. foreach (var potentialTarget in targetList)
  38. {
  39. currentWeight += potentialTarget.Comp.Weight;
  40. if (currentWeight > chosenWeight)
  41. {
  42. target = potentialTarget;
  43. break;
  44. }
  45. }
  46. targetList.Remove(target);
  47. RemComp<SentienceTargetComponent>(target);
  48. var ghostRole = EnsureComp<GhostRoleComponent>(target);
  49. EnsureComp<GhostTakeoverAvailableComponent>(target);
  50. ghostRole.RoleName = MetaData(target).EntityName;
  51. ghostRole.RoleDescription = Loc.GetString("station-event-random-sentience-role-description", ("name", ghostRole.RoleName));
  52. groups.Add(Loc.GetString(target.Comp.FlavorKind));
  53. }
  54. if (groups.Count == 0)
  55. return;
  56. var groupList = groups.ToList();
  57. var kind1 = groupList.Count > 0 ? groupList[0] : "???";
  58. var kind2 = groupList.Count > 1 ? groupList[1] : "???";
  59. var kind3 = groupList.Count > 2 ? groupList[2] : "???";
  60. ChatSystem.DispatchStationAnnouncement(
  61. station.Value,
  62. Loc.GetString("station-event-random-sentience-announcement",
  63. ("kind1", kind1), ("kind2", kind2), ("kind3", kind3), ("amount", groupList.Count),
  64. ("data", _random.Pick(_prototype.Index<LocalizedDatasetPrototype>("RandomSentienceEventData"))),
  65. ("strength", _random.Pick(_prototype.Index<LocalizedDatasetPrototype>("RandomSentienceEventStrength")))
  66. ),
  67. playDefaultSound: false,
  68. colorOverride: Color.Gold
  69. );
  70. }
  71. }