using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Server.Station.Components; using Content.Shared.GameTicking.Components; using Content.Shared.Random.Helpers; using Content.Shared.Station.Components; using Robust.Shared.Collections; using Robust.Shared.Map; using Robust.Shared.Map.Components; namespace Content.Server.GameTicking.Rules; public abstract partial class GameRuleSystem where T: IComponent { protected EntityQueryEnumerator QueryActiveRules() { return EntityQueryEnumerator(); } protected EntityQueryEnumerator QueryDelayedRules() { return EntityQueryEnumerator(); } /// /// Queries all gamerules, regardless of if they're active or not. /// protected EntityQueryEnumerator QueryAllRules() { return EntityQueryEnumerator(); } /// /// Utility function for finding a random event-eligible station entity /// protected bool TryGetRandomStation([NotNullWhen(true)] out EntityUid? station, Func? filter = null) { var stations = new ValueList(Count()); filter ??= _ => true; var query = AllEntityQuery(); while (query.MoveNext(out var uid, out _)) { if (!filter(uid)) continue; stations.Add(uid); } if (stations.Count == 0) { station = null; return false; } // TODO: Engine PR. station = stations[RobustRandom.Next(stations.Count)]; return true; } protected bool TryFindRandomTile(out Vector2i tile, [NotNullWhen(true)] out EntityUid? targetStation, out EntityUid targetGrid, out EntityCoordinates targetCoords) { tile = default; targetStation = EntityUid.Invalid; targetGrid = EntityUid.Invalid; targetCoords = EntityCoordinates.Invalid; if (TryGetRandomStation(out targetStation)) { return TryFindRandomTileOnStation((targetStation.Value, Comp(targetStation.Value)), out tile, out targetGrid, out targetCoords); } return false; } protected bool TryFindRandomTileOnStation(Entity station, out Vector2i tile, out EntityUid targetGrid, out EntityCoordinates targetCoords) { tile = default; targetCoords = EntityCoordinates.Invalid; targetGrid = EntityUid.Invalid; // Weight grid choice by tilecount var weights = new Dictionary, float>(); foreach (var possibleTarget in station.Comp.Grids) { if (!TryComp(possibleTarget, out var comp)) continue; weights.Add((possibleTarget, comp), _map.GetAllTiles(possibleTarget, comp).Count()); } if (weights.Count == 0) { targetGrid = EntityUid.Invalid; return false; } (targetGrid, var gridComp) = RobustRandom.Pick(weights); var found = false; var aabb = gridComp.LocalAABB; for (var i = 0; i < 10; i++) { var randomX = RobustRandom.Next((int) aabb.Left, (int) aabb.Right); var randomY = RobustRandom.Next((int) aabb.Bottom, (int) aabb.Top); tile = new Vector2i(randomX, randomY); if (_atmosphere.IsTileSpace(targetGrid, Transform(targetGrid).MapUid, tile) || _atmosphere.IsTileAirBlocked(targetGrid, tile, mapGridComp: gridComp)) { continue; } found = true; targetCoords = _map.GridTileToLocal(targetGrid, gridComp, tile); break; } return found; } protected void ForceEndSelf(EntityUid uid, GameRuleComponent? component = null) { GameTicker.EndGameRule(uid, component); } }