diff --git a/Content.Server/Nyanotrasen/Abilities/Felinid/FelinidSystem.cs b/Content.Server/Nyanotrasen/Abilities/Felinid/FelinidSystem.cs index e066da5c2f3..28213f71350 100644 --- a/Content.Server/Nyanotrasen/Abilities/Felinid/FelinidSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Felinid/FelinidSystem.cs @@ -21,6 +21,7 @@ using Robust.Shared.Prototypes; using Content.Shared.Nutrition.EntitySystems; using Content.Shared.Nyanotrasen.Abilities; +using Content.Shared.CombatMode.Pacification; // Frontier namespace Content.Server.Abilities.Felinid { @@ -47,6 +48,8 @@ public override void Initialize() SubscribeLocalEvent(OnUnequipped); SubscribeLocalEvent(OnHairballHit); SubscribeLocalEvent(OnHairballPickupAttempt); + + SubscribeLocalEvent(OnHairballAttemptPacifiedThrow); // Frontier - Block hairball abuse } private Queue RemQueue = new(); @@ -190,6 +193,11 @@ private void OnHairballPickupAttempt(EntityUid uid, HairballComponent component, args.Cancel(); } } + + private void OnHairballAttemptPacifiedThrow(Entity ent, ref AttemptPacifiedThrowEvent args) // Frontier - Block hairball abuse + { + args.Cancel("pacified-cannot-throw-hairball"); + } } } diff --git a/Content.Server/_NF/PacifiedZone/PacifiedByZoneComponent.cs b/Content.Server/_NF/PacifiedZone/PacifiedByZoneComponent.cs new file mode 100644 index 00000000000..432344d4b9d --- /dev/null +++ b/Content.Server/_NF/PacifiedZone/PacifiedByZoneComponent.cs @@ -0,0 +1,10 @@ +namespace Content.Server._NF.PacifiedZone +{ + // Denotes an entity as being pacified by a zone. + // An entity with PacifiedComponent but not PacifiedByZoneComponent is naturally pacified + // (e.g. through Pax, or the Pious trait) + [RegisterComponent] + public sealed partial class PacifiedByZoneComponent : Component + { + } +} \ No newline at end of file diff --git a/Content.Server/_NF/PacifiedZone/PacifiedZoneGeneratorComponent.cs b/Content.Server/_NF/PacifiedZone/PacifiedZoneGeneratorComponent.cs new file mode 100644 index 00000000000..bf26f399f95 --- /dev/null +++ b/Content.Server/_NF/PacifiedZone/PacifiedZoneGeneratorComponent.cs @@ -0,0 +1,27 @@ +using Robust.Shared.Prototypes; +using Content.Shared.Roles; + +namespace Content.Server._NF.PacifiedZone +{ + [RegisterComponent] + public sealed partial class PacifiedZoneGeneratorComponent : Component + { + [ViewVariables] + public List TrackedEntities = new(); + + [ViewVariables] + public TimeSpan NextUpdate; + + /// + /// The interval at which this component updates. + /// + [DataField] + public TimeSpan UpdateInterval = TimeSpan.FromSeconds(1); + + [DataField] + public int Radius = 5; + + [DataField] + public List> ImmuneRoles = new(); + } +} \ No newline at end of file diff --git a/Content.Server/_NF/PacifiedZone/PacifiedZoneGeneratorSystem.cs b/Content.Server/_NF/PacifiedZone/PacifiedZoneGeneratorSystem.cs new file mode 100644 index 00000000000..da6591a6237 --- /dev/null +++ b/Content.Server/_NF/PacifiedZone/PacifiedZoneGeneratorSystem.cs @@ -0,0 +1,132 @@ +using Robust.Shared.Timing; +using Content.Shared.Alert; +using Content.Shared.CombatMode.Pacification; +using Content.Shared.Humanoid; +using Content.Shared.Mind; +using Content.Shared.Roles.Jobs; + +namespace Content.Server._NF.PacifiedZone +{ + public sealed class PacifiedZoneGeneratorSystem : EntitySystem + { + [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly SharedMindSystem _mindSystem = default!; + [Dependency] private readonly SharedJobSystem _jobSystem = default!; + [Dependency] private readonly AlertsSystem _alerts = default!; + + private const string Alert = "PacifiedZone"; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent(OnComponentShutdown); + } + + private void OnComponentInit(EntityUid uid, PacifiedZoneGeneratorComponent component, ComponentInit args) + { + foreach (var humanoidUid in _lookup.GetEntitiesInRange(Transform(uid).Coordinates, component.Radius)) + { + if (HasComp(humanoidUid)) + continue; + + if (!_mindSystem.TryGetMind(humanoidUid, out var mindId, out var _)) + continue; + + _jobSystem.MindTryGetJobId(mindId, out var jobId); + + if (jobId != null && component.ImmuneRoles.Contains(jobId.Value)) + continue; + + var pacifiedComponent = AddComp(humanoidUid); + EnableAlert(humanoidUid, pacifiedComponent); + AddComp(humanoidUid); + component.TrackedEntities.Add(humanoidUid); + } + + component.NextUpdate = _gameTiming.CurTime + component.UpdateInterval; + } + + private void OnComponentShutdown(EntityUid uid, PacifiedZoneGeneratorComponent component, ComponentShutdown args) + { + foreach (var entity in component.TrackedEntities) + { + RemComp(entity); + RemComp(entity); + DisableAlert(entity); + } + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var genQuery = AllEntityQuery(); + while (genQuery.MoveNext(out var genUid, out var component)) + { + List newEntities = new List(); + // Not yet update time, skip this + if (_gameTiming.CurTime < component.NextUpdate) + continue; + + var query = _lookup.GetEntitiesInRange(Transform(genUid).Coordinates, component.Radius); + foreach (var humanoidUid in query) + { + if (!_mindSystem.TryGetMind(humanoidUid, out var mindId, out var mind)) + continue; + + _jobSystem.MindTryGetJobId(mindId, out var jobId); + + // Player matches an immune role, should not be pacified. + if (jobId != null && component.ImmuneRoles.Contains(jobId.Value)) + continue; + + if (component.TrackedEntities.Contains(humanoidUid)) + { + // Entity still in zone. + newEntities.Add(humanoidUid); + component.TrackedEntities.Remove(humanoidUid); + } + else + { + // Player is pacified (either naturally or by another zone), skip them. + if (HasComp(humanoidUid)) + continue; + + // New entity in zone, needs the Pacified comp. + var pacifiedComponent = AddComp(humanoidUid); + EnableAlert(humanoidUid, pacifiedComponent); + AddComp(humanoidUid); + newEntities.Add(humanoidUid); + } + } + + // Anything left in our old set has left the zone, remove their pacified status. + foreach (var humanoid_net_uid in component.TrackedEntities) + { + RemComp(humanoid_net_uid); + RemComp(humanoid_net_uid); + DisableAlert(humanoid_net_uid); + } + + // Update state for next run. + component.TrackedEntities = newEntities; + component.NextUpdate = _gameTiming.CurTime + component.UpdateInterval; + } + } + + // Overrides the default Pacified alert with one for the pacified zone. + private void EnableAlert(EntityUid entity, PacifiedComponent pacified) + { + _alerts.ClearAlert(entity, pacified.PacifiedAlert); + _alerts.ShowAlert(entity, Alert); + } + + // Hides our pacified zone alert. + private void DisableAlert(EntityUid entity) + { + _alerts.ClearAlert(entity, Alert); + } + } +} \ No newline at end of file diff --git a/Resources/Locale/en-US/_NF/alerts/alerts.ftl b/Resources/Locale/en-US/_NF/alerts/alerts.ftl new file mode 100644 index 00000000000..61fa886596b --- /dev/null +++ b/Resources/Locale/en-US/_NF/alerts/alerts.ftl @@ -0,0 +1,2 @@ +alerts-pacified-zone-name = [color=royalblue]Pacified Zone[/color] +alerts-pacified-zone-desc = You're in a pacified zone, you need to leave before harming living things. diff --git a/Resources/Locale/en-US/_NF/pacified/pacified.ftl b/Resources/Locale/en-US/_NF/pacified/pacified.ftl new file mode 100644 index 00000000000..7ca98d11afc --- /dev/null +++ b/Resources/Locale/en-US/_NF/pacified/pacified.ftl @@ -0,0 +1,4 @@ + +## Messages shown to Pacified players when they try to do violence: + +pacified-cannot-throw-hairball = I can't possibly throw { THE($projectile) }, what if somebody vomits? \ No newline at end of file diff --git a/Resources/Maps/_NF/Outpost/frontier.yml b/Resources/Maps/_NF/Outpost/frontier.yml index e3491ea2ade..a25ffeb1b80 100644 --- a/Resources/Maps/_NF/Outpost/frontier.yml +++ b/Resources/Maps/_NF/Outpost/frontier.yml @@ -1762,8 +1762,8 @@ entities: 2400: 7,25 2401: 0,21 2402: 0,21 - 2457: -37,12 - 2458: -38,12 + 2451: -37,12 + 2452: -38,12 - node: cleanable: True zIndex: 180 @@ -2253,7 +2253,7 @@ entities: 2351: 40,11 2352: 40,10 2353: 37,11 - 2456: -35,12 + 2450: -35,12 - node: cleanable: True zIndex: 180 @@ -2505,10 +2505,10 @@ entities: 2218: 31,18 2219: 32,17 2272: 42,16 - 2459: -33,12 - 2460: -34,12 - 2461: -32,12 - 2462: -31,12 + 2453: -33,12 + 2454: -34,12 + 2455: -32,12 + 2456: -31,12 - node: color: '#334E6DC8' id: FullTileOverlayGreyscale @@ -2975,45 +2975,45 @@ entities: color: '#FFFFFFFF' id: WarnCornerNE decals: - 2448: -39,16 + 2442: -39,16 - node: color: '#FFFFFFFF' id: WarnCornerNW decals: - 2450: -41,16 + 2444: -41,16 - node: color: '#FFFFFFFF' id: WarnCornerSE decals: - 2452: -39,14 + 2446: -39,14 - node: color: '#FFFFFFFF' id: WarnCornerSW decals: - 2454: -41,14 + 2448: -41,14 - node: color: '#EFB34196' id: WarnFull decals: - 2447: -32,6 + 2441: -32,6 - node: color: '#52B4E996' id: WarnFullGreyscale decals: - 2469: -36,6 - 2470: -35,6 + 2459: -36,6 + 2460: -35,6 - node: color: '#D4D4D496' id: WarnFullGreyscale decals: - 2471: -34,6 - 2472: -33,6 + 2461: -34,6 + 2462: -33,6 - node: color: '#DE3A3A96' id: WarnFullGreyscale decals: - 2467: -38,6 - 2468: -37,6 + 2457: -38,6 + 2458: -37,6 - node: color: '#FFFFFFFF' id: WarnLineE @@ -3076,7 +3076,7 @@ entities: 2359: 35,22 2360: 35,23 2403: -57,2 - 2453: -39,15 + 2447: -39,15 - node: color: '#FFFFFFFF' id: WarnLineN @@ -3129,7 +3129,7 @@ entities: 2238: 37,19 2239: 36,21 2240: 37,21 - 2455: -40,14 + 2449: -40,14 - node: cleanable: True color: '#FFFFFFFF' @@ -3198,7 +3198,7 @@ entities: 2357: 35,22 2358: 35,23 2404: -57,2 - 2451: -41,15 + 2445: -41,15 - node: color: '#FFFFFFFF' id: WarnLineW @@ -3253,7 +3253,7 @@ entities: 2242: 37,19 2243: 37,21 2244: 36,21 - 2449: -40,16 + 2443: -40,16 - node: cleanable: True color: '#FFFFFFFF' @@ -5054,9 +5054,6 @@ entities: parent: 2173 - type: DeviceLinkSink invokeCounter: 2 - links: - - 3745 - - 3746 - type: DeviceLinkSource linkedPorts: 3746: @@ -5071,9 +5068,6 @@ entities: parent: 2173 - type: DeviceLinkSink invokeCounter: 2 - links: - - 3745 - - 3746 - type: DeviceLinkSource linkedPorts: 3746: @@ -5088,9 +5082,6 @@ entities: parent: 2173 - type: DeviceLinkSink invokeCounter: 2 - links: - - 2982 - - 2976 - type: DeviceLinkSource linkedPorts: 2976: @@ -5105,9 +5096,6 @@ entities: parent: 2173 - type: DeviceLinkSink invokeCounter: 2 - links: - - 2976 - - 2982 - type: DeviceLinkSource linkedPorts: 2976: @@ -14674,9 +14662,6 @@ entities: rot: 1.5707963267948966 rad pos: 52.5,18.5 parent: 2173 - - type: DeviceLinkSink - links: - - 6145 - proto: CrateTrashCart entities: - uid: 1990 @@ -28057,6 +28042,13 @@ entities: - type: Transform pos: -35.5,6.5 parent: 2173 +- proto: PacifiedZone100 + entities: + - uid: 2054 + components: + - type: Transform + pos: -0.5,12.5 + parent: 2173 - proto: Paper entities: - uid: 2038 @@ -36898,9 +36890,6 @@ entities: rot: 3.141592653589793 rad pos: 4.5,24.5 parent: 2173 - - type: DeviceLinkSink - links: - - 2642 - type: DeviceLinkSource linkedPorts: 2642: @@ -36918,9 +36907,6 @@ entities: - type: Transform pos: 4.5,24.5 parent: 2173 - - type: DeviceLinkSink - links: - - 2643 - type: DeviceLinkSource linkedPorts: 2643: diff --git a/Resources/Maps/_NF/Shuttles/Bus/publicts.yml b/Resources/Maps/_NF/Shuttles/Bus/publicts.yml index e54f4a80488..f43aa385124 100644 --- a/Resources/Maps/_NF/Shuttles/Bus/publicts.yml +++ b/Resources/Maps/_NF/Shuttles/Bus/publicts.yml @@ -194,6 +194,13 @@ entities: rot: -1.5707963267948966 rad pos: -3.5,0.5 parent: 8756 +- proto: AntiAnomalyZone + entities: + - uid: 85 + components: + - type: Transform + pos: -0.5,-0.5 + parent: 8756 - proto: APCBasic entities: - uid: 8819 @@ -671,6 +678,13 @@ entities: parent: 8756 - type: Physics bodyType: Static +- proto: PacifiedZone10 + entities: + - uid: 84 + components: + - type: Transform + pos: -0.5,-2.5 + parent: 8756 - proto: PottedPlantRandom entities: - uid: 49 diff --git a/Resources/Prototypes/_NF/Alerts/pacified_zone.yml b/Resources/Prototypes/_NF/Alerts/pacified_zone.yml new file mode 100644 index 00000000000..8fc8a36ef90 --- /dev/null +++ b/Resources/Prototypes/_NF/Alerts/pacified_zone.yml @@ -0,0 +1,7 @@ +- type: alert + id: PacifiedZone + icons: + - sprite: _NF/Markers/pacifiedzone.rsi + state: pacified_zone + name: alerts-pacified-zone-name + description: alerts-pacified-zone-desc diff --git a/Resources/Prototypes/_NF/Entities/Markers/pacified_zone.yml b/Resources/Prototypes/_NF/Entities/Markers/pacified_zone.yml new file mode 100644 index 00000000000..6b780f6caaf --- /dev/null +++ b/Resources/Prototypes/_NF/Entities/Markers/pacified_zone.yml @@ -0,0 +1,58 @@ +- type: entity + parent: MarkerBase + id: BasePacifiedZone + name: pacified zone + abstract: true + components: + - type: Sprite + sprite: _NF/Markers/pacifiedzone.rsi + layers: + - sprite: Markers/cross.rsi + state: pink + - state: pacified_zone + - type: PacifiedZoneGenerator + radius: 10 + immuneRoles: + - Bailiff + - Brigmedic + - Cadet + - Deputy + - DetectiveNF + - SeniorOfficer + - Sheriff + - SecurityGuard + - StationRepresentative + - StationTrafficController + +- type: entity + parent: BasePacifiedZone + id: PacifiedZone10 + description: Players will not be able to attack living things within a 10 block radius of this point. + suffix: 10 + +- type: entity + parent: BasePacifiedZone + id: PacifiedZone20 + description: Players will not be able to attack living things within a 20 block radius of this point. + suffix: 20 + components: + - type: PacifiedZoneGenerator + radius: 20 + +- type: entity + parent: BasePacifiedZone + id: PacifiedZone50 + description: Players will not be able to attack living things within a 50 block radius of this point. + suffix: 50 + components: + - type: PacifiedZoneGenerator + radius: 50 + +- type: entity + parent: BasePacifiedZone + id: PacifiedZone100 + description: Players will not be able to attack living things within a 100 block radius of this point. + suffix: 100 + components: + - type: PacifiedZoneGenerator + radius: 100 diff --git a/Resources/Textures/_NF/Markers/pacifiedzone.rsi/meta.json b/Resources/Textures/_NF/Markers/pacifiedzone.rsi/meta.json new file mode 100644 index 00000000000..d962ddc16be --- /dev/null +++ b/Resources/Textures/_NF/Markers/pacifiedzone.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by BeatusCrow(github/discord)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "pacified_zone" + } + ] +} diff --git a/Resources/Textures/_NF/Markers/pacifiedzone.rsi/pacified_zone.png b/Resources/Textures/_NF/Markers/pacifiedzone.rsi/pacified_zone.png new file mode 100644 index 00000000000..afbff623fb9 Binary files /dev/null and b/Resources/Textures/_NF/Markers/pacifiedzone.rsi/pacified_zone.png differ