From b02c211e2f22a10901fa57a5c76a625be8be4a3d Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Tue, 23 Jan 2024 15:32:05 +0300 Subject: [PATCH] Start rebalancing anomalies - Rock and Flesh anomaly reworked (#24381) * rework * bruh * all fixed * balance * bb * Update TileAnomalySystem.cs * Update EntityAnomalySystem.cs --- .../Anomaly/Effects/EntityAnomalySystem.cs | 86 +++-- .../Anomaly/Effects/TileAnomalySystem.cs | 91 ++++- .../Anomaly/Components/AnomalyComponent.cs | 4 +- .../Components/EntitySpawnAnomalyComponent.cs | 53 ++- .../Effects/Components/TileSpawnAnomaly.cs | 26 -- .../Components/TileSpawnAnomalyComponent.cs | 73 ++++ .../Effects/SharedEntityAnomalySystem.cs | 6 + .../Effects/SharedTileAnomalySystem.cs | 6 + Content.Shared/Anomaly/SharedAnomalySystem.cs | 4 +- .../Prototypes/Entities/Effects/wallspawn.yml | 50 ++- .../Markers/Spawners/Random/anomaly.yml | 20 +- .../Markers/Spawners/Random/asteroidcrab.yml | 31 -- .../Entities/Objects/Misc/ice_crust.yml | 3 +- .../Structures/Specific/Anomaly/anomalies.yml | 324 +++++++++++++++--- .../Entities/Structures/Walls/asteroid.yml | 88 ++--- .../Specific/anomaly.rsi/anom6-pulse.png | Bin 23507 -> 3741 bytes .../Structures/Specific/anomaly.rsi/anom6.png | Bin 18861 -> 3078 bytes 17 files changed, 660 insertions(+), 205 deletions(-) delete mode 100644 Content.Shared/Anomaly/Effects/Components/TileSpawnAnomaly.cs create mode 100644 Content.Shared/Anomaly/Effects/Components/TileSpawnAnomalyComponent.cs create mode 100644 Content.Shared/Anomaly/Effects/SharedEntityAnomalySystem.cs create mode 100644 Content.Shared/Anomaly/Effects/SharedTileAnomalySystem.cs delete mode 100644 Resources/Prototypes/Entities/Markers/Spawners/Random/asteroidcrab.yml diff --git a/Content.Server/Anomaly/Effects/EntityAnomalySystem.cs b/Content.Server/Anomaly/Effects/EntityAnomalySystem.cs index ee4e2ac115..30b159b615 100644 --- a/Content.Server/Anomaly/Effects/EntityAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/EntityAnomalySystem.cs @@ -1,17 +1,18 @@ using System.Linq; using System.Numerics; using Content.Shared.Anomaly.Components; +using Content.Shared.Anomaly.Effects; using Content.Shared.Anomaly.Effects.Components; using Content.Shared.Physics; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; -using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Server.Anomaly.Effects; -public sealed class EntityAnomalySystem : EntitySystem +public sealed class EntityAnomalySystem : SharedEntityAnomalySystem { [Dependency] private readonly IMapManager _map = default!; [Dependency] private readonly IRobustRandom _random = default!; @@ -22,55 +23,70 @@ public sealed class EntityAnomalySystem : EntitySystem SubscribeLocalEvent(OnPulse); SubscribeLocalEvent(OnSupercritical); SubscribeLocalEvent(OnStabilityChanged); + SubscribeLocalEvent(OnSeverityChanged); } - private void OnPulse(EntityUid uid, EntitySpawnAnomalyComponent component, ref AnomalyPulseEvent args) + private void OnPulse(Entity component, ref AnomalyPulseEvent args) { - if (!component.SpawnOnPulse) - return; + foreach (var entry in component.Comp.Entries) + { + if (!entry.SpawnOnPulse) + continue; - var range = component.SpawnRange * args.Stability; - var amount = (int) (component.MaxSpawnAmount * args.Severity + 0.5f); - - var xform = Transform(uid); - SpawnEntitesOnOpenTiles(component, xform, amount, range, component.Spawns); + SpawnEntitesOnOpenTiles(component, entry, args.Stability, args.Severity); + } } - private void OnSupercritical(EntityUid uid, EntitySpawnAnomalyComponent component, ref AnomalySupercriticalEvent args) + private void OnSupercritical(Entity component, ref AnomalySupercriticalEvent args) { - if (!component.SpawnOnSuperCritical) - return; + foreach (var entry in component.Comp.Entries) + { + if (!entry.SpawnOnSuperCritical) + continue; - var xform = Transform(uid); - // A cluster of entities - SpawnEntitesOnOpenTiles(component, xform, component.MaxSpawnAmount, component.SpawnRange, component.Spawns); - // And so much meat (for the meat anomaly at least) - SpawnEntitesOnOpenTiles(component, xform, component.MaxSpawnAmount, component.SpawnRange, component.SuperCriticalSpawns); + SpawnEntitesOnOpenTiles(component, entry, 1, 1); + } } - private void OnStabilityChanged(EntityUid uid, EntitySpawnAnomalyComponent component, ref AnomalyStabilityChangedEvent args) + private void OnStabilityChanged(Entity component, ref AnomalyStabilityChangedEvent args) { - if (!component.SpawnOnStabilityChanged) - return; + foreach (var entry in component.Comp.Entries) + { + if (!entry.SpawnOnStabilityChanged) + continue; - var range = component.SpawnRange * args.Stability; - var amount = (int) (component.MaxSpawnAmount * args.Stability + 0.5f); - - var xform = Transform(uid); - SpawnEntitesOnOpenTiles(component, xform, amount, range, component.Spawns); + SpawnEntitesOnOpenTiles(component, entry, args.Stability, args.Severity); + } } - private void SpawnEntitesOnOpenTiles(EntitySpawnAnomalyComponent component, TransformComponent xform, int amount, float radius, List spawns) + private void OnSeverityChanged(Entity component, ref AnomalySeverityChangedEvent args) { - if (!component.Spawns.Any()) + foreach (var entry in component.Comp.Entries) + { + if (!entry.SpawnOnSeverityChanged) + continue; + + SpawnEntitesOnOpenTiles(component, entry, args.Stability, args.Severity); + } + } + + //TheShuEd: + //I know it's a shitcode! I didn't write it! I just restructured the functions + // To Do: make it reusable with TileAnomalySystem + private void SpawnEntitesOnOpenTiles(Entity component, EntitySpawnSettingsEntry entry, float stability, float severity) + { + if (entry.Spawns.Count == 0) return; - if (!_map.TryGetGrid(xform.GridUid, out var grid)) + var xform = Transform(component.Owner); + if (!TryComp(xform.GridUid, out var grid)) return; + var amount = (int) (MathHelper.Lerp(entry.MinAmount, entry.MaxAmount, severity * stability) + 0.5f); + var localpos = xform.Coordinates.Position; var tilerefs = grid.GetLocalTilesIntersecting( - new Box2(localpos + new Vector2(-radius, -radius), localpos + new Vector2(radius, radius))).ToArray(); + new Box2(localpos + new Vector2(-entry.MaxRange, -entry.MaxRange), localpos + new Vector2(entry.MaxRange, entry.MaxRange))).ToArray(); if (tilerefs.Length == 0) return; @@ -80,6 +96,14 @@ public sealed class EntityAnomalySystem : EntitySystem var amountCounter = 0; foreach (var tileref in tilerefs) { + //cut outer circle + if (MathF.Sqrt(MathF.Pow(tileref.X - xform.LocalPosition.X, 2) + MathF.Pow(tileref.Y - xform.LocalPosition.Y, 2)) > entry.MaxRange) + continue; + + //cut inner circle + if (MathF.Sqrt(MathF.Pow(tileref.X - xform.LocalPosition.X, 2) + MathF.Pow(tileref.Y - xform.LocalPosition.Y, 2)) < entry.MinRange) + continue; + var valid = true; foreach (var ent in grid.GetAnchoredEntities(tileref.GridIndices)) { @@ -97,7 +121,7 @@ public sealed class EntityAnomalySystem : EntitySystem if (!valid) continue; amountCounter++; - Spawn(_random.Pick(spawns), tileref.GridIndices.ToEntityCoordinates(xform.GridUid.Value, _map)); + Spawn(_random.Pick(entry.Spawns), tileref.GridIndices.ToEntityCoordinates(xform.GridUid.Value, _map)); if (amountCounter >= amount) return; } diff --git a/Content.Server/Anomaly/Effects/TileAnomalySystem.cs b/Content.Server/Anomaly/Effects/TileAnomalySystem.cs index 08ec3a1c93..1cc81aecc0 100644 --- a/Content.Server/Anomaly/Effects/TileAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/TileAnomalySystem.cs @@ -1,13 +1,16 @@ +using System.Linq; using System.Numerics; using Content.Shared.Anomaly.Components; +using Content.Shared.Anomaly.Effects; using Content.Shared.Anomaly.Effects.Components; using Content.Shared.Maps; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Random; namespace Content.Server.Anomaly.Effects; -public sealed class TileAnomalySystem : EntitySystem +public sealed class TileAnomalySystem : SharedTileAnomalySystem { [Dependency] private readonly IMapManager _map = default!; [Dependency] private readonly IRobustRandom _random = default!; @@ -17,25 +20,93 @@ public sealed class TileAnomalySystem : EntitySystem /// public override void Initialize() { - SubscribeLocalEvent(OnSeverityChanged); + + SubscribeLocalEvent(OnPulse); + SubscribeLocalEvent(OnSupercritical); + SubscribeLocalEvent(OnStabilityChanged); + SubscribeLocalEvent(OnSeverityChanged); } - private void OnSeverityChanged(EntityUid uid, TileSpawnAnomalyComponent component, ref AnomalyStabilityChangedEvent args) + private void OnPulse(Entity component, ref AnomalyPulseEvent args) { - var xform = Transform(uid); - if (!_map.TryGetGrid(xform.GridUid, out var grid)) + foreach (var entry in component.Comp.Entries) + { + if (!entry.SpawnOnPulse) + continue; + + SpawnTiles(component, entry, args.Stability, args.Severity); + } + } + private void OnSupercritical(Entity component, ref AnomalySupercriticalEvent args) + { + foreach (var entry in component.Comp.Entries) + { + if (!entry.SpawnOnSuperCritical) + continue; + + SpawnTiles(component, entry, 1, 1); + } + } + + private void OnStabilityChanged(Entity component, ref AnomalyStabilityChangedEvent args) + { + foreach (var entry in component.Comp.Entries) + { + if (!entry.SpawnOnStabilityChanged) + continue; + + SpawnTiles(component, entry, args.Stability, args.Severity); + } + } + + private void OnSeverityChanged(Entity component, ref AnomalySeverityChangedEvent args) + { + foreach (var entry in component.Comp.Entries) + { + if (!entry.SpawnOnSeverityChanged) + continue; + + SpawnTiles(component, entry, args.Stability, args.Severity); + } + } + + //TheShuEd: + //I know it's a shitcode! I didn't write it! I just restructured the functions + // To Do: make it reusable with EntityAnomalySustem + private void SpawnTiles(Entity component, TileSpawnSettingsEntry entry, float stability, float severity) + { + var xform = Transform(component.Owner); + if (!TryComp(xform.GridUid, out var grid)) return; - var radius = component.SpawnRange * args.Stability; - var fleshTile = (ContentTileDefinition) _tiledef[component.FloorTileId]; + var amount = (int) (MathHelper.Lerp(entry.MinAmount, entry.MaxAmount, stability * severity) + 0.5f); + var localpos = xform.Coordinates.Position; var tilerefs = grid.GetLocalTilesIntersecting( - new Box2(localpos + new Vector2(-radius, -radius), localpos + new Vector2(radius, radius))); + new Box2(localpos + new Vector2(-entry.MaxRange, -entry.MaxRange), localpos + new Vector2(entry.MaxRange, entry.MaxRange))).ToArray(); + + if (tilerefs.Length == 0) + return; + + _random.Shuffle(tilerefs); + var amountCounter = 0; + foreach (var tileref in tilerefs) { - if (!_random.Prob(component.SpawnChance)) + //cut outer circle + if (MathF.Sqrt(MathF.Pow(tileref.X - xform.LocalPosition.X, 2) + MathF.Pow(tileref.Y - xform.LocalPosition.Y, 2)) > entry.MaxRange) continue; - _tile.ReplaceTile(tileref, fleshTile); + + //cut inner circle + if (MathF.Sqrt(MathF.Pow(tileref.X - xform.LocalPosition.X, 2) + MathF.Pow(tileref.Y - xform.LocalPosition.Y, 2)) < entry.MinRange) + continue; + + amountCounter++; + var tile = (ContentTileDefinition) _tiledef[entry.Floor]; + _tile.ReplaceTile(tileref, tile); + + if (amountCounter >= amount) + return; } } } diff --git a/Content.Shared/Anomaly/Components/AnomalyComponent.cs b/Content.Shared/Anomaly/Components/AnomalyComponent.cs index 0e83861863..89afbb0122 100644 --- a/Content.Shared/Anomaly/Components/AnomalyComponent.cs +++ b/Content.Shared/Anomaly/Components/AnomalyComponent.cs @@ -268,13 +268,13 @@ public readonly record struct AnomalyShutdownEvent(EntityUid Anomaly, bool Super /// /// The anomaly being changed [ByRefEvent] -public readonly record struct AnomalySeverityChangedEvent(EntityUid Anomaly, float Severity); +public readonly record struct AnomalySeverityChangedEvent(EntityUid Anomaly, float Stability, float Severity); /// /// Event broadcast when an anomaly's stability is changed. /// [ByRefEvent] -public readonly record struct AnomalyStabilityChangedEvent(EntityUid Anomaly, float Stability); +public readonly record struct AnomalyStabilityChangedEvent(EntityUid Anomaly, float Stability, float Severity); /// /// Event broadcast when an anomaly's health is changed. diff --git a/Content.Shared/Anomaly/Effects/Components/EntitySpawnAnomalyComponent.cs b/Content.Shared/Anomaly/Effects/Components/EntitySpawnAnomalyComponent.cs index 7a816e4312..6b4ea208c3 100644 --- a/Content.Shared/Anomaly/Effects/Components/EntitySpawnAnomalyComponent.cs +++ b/Content.Shared/Anomaly/Effects/Components/EntitySpawnAnomalyComponent.cs @@ -2,52 +2,71 @@ using Robust.Shared.Prototypes; namespace Content.Shared.Anomaly.Effects.Components; -[RegisterComponent] +[RegisterComponent, Access(typeof(SharedEntityAnomalySystem))] public sealed partial class EntitySpawnAnomalyComponent : Component +{ + /// + /// All types of entity spawns with their settings + /// + [DataField] + public List Entries = new(); +} + +[DataDefinition, Serializable] +public partial record struct EntitySpawnSettingsEntry() { /// /// A list of entities that are random picked to be spawned on each pulse /// [DataField] - public List Spawns = new(); + public List Spawns { get; set; } = new(); /// - /// A list of entities that are random picked to be spawned when supercritical; + /// The minimum number of entities that spawn per pulse /// [DataField] - public List SuperCriticalSpawns = new(); + public int MinAmount { get; set; } = 0; /// /// The maximum number of entities that spawn per pulse /// scales with severity. /// - [DataField("maxSpawnAmount"), ViewVariables(VVAccess.ReadWrite)] - public int MaxSpawnAmount = 7; + [DataField] + public int MaxAmount { get; set; } = 1; + + /// + /// The distance from the anomaly in which the entities will not appear + /// + [DataField] + public float MinRange { get; set; } = 0f; /// /// The maximum radius the entities will spawn in. - /// Also governs the maximum reach of flesh tiles - /// scales with stability /// - [DataField("spawnRange"), ViewVariables(VVAccess.ReadWrite)] - public float SpawnRange = 5f; + [DataField] + public float MaxRange { get; set; } = 1f; /// /// Whether or not anomaly spawns entities on Pulse /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public bool SpawnOnPulse = true; + [DataField] + public bool SpawnOnPulse { get; set; } = false; /// /// Whether or not anomaly spawns entities on SuperCritical /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public bool SpawnOnSuperCritical = true; + [DataField] + public bool SpawnOnSuperCritical { get; set; } = false; /// /// Whether or not anomaly spawns entities on StabilityChanged - /// The idea was to spawn entities either on Pulse/Supercritical OR StabilityChanged /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public bool SpawnOnStabilityChanged = false; + [DataField] + public bool SpawnOnStabilityChanged { get; set; } = false; + + /// + /// Whether or not anomaly spawns entities on SeverityChanged + /// + [DataField] + public bool SpawnOnSeverityChanged { get; set; } = false; } diff --git a/Content.Shared/Anomaly/Effects/Components/TileSpawnAnomaly.cs b/Content.Shared/Anomaly/Effects/Components/TileSpawnAnomaly.cs deleted file mode 100644 index 7e3125ba20..0000000000 --- a/Content.Shared/Anomaly/Effects/Components/TileSpawnAnomaly.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Content.Shared.Maps; -using Robust.Shared.Prototypes; - -namespace Content.Shared.Anomaly.Effects.Components; - -[RegisterComponent] -public sealed partial class TileSpawnAnomalyComponent : Component -{ - /// - /// The maximum radius of tiles scales with stability - /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public float SpawnRange = 5f; - - /// - /// The probability a tile will spawn. - /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public float SpawnChance = 0.33f; - - /// - /// The tile that is spawned by the anomaly's effect - /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public ProtoId FloorTileId = "FloorFlesh"; -} diff --git a/Content.Shared/Anomaly/Effects/Components/TileSpawnAnomalyComponent.cs b/Content.Shared/Anomaly/Effects/Components/TileSpawnAnomalyComponent.cs new file mode 100644 index 0000000000..1e54803948 --- /dev/null +++ b/Content.Shared/Anomaly/Effects/Components/TileSpawnAnomalyComponent.cs @@ -0,0 +1,73 @@ +using Content.Shared.Maps; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Anomaly.Effects.Components; + +[RegisterComponent, Access(typeof(SharedTileAnomalySystem))] +public sealed partial class TileSpawnAnomalyComponent : Component +{ + /// + /// All types of floors spawns with their settings + /// + [DataField] + public List Entries = new(); +} + +[DataDefinition, Serializable] +public partial record struct TileSpawnSettingsEntry() +{ + /// + /// The tile that is spawned by the anomaly's effect + /// + [DataField(required: true)] + public ProtoId Floor { get; set; } = default!; + + /// + /// The minimum number of tiles that spawn per pulse + /// + [DataField] + public int MinAmount { get; set; } = 0; + + /// + /// The maximum number of tiles that spawn per pulse + /// scales with severity. + /// + [DataField] + public int MaxAmount { get; set; } = 1; + + /// + /// The distance from the anomaly in which the tiles will not appear + /// + [DataField] + public float MinRange { get; set; } = 0f; + + /// + /// The maximum radius the tiles will spawn in. + /// + [DataField] + public float MaxRange { get; set; } = 1f; + + /// + /// Whether or not anomaly spawns tiles on Pulse + /// + [DataField] + public bool SpawnOnPulse { get; set; } = false; + + /// + /// Whether or not anomaly spawns tiles on SuperCritical + /// + [DataField] + public bool SpawnOnSuperCritical { get; set; } = false; + + /// + /// Whether or not anomaly spawns tiles on StabilityChanged + /// + [DataField] + public bool SpawnOnStabilityChanged { get; set; } = false; + + /// + /// Whether or not anomaly spawns tiles on StabilityChanged + /// + [DataField] + public bool SpawnOnSeverityChanged { get; set; } = false; +} diff --git a/Content.Shared/Anomaly/Effects/SharedEntityAnomalySystem.cs b/Content.Shared/Anomaly/Effects/SharedEntityAnomalySystem.cs new file mode 100644 index 0000000000..28732f4022 --- /dev/null +++ b/Content.Shared/Anomaly/Effects/SharedEntityAnomalySystem.cs @@ -0,0 +1,6 @@ + +namespace Content.Shared.Anomaly.Effects; + +public abstract class SharedEntityAnomalySystem : EntitySystem +{ +} diff --git a/Content.Shared/Anomaly/Effects/SharedTileAnomalySystem.cs b/Content.Shared/Anomaly/Effects/SharedTileAnomalySystem.cs new file mode 100644 index 0000000000..199c6b6f13 --- /dev/null +++ b/Content.Shared/Anomaly/Effects/SharedTileAnomalySystem.cs @@ -0,0 +1,6 @@ + +namespace Content.Shared.Anomaly.Effects; + +public abstract class SharedTileAnomalySystem : EntitySystem +{ +} diff --git a/Content.Shared/Anomaly/SharedAnomalySystem.cs b/Content.Shared/Anomaly/SharedAnomalySystem.cs index c014ff90e1..7390cbda0a 100644 --- a/Content.Shared/Anomaly/SharedAnomalySystem.cs +++ b/Content.Shared/Anomaly/SharedAnomalySystem.cs @@ -227,7 +227,7 @@ public abstract class SharedAnomalySystem : EntitySystem component.Stability = Math.Clamp(newVal, 0, 1); Dirty(component); - var ev = new AnomalyStabilityChangedEvent(uid, component.Stability); + var ev = new AnomalyStabilityChangedEvent(uid, component.Stability, component.Severity); RaiseLocalEvent(uid, ref ev, true); } @@ -250,7 +250,7 @@ public abstract class SharedAnomalySystem : EntitySystem component.Severity = Math.Clamp(newVal, 0, 1); Dirty(component); - var ev = new AnomalySeverityChangedEvent(uid, component.Severity); + var ev = new AnomalySeverityChangedEvent(uid, component.Stability, component.Severity); RaiseLocalEvent(uid, ref ev, true); } diff --git a/Resources/Prototypes/Entities/Effects/wallspawn.yml b/Resources/Prototypes/Entities/Effects/wallspawn.yml index 2010b8e73e..f1bd236a8a 100644 --- a/Resources/Prototypes/Entities/Effects/wallspawn.yml +++ b/Resources/Prototypes/Entities/Effects/wallspawn.yml @@ -26,15 +26,57 @@ prototype: AsteroidRock - type: entity - id: WallSpawnAsteroidCrab + id: WallSpawnAsteroidUraniumCrab parent: WallSpawnAsteroid components: - type: SpawnOnDespawn - prototype: AsteroidRockCrab + prototype: AsteroidRockUraniumCrab - type: entity - id: WallSpawnAsteroidCrab1 + id: WallSpawnAsteroidUranium parent: WallSpawnAsteroid components: - type: SpawnOnDespawn - prototype: AsteroidRockCrab1 + prototype: AsteroidRockUranium + +- type: entity + id: WallSpawnAsteroidQuartzCrab + parent: WallSpawnAsteroid + components: + - type: SpawnOnDespawn + prototype: AsteroidRockQuartzCrab + +- type: entity + id: WallSpawnAsteroidQuartz + parent: WallSpawnAsteroid + components: + - type: SpawnOnDespawn + prototype: AsteroidRockQuartz + +- type: entity + id: WallSpawnAsteroidSilverCrab + parent: WallSpawnAsteroid + components: + - type: SpawnOnDespawn + prototype: AsteroidRockSilverCrab + +- type: entity + id: WallSpawnAsteroidSilver + parent: WallSpawnAsteroid + components: + - type: SpawnOnDespawn + prototype: AsteroidRockSilver + +- type: entity + id: WallSpawnAsteroidIronCrab + parent: WallSpawnAsteroid + components: + - type: SpawnOnDespawn + prototype: AsteroidRockTinCrab + +- type: entity + id: WallSpawnAsteroidIron + parent: WallSpawnAsteroid + components: + - type: SpawnOnDespawn + prototype: AsteroidRockTin \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml index 6d2149965f..c81c840fb0 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml @@ -16,8 +16,26 @@ - AnomalyFlesh - AnomalyBluespace - AnomalyIce - - AnomalyRock + - RandomRockAnomalySpawner - AnomalyLiquid - AnomalyFlora chance: 1 offset: 0.15 # not to put it higher. The anomaly sychnronizer looks for anomalies within this radius, and if the radius is higher, the anomaly can be attracted from a neighboring tile. + +- type: entity + id: RandomRockAnomalySpawner + parent: MarkerBase + components: + - type: Sprite + layers: + - state: red + - sprite: Structures/Specific/anomaly.rsi + state: anom6 + - type: RandomSpawner + prototypes: + - AnomalyRockIron + - AnomalyRockSilver + - AnomalyRockQuartz + - AnomalyRockUranium + chance: 1 + offset: 0.15 \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/asteroidcrab.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/asteroidcrab.yml deleted file mode 100644 index 4c4b969335..0000000000 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/asteroidcrab.yml +++ /dev/null @@ -1,31 +0,0 @@ -- type: entity - name: Asteroid Crab Spawner - id: AsteroidCrabSpawner - parent: MarkerBase - components: - - type: Sprite - layers: - - state: red - - sprite: Structures/Walls/rock.rsi - state: rock_asteroid_ore - - type: RandomSpawner - prototypes: - - AsteroidRockCrab - - AsteroidRockCrab1 - chance: 1 - -- type: entity - name: Rock Anom Crab Spawner - id: RockAnomCrabSpawner - parent: MarkerBase - components: - - type: Sprite - layers: - - state: red - - sprite: Structures/Walls/rock.rsi - state: rock_asteroid_ore - - type: RandomSpawner - prototypes: - - WallSpawnAsteroidCrab - - WallSpawnAsteroidCrab1 - chance: 1 \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Misc/ice_crust.yml b/Resources/Prototypes/Entities/Objects/Misc/ice_crust.yml index ad1f876675..bc3488aaf4 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/ice_crust.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/ice_crust.yml @@ -10,8 +10,7 @@ - type: MeleeSound soundGroups: Brute: - path: - "/Audio/Weapons/slash.ogg" + collection: GlassBreak - type: Sprite sprite: Objects/Misc/ice_crust.rsi layers: diff --git a/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml b/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml index aecef8c637..2a4a934861 100644 --- a/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml +++ b/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml @@ -147,16 +147,58 @@ color: "#cb5b7e" castShadows: false - type: TileSpawnAnomaly - floorTileId: FloorFlesh + entries: + - spawnOnPulse: true + spawnOnStabilityChanged: true + minAmount: 3 + maxAmount: 7 + maxRange: 4 + floor: FloorFlesh + - spawnOnSuperCritical: true + minAmount: 10 + maxAmount: 30 + maxRange: 10 + floor: FloorFlesh - type: EntitySpawnAnomaly - superCriticalSpawns: - - FleshKudzu - spawns: - - MobFleshJared - - MobFleshGolem - - MobFleshClamp - - MobFleshLover - - FleshBlocker + entries: + - spawnOnPulse: true + minAmount: 1 + maxAmount: 4 + minRange: 1.5 + maxRange: 2.5 + spawns: + - FleshBlocker + - spawnOnPulse: true + maxAmount: 3 + minRange: 3 + maxRange: 4.5 + spawns: + - MobFleshJared + - MobFleshGolem + - MobFleshClamp + - MobFleshLover + - spawnOnSuperCritical: true + minAmount: 10 + maxAmount: 15 + minRange: 5 + maxRange: 15 + spawns: + - FleshBlocker + - spawnOnSuperCritical: true + minAmount: 5 + maxAmount: 10 + maxRange: 8 + spawns: + - MobFleshJared + - MobFleshGolem + - MobFleshClamp + - MobFleshLover + - spawnOnSuperCritical: true + minAmount: 5 + maxAmount: 8 + maxRange: 10 + spawns: + - FleshKudzu - type: entity id: AnomalyBluespace @@ -241,12 +283,13 @@ projectilePrototype: ProjectileIcicle targetNonSentientChance: 0.1 - type: EntitySpawnAnomaly - spawns: - - IceCrust - maxSpawnAmount: 17 - spawnOnPulse: false - spawnOnSuperCritical: false - spawnOnStabilityChanged: true + entries: + - spawnOnStabilityChanged: true + minAmount: 5 + maxAmount: 15 + maxRange: 4 + spawns: + - IceCrust - type: TempAffectingAnomaly tempChangePerSecond: -25 hotspotExposeTemperature: -1000 @@ -256,8 +299,9 @@ spawnRadius: 0 - type: entity - id: AnomalyRock + id: AnomalyRockBase parent: BaseAnomaly + abstract: true suffix: Rock components: - type: Anomaly @@ -276,18 +320,201 @@ color: "#5ca8cb" castShadows: false - type: TileSpawnAnomaly - floorTileId: FloorAsteroidTile - spawnChance: 0.8 + entries: + - spawnOnPulse: true + minAmount: 15 + maxAmount: 20 + maxRange: 7.5 + floor: FloorAsteroidTile + - spawnOnSuperCritical: true + minAmount: 30 + maxAmount: 50 + maxRange: 12 + floor: FloorAsteroidTile + +- type: entity + id: AnomalyRockUranium + parent: AnomalyRockBase + suffix: Rock, Uranium + components: + - type: Sprite + color: "#52ff39" + - type: PointLight + radius: 2.0 + energy: 7.5 + color: "#52ff39" - type: EntitySpawnAnomaly - maxSpawnAmount: 50 - spawnRange: 10 - spawns: - - WallSpawnAsteroid - - RockAnomCrabSpawner - - CrystalSpawner - superCriticalSpawns: - - WallSpawnAsteroid - - SpawnMobOreCrab + entries: + - spawnOnPulse: true + minAmount: 8 + maxAmount: 15 + minRange: 4.5 + maxRange: 7.5 + spawns: + - WallSpawnAsteroid + - WallSpawnAsteroid + - WallSpawnAsteroidUranium + - WallSpawnAsteroidUraniumCrab + - spawnOnPulse: true + maxAmount: 3 + minRange: 2.5 + maxRange: 4.5 + spawns: + - CrystalGreen + - spawnOnSuperCritical: true + minAmount: 30 + maxAmount: 40 + minRange: 5 + maxRange: 15 + spawns: + - CrystalGreen + - WallSpawnAsteroid + - WallSpawnAsteroid + - WallSpawnAsteroidUraniumCrab + - spawnOnSuperCritical: true + minAmount: 6 + maxAmount: 10 + maxRange: 5 + spawns: + - MobSpawnCrabUranium + +- type: entity + id: AnomalyRockQuartz + parent: AnomalyRockBase + suffix: Rock, Quartz + components: + - type: Sprite + color: "#fb4747" + - type: PointLight + radius: 2.0 + energy: 7.5 + color: "#fb4747" + - type: EntitySpawnAnomaly + entries: + - spawnOnPulse: true + minAmount: 8 + maxAmount: 15 + minRange: 4.5 + maxRange: 7.5 + spawns: + - WallSpawnAsteroid + - WallSpawnAsteroid + - WallSpawnAsteroidQuartz + - WallSpawnAsteroidQuartzCrab + - spawnOnPulse: true + maxAmount: 3 + minRange: 2.5 + maxRange: 4.5 + spawns: + - CrystalGrey + - spawnOnSuperCritical: true + minAmount: 30 + maxAmount: 40 + minRange: 5 + maxRange: 15 + spawns: + - CrystalGrey + - WallSpawnAsteroid + - WallSpawnAsteroid + - WallSpawnAsteroidQuartzCrab + - spawnOnSuperCritical: true + minAmount: 6 + maxAmount: 10 + maxRange: 5 + spawns: + - MobSpawnCrabQuartz + +- type: entity + id: AnomalyRockSilver + parent: AnomalyRockBase + suffix: Rock, Silver + components: + - type: Sprite + color: "#47f8ff" + - type: PointLight + radius: 2.0 + energy: 7.5 + color: "#47f8ff" + - type: EntitySpawnAnomaly + entries: + - spawnOnPulse: true + minAmount: 8 + maxAmount: 15 + minRange: 4.5 + maxRange: 7.5 + spawns: + - WallSpawnAsteroid + - WallSpawnAsteroid + - WallSpawnAsteroidSilver + - WallSpawnAsteroidSilverCrab + - spawnOnPulse: true + maxAmount: 3 + minRange: 2.5 + maxRange: 4.5 + spawns: + - CrystalCyan + - spawnOnSuperCritical: true + minAmount: 30 + maxAmount: 40 + minRange: 5 + maxRange: 15 + spawns: + - CrystalCyan + - WallSpawnAsteroid + - WallSpawnAsteroid + - WallSpawnAsteroidSilverCrab + - spawnOnSuperCritical: true + minAmount: 6 + maxAmount: 10 + maxRange: 5 + spawns: + - MobSpawnCrabSilver + +- type: entity + id: AnomalyRockIron + parent: AnomalyRockBase + suffix: Rock, Iron + components: + - type: Sprite + color: "#ff8227" + - type: PointLight + radius: 2.0 + energy: 7.5 + color: "#ff8227" + - type: EntitySpawnAnomaly + entries: + - spawnOnPulse: true + minAmount: 8 + maxAmount: 15 + minRange: 4.5 + maxRange: 7.5 + spawns: + - WallSpawnAsteroid + - WallSpawnAsteroid + - WallSpawnAsteroidIron + - WallSpawnAsteroidIronCrab + - spawnOnPulse: true + maxAmount: 3 + minRange: 2.5 + maxRange: 4.5 + spawns: + - CrystalOrange + - spawnOnSuperCritical: true + minAmount: 30 + maxAmount: 40 + minRange: 5 + maxRange: 15 + spawns: + - CrystalOrange + - WallSpawnAsteroid + - WallSpawnAsteroid + - WallSpawnAsteroidIronCrab + - spawnOnSuperCritical: true + minAmount: 6 + maxAmount: 10 + maxRange: 5 + spawns: + - MobSpawnCrabIron - type: entity id: AnomalyFlora @@ -316,15 +543,31 @@ types: Slash: 0 - type: TileSpawnAnomaly - floorTileId: FloorAstroGrass - spawnRange: 6 + entries: + - spawnOnPulse: true + minAmount: 3 + maxAmount: 7 + maxRange: 5 + floor: FloorAstroGrass + - spawnOnSuperCritical: true + minAmount: 10 + maxAmount: 30 + maxRange: 15 + floor: FloorAstroGrass - type: EntitySpawnAnomaly - maxSpawnAmount: 15 - spawnRange: 6 - superCriticalSpawns: - - KudzuFlowerAngry - spawns: - - KudzuFlowerFriendly + entries: + - spawnOnPulse: true + minAmount: 2 + maxAmount: 5 + maxRange: 2 + spawns: + - KudzuFlowerFriendly + - spawnOnSuperCritical: true + minAmount: 5 + maxAmount: 10 + maxRange: 6 + spawns: + - KudzuFlowerAngry - type: entity id: AnomalyFloraBulb @@ -400,10 +643,13 @@ types: Slash: 1 - type: EntitySpawnAnomaly - superCriticalSpawns: - - ReagentSlimeSpawner - spawns: - - PuddleSparkle + entries: + - spawnOnSuperCritical: true + minAmount: 3 + maxAmount: 8 + maxRange: 2 + spawns: + - ReagentSlimeSpawner - type: SolutionContainerManager solutions: anomaly: diff --git a/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml b/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml index d5c542a0a1..aa5f1421c7 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml @@ -148,6 +148,28 @@ state: rock_asteroid_west - state: rock_quartz +- type: entity + id: AsteroidRockQuartzCrab + parent: AsteroidRock + description: An ore vein rich with quartz. + suffix: Quartz Crab + components: + - type: OreVein + oreChance: 1.0 + currentOre: OreQuartzCrab + - type: Sprite + layers: + - state: rock_asteroid + - map: [ "enum.EdgeLayer.South" ] + state: rock_asteroid_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_asteroid_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_asteroid_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_asteroid_west + - state: rock_quartz + - type: entity id: AsteroidRockSilver parent: AsteroidRock @@ -169,6 +191,15 @@ - map: [ "enum.EdgeLayer.West" ] state: rock_asteroid_west - state: rock_silver + +- type: entity + id: AsteroidRockSilverCrab + parent: AsteroidRockSilver + suffix: Silver Crab + components: + - type: OreVein + oreChance: 1.0 + currentOre: OreSilverCrab # Yes I know it drops steel but we may get smelting at some point - type: entity @@ -192,6 +223,15 @@ - map: [ "enum.EdgeLayer.West" ] state: rock_asteroid_west - state: rock_tin + +- type: entity + id: AsteroidRockTinCrab + parent: AsteroidRockTin + suffix: Iron + components: + - type: OreVein + oreChance: 1.0 + currentOre: OreIronCrab - type: entity id: AsteroidRockUranium @@ -215,6 +255,14 @@ state: rock_asteroid_west - state: rock_uranium +- type: entity + id: AsteroidRockUraniumCrab + parent: AsteroidRockUranium + suffix: Uranium Crab + components: + - type: OreVein + oreChance: 1.0 + currentOre: OreUraniumCrab - type: entity id: AsteroidRockBananium @@ -271,46 +319,6 @@ oreChance: 0.33 oreRarityPrototypeId: RandomOreDistributionStandard -- type: entity - id: AsteroidRockCrab - parent: AsteroidRock - name: asteroid rock - suffix: orecrab - description: An asteroid. - components: - - type: Sprite - sprite: Structures/Walls/rock.rsi - layers: - - state: rock_asteroid_ore - - map: [ "enum.EdgeLayer.South" ] - state: rock_asteroid_south - - map: [ "enum.EdgeLayer.East" ] - state: rock_asteroid_east - - map: [ "enum.EdgeLayer.North" ] - state: rock_asteroid_north - - map: [ "enum.EdgeLayer.West" ] - state: rock_asteroid_west - - type: OreVein - oreChance: 0.33 - oreRarityPrototypeId: OreCrab - -- type: entity - id: AsteroidRockCrab1 - parent: AsteroidRockCrab - components: - - type: Sprite - sprite: Structures/Walls/rock.rsi - layers: - - state: rock_asteroid_ore1 - - map: [ "enum.EdgeLayer.South" ] - state: rock_asteroid_south - - map: [ "enum.EdgeLayer.East" ] - state: rock_asteroid_east - - map: [ "enum.EdgeLayer.North" ] - state: rock_asteroid_north - - map: [ "enum.EdgeLayer.West" ] - state: rock_asteroid_west - - type: entity id: IronRock parent: AsteroidRock diff --git a/Resources/Textures/Structures/Specific/anomaly.rsi/anom6-pulse.png b/Resources/Textures/Structures/Specific/anomaly.rsi/anom6-pulse.png index f92a77a95ed07e8d75d6211cbf7841b4f44ce5e0..cfeabdaa8131470a8d54c12755fe3a83f06bdb93 100644 GIT binary patch literal 3741 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 Hu0mjf`Bn}* literal 23507 zcmeHvcT|&0v~Q>a(orc=LIgz*ffNW3AynzTNf9xmK%@kdP(-TIEudmS1Vj+zAVop3 zQ3M49MVcZi0v4)DFH+x!SkU9S_vD^;-(B~uWUY{onO$an`!{>`%pYHzrMUqQmlzia z1mZC=)UyVD!-20B2Rrb$D)(S0unLy{xi-16SPf4~8GzT+NG>+`8 zfW?#D2nvDTzJN3cq^=q0i^X{oXka&jJIO}_GJK~30w&=#AUl=KU}nC$1P_v75QSh9 zWNwQK^2Dj(A(|L2^*}UWz?(qBf&;z1e5mL^4agU}XyAFdSrG#MB0}@jfM_o}1Ur~n zf_2Fh0$5oA1;xQoDqs~g1-P<`ijs;v7y*MTE5eY9NEj4>L@UA2N(k`R4+O&nJgHOg zM6|V@{#SRve;N=E8qF82s2C6spb&smAXD5G;c9AXiZFyC0s#dipw#_7G;AQ$hq`IS z$TvHB1S*a~@}-f;KHz1$SU0jCO#=d1cJ%%8bza`S-yQi-zhVcVs2GU#RfH?R6o03L z$9>oF^`m%w85$m^Nbn+f6MSe?Ko9;~JzozpjZF0*|BcJ<-GA#Ch>4lmci+DquebMa zT~ld0`~e8QLi$@xs_lMXf}%BnO7^4R2s`|Nscib)?5Q+s!jI_u15<$bZw=8%#J{n# z-1D~}5CTbmqqf|$qV|PTE1^~gKttyo|56ku2c3{qY3cg?@m(j(*imY0UM4~{?u;y_&$A0SF!7QYVG{pZ$i z9bP2NO6tLraU?wYhf{(7%}jnsbx z#WK0f%+N+YR2mjQ%193bG$@dON#l_?C9InY0t!PCuuxTm5)7)UtfmT8RZ~_*VBrWP z!43X}GC!;TnDkfE-@F5+e?M^~Rz(f2rmPB8c7wYuPn-aCBd8Fecmhlbizg6J%4)=K zj#e4_iz5pP3D|A0UaMr5=Yj|3qJ~#i#S#HnVajeQP-VCh5sF2+;Q*+WP-;Xh5k*)I z+X@uFG4mH!hNNXm?f*H#Unpfm*!Oem4@!O67ksf4Dq%V6X+XZEz3&^z3QN9n5d1~`?|lS#5Pbe77p++NBJlV6R5Fnk zfTa+$-GNp5Pcr0+)t}XVHUIks@_#1=WFLP5g`Ow?vBm<03jxSIL<-p({5|D?X=E_g z*Vl`L!!Czc(ccIEwG8;4X}*Pem5u+0bERVa{~g;@V0d6zV^yG7V0}T6L}03LFcCyQu=@1zZV8`>I$36bXaFRMZd%912JHHosLF=GQ6yK;`EYp=t}18A_^X z#B#a92-?@o{;#vjf09U+bItd}^9}d^nXG~*P)PLTl~tp}eS-=7C6oT|ne)HSq*yng zz63UJs2bc20VOCa0o4&ql?YV-ZbUZ}5{W{peXk1`i*mUT`cj8^k^V)w^{<2W&uZuY z+V=O`liU9X>2#%Z`?-GpR+Im=-u`yDSV<}R%jMPb(FjNx|4DfbY}ml%0D9F@`F7y> zr`z8z>OXCNU#;W69zOr}%=6Cx;Nb^rJ!GApgX?Iv)ss`&k8byd)oGv$BN=f{lx zn;a~gWjLV=Tn1bWxadNFE@1|{7;w>r0A0cib}`_h3jw->8SG-fMHd2e2{YKmfQv2! z=n`hIivbs12+$?WU>5@}x)7jCn87XvTy!BomoS4}47lh*fG%MMyBKiMg#cZ`40bW# zq6-1Kgc785Ye z(Ao?H3X%ohh;j%7`n&}E4uC*@Fc4^P4+w-l3jzs~Pq;qN2Z1&O8tG}<2EO=^dLU`t z)6`nc(%V5IM<8N;Vni4>yJaH2S{D{By|D_pw{h0^`H{<4ZpS_vNtCYA+xJdd&uVwM zAh?dR!v%*r&J+{?;Oq{!}Onj{<#}lm3K`s2*PX%|vZ0(-pzqIRA*3b~rFp-$0 zwYu1KIZsb7EPNVX{Isy3Z@BgIlK&Ae)$~GV&OR4(x+XQ1MCqxs>ksY9t+>8Hl)KUz zGvqMF%;e6D1uLHcsi_1!XCtlywStV zbj|Z_lM*zR6;ZkE-Cnjxz8g*D?Qzn|5hm}0hnSftn{*QSY1G3Bpt@$GHnY1uNa(i*;d(M%4BlkNY7Q-i_okV{TWC%q3yJN=*6_acl9Aj=NAx{ z=6YSSI3dD)rXG4QrF$E%UpkfZbglW+JaVV_){LRogC-GKkieb&MpDZq6QTL~xPQ7TU*PqOibg5StmN2v3H{PGyHc>FEXFOo3 zWj%Xu{vb$P^de6*WQ3YL5@2v<^g+w;m{pgWR6`c42?Tn$Wx98FR^q*}Y873-^46Y? zV}K#m(7Ugx-X=y((KGj|c8+W>so)J?BJy%D2}+7zi=Uo;N;R76Io5MM%CenmpQ+C* z+ATkr-L+|+w^;xL4DqgLs!0f*Nrz*j)CH?+ok4;M#UeqYZ`-6auy3aeX75W!9FQ6B zWx4sHbh1sUKBfTI_4;jEBl%+{&q!;HlkoWCx|8z_M->me8kTGqj*z~r>95m_&1igi z=?Tq@*b)qWvnX2HO6s`qRXd~74T4?fHqMXiXv0qqZ@Y`?ymqs23BmtdjDsd8V%~YZ zSj@O9y{j>2oUkFM^)fVH{iQVepu?3|31Mhf;D>d*g`xZcMEx0pEaKC5dm~>tDe` z_zN+2?ii(QxboWJURlT))zJ8o{0MJ0y=b-DUHtEyKpTq}Y-o%2Y%%TX_jiU(`_x2N zgj9p#8|;fRi3+-CyM4VD?8jt}huYX6O=HqA)3qhTxT}yw-#-VI%4Y9dr;n534~;OL z_K`X>d*wt%^2}{V^Ayj#s$unPaR~ETx#VY>ekZG+lS0(V}n zg>r;m;#R_9sqmwmzz?>(OL&NDNM9-Fksv$ggY2~iC;LneZwwgjQCXO?LM*b~s92Oq zJ({*HSH7<^b-m%Hlb=5}UpnG&MefpMXtwKmok9#eXfjUV@cK*1J-Z%NNR{U;xcKC` zHO@H?P@LBMM_k7p5i7FGhO%YNV$Wzob+o7kbtpe4`zk<5 zx2uq#B;Ik4ifyc?SQP|prQcEdXKs&lW)97#fUISF;}TiQ4fqWTUey)~+2zi0R8QSL zERpZ3A8D0YgV@{Va9T}9F6~8^Va>K58RGvjhoW6=f_Ue!6yPkG&FX*KIuP>bI^{|Zs|ToVoAw%PtJ@N zHS&FMRe>9p9WEWaMa;#u3N@GgaB}Dw3@*@!F5(%qJ$E`p#d z=NCMkN5;u-HnwzEeo$#G*eK~NzCqI$YXCAFpq+X5)ZO1|z7FKil!7AT+hUu+tjiCA zMstvcTkJDp)WCs{oOOp!CS@0jMv9A{w@E#~1!{2Xn&G^AlPC)s?hKJ~us?YddN@#> zw^GuR(>_Plb%f8vr1;iB-?D|Vj3I~F7dMk?a{JC>rVUhit8s@Vcy_&n`1uZ}UehZ) zn%UrOcjMXiY**O~snBWj^}&H&Mj}#Lmj@>+FP!<@oE8_G#c55!k4hS6^K@fRc)cED z*QwNP*|2#0!2vB}e2ek*0}fsaa|!vALKxOU5hv?U3Ws zIs*UR-W=0-i@m|E(pA!W&NY?G2?S|9T?A}dSsSBmCA3a)6p;L*vdlZsB^Ae7N1-5y zNncFW&Z~a4t($_Sg5AAABb|bqgY92K{L1ng{VIaQHRjeyZz>uqJ-HP~R3Zo8kXWpR zyX1I67e6Qz$r$WC4J+ws&c1Orrr*Bwav5^6W#@;i@}_rpO)qqJhYy~t#Z;s>s_gW| zf5iK|x+N5D5ZU86y07nug~?n>=^CDkH@!p++7)~LJ|kFwwldn_KsLu^FVjK6&xzSrmVAl6dC@ zPAQ8LRk_(d&vQ&`O%U&>c6TRhn2l=`-P;qTxnEt~B+8Okbi}o>`5b}!Gk)`& z<6*u5N&;(*+m4Kq3S~awC)Zg+UldA7KdNXly+%l}`VhPO{$h|$1>wrBrJ_NX@mE1F zZTY;k zRdB9v=4lWO?iH}Zo)F`#%4Y)@5NG+gXj`zWw~6y!^t#Xu;>@mFu=YKD(dmO(Ez^Ca zd3XGuedhgG&S`BORw60?Ffz2E^-Yjw(44mGypP}E7Xo*UB0*u5%zEtseL(gY7LuY) z3&>j=cS! zF*<8Cr*(r&ONU~m#RboU)&@p%|IfKN3SJjX|X$%#c%*Dbb=|CUJ^u#t57_P<%mc=x1CT{s}m+4eH0 zy2pnzj`q?|9kulisPIh{E_PMW(5AJTw6@Vg-^eRLbAOI#zZBo*bV9VP%w~rOkI(fU z@XmSuWNnC+9G;`Eo|`xQ(FOu{rOn&v+06onCd5Gv1}|Bnx*$^B!_p(D`)8zesyni2 z_8dpI+}EJ>HC2Uq-o(_*eH1ize;M^k>zpUg!O)Y^z0;4?xTVAoasP2s``GTp5vKdG zRGwX`l+A~{vh`JjO%lvzWOMPws`i@`*TzZT;^VPrUki4U3)ZZ);=g{ea>M&|J}N=dDcgzP|W+7by|(vfJRBOhmr~BcLrR(iLHwz z3bb_}5CZxr?3E~%Oj-Mqps^)=QovN|vB7?a*5L@`yBw*Ou~yAt{)-^h^am%`pSuKG zAF(7Wvnar`M2X_=OUYP}>}fx3zX%m7x0dQIbP5SS92{Lol*)IM(&k}X>pc&pp_j7K z(iI>AuJJ8M)6NNLSblYiqZIh!ag3s!&6u5(_I1$g+4hVZCD&e`Ob?~9DQc+J z71tUniwblv3U~E-JhqNr*O?__pwx*;=nWMS~!v@B_+)HEZ|xMD(E zPbtLjU9yIFXJT|%)Il_PAYFz_*ANqN8 z+wL2eoODx2fkP}u3Je`9w`cP#7Yz`oL)q3MOt?T(?X^qi(uWB}b4D@_W&Lwkz*SiTEQ$7NFFmbi1k(GneAwm<&u*S?#MN&N&Dy&4{t3(Z zI-bU-CmqY0OEKXXZ=chZ&c&F60_#|ok1gH3Ics&F7toZ9(|3l&9gj4~WJjj9U%4D{ zJW_GNO+&w=^2TTt5U{!}zB1Rlbz1$Q--ZnI8=oRcRtk;45Z9 zIdy5G=X>X`?+9Vtbb$quHa}6t?Cj0OrB(Sz=a8zU|FlL@X9yqXhhb2p=+$cSz~=$& zX5FrZfNkZzkGz?|ds{}=oCKYfhS;K0!#YmdfW=5+Hmqoj=*2+N!W(C)N)KZ`3u6&A z3iqaRH8GPa6Z7qQz9FDy@ij&HgPUe{T-SPHkx-jzs&hO(_cd~HcY*7z_@SKzZ$8}_ zCIvMaW(^dpXm%!eL5HWXkgEU+!xH1lpS7c#Z6_F;0hwdN-9Qj}( zLcXIL=!%v-myT?AniQCS#w-uc?aeVUdEr+h$eCDl`QF8AP2H!I^K5*^tJs~1h~yF% zpFg0Q8ZTM$UaO_e2b!RiQOCRA?telZ_z)B5go2Kw1_g7<2%1qQ(NX?IEScORB?TlVy44{y^zE z-8FL2MQYCip5I0;4Ha&5tQ2l3_JQUT@@}BhKmO(k+2Glx4a@Efk!@D^DJNjgBuX?TU}pPj$H2*^H1hsChf@ z{Mi0e*uE{bsC>)uRv`?tcuuSZYo+`qY|f+%f`d30o~oYeVD>QI1q z--nSm8saY}g3rzeYOZO!Q!0HKQ(1U!kVW35OKBJ3GT$EM+Ks#>k->PQJDyCl#us{S z@_yu<3VAak`>~?Y?!nH{XIm_qNo`rSp|^+p3^J|6Hi{iTO$aDg(JU)2UUy)_Z~?f% zU2f#c4p7vZIm|xG2gB+_K@oPHxI9kjB0(d(HN}f67WzoK+fgNnzX)=Z!4YlL#0c&N$qt)NlZV8SCCrc{~r}kaHiwRG=l01&qDvnIA-g}{Z zQy(P2XsYszWZo7xFogZAe$6~>5;&^#8^?e+-8Cey?X2G*R^Fi#T&ilVTe&;(0xC=Y z#%;-jG`k^|SLzfl#k=`!YdC7i!@A)|4o<%m$cmvhSpq&-0C#VULhqj_hWU{h+6!@|MBdZ938|eT%{-*D%ev(pX<#?isWP zJNue;ar~)Zv(c~p@uH_zNcgcVGH2^jq-il{w?S<1Q+EzyUOSaN`sqg7g=0g3F~Gb$+q@dR`J8Qna1{?6@|DN z?KsSHZK(qh7j`U&+H%=8tnxuS+XbN=?A>|$VtQ-Hlk@Cm$ zs)Ot}>_GyQ)Y*Q=n}SQm5}|R@Cx}@FF&>A?$y#_$!kWp9d3ga)I!8wNTGPlt!#p-g za`uGhCb`h`KJ)1Y*3*vipmer-G16L=Z3-V)`ZgW1FNkGXm){>} zeQTe+_dRFteb%}Fki7l5ymVL!fHa0IH;uf5=ydS^Nt%_x7l_gXiP(b8$z+MRP{gU(f()^JM#R+k z6fwgnG4n+S6tTRR6BpU=v(F+si<9uYy1K45IaYvHg`_dOZM)Sy63ve6hvve+8gpGXV1Uzt}Vn z0w5{sTl>IQ_o0dBB}pL2uro2q&dxUGa#+UVg8rfZ>F_u7)%T3W>Ha7W-JO%b6s8L3 z;<~ZYQ`3cfdS(Wb#i1Mhd5HgU;9sA^Focu9;d6MRh;Y%Aae0ZNcJtU=0XLmT=koqj z6aQh@pR_pFB2gMXe*tQ&F_0Rd0_4{|fT9oq5_3Sb1O3rAe|$I)zq|<5iN(49Ea=~} z!e!zmlbiTC&MhR2&Jyyo7Wc%@5}*MANCGNQ04hKO=mH~P4s3uua0VX07X*SZ5Cv8N z7DxhVfDf`kKG+C~Knd6Zc7tkA3mQNZXaOfc2RIEbfXm=If4Bi|g9l&)jDzQ32D}0D z5CmZ%GDLwCAXP{UGJwn>2IL5NK>kn&6a~dWi4YGGLix}ps01p9s-Zfl3Hly71zmuy zLW9sfXcU@)euv(}2uy;hurjO-o4^d%1@?o(;FWM9yc*7f3*qf>6UgRb+f=natP#6>iMMoK- z>`~sR{}cWr;0PjdE%mRJX`^;5_c4L7B_^Oz|G^O@LG5~d?22U&&8MF8}MED z0sJ_Ao*+%oAvh4i2+4$vgepP{;S%8?;T4fcR43XJgNa>atgt3H=1Y2UgM2$qd#E`@b zNxY<%q>JP#$vnwQ$&-=;lG9RnDQzh?DW=pqsT!$MQo~ZS(iCYk=|Jf;=~C&V(pRM? zWw0{ZG9EH)nL?REG8bjWCO)PYmQcT=_ETqMWn?X7 z!)0@1Yh=&Jj?fUAHqD2YN-LwCpxvRpms6H=k>kj1lWUP1lADuXBJV8EkuR2SmA@_j zUV*OQp^&1mQ=voQks?Y_UoluQTk(M6CB^9_)Ft*ySWAkRoLF*S30Bfq3Q=04bV#XB ze`!`(McGR^LwT?AMdfJ~nu@bZvPy-@S(PbOimIb3SG7X*oa!^WEZv2kO0S~#&}YdVy&)LYdbX%I9R8VMQ|8r>Q*nyQ)sn)#Z|n)kKvS`4iutvy=3 zT65Yu+7a4Yv^%sXb>ww?bnNb*ob80Vw7dnY&2?2Gxj$wFzzsZVWMdgZL-s(*W{C_ zm1(MJgXse^88ctA0<$i&-_7;SS>`q7w=BpOo)+sZIxSvW8d!2H4_Mx{qF4o3e{Heq zw)$voW6ig2v7WNgw28CXXEV&8GJ+VTj4QTiTUXolwx@01*;(5O>`vJIW^ZJlVt>?r za;eTz&eDdZV-D&LOouv$5l6aXoZ~^q5hpb#rc=Gs6K4%)wsWKNgo~a_vdb}-7p|tR zeAhPDIX64EwQlF#5qB^5V)uRze;JSE9@QR?J=HxEJ)1peysW&|c%An~d;59s^d9z6 z_F?%n`ONs*_^$Qs@gw<#`c?Zq@z?j~`*#Jv0lopd0v;~YTE<(}5eNc(0(S*I3epK$ z9rR-`CO9a#CirQHSxA0JZzv@+HuPxdn=sd~vakosb(ag5cZW-c$AmY9f6qm@N0dj5 zM4Cjdjl3SE7{!h1jK)TXM>j^#uJBl~d&PK+RZLOLos~K(b5>qmrMN0})tOkySZ3_W zICNY@+|jrX%s^&6b2i>5eqa0y%Z;^%^_=a@u3%4b9605ii3Ep)@`TAmhs0fpQ%O!q zl}XcFH*PieWwLj2ZSq`7e_+btl!erY)YddyT3p&Go(wOA*ORW2o|8V9VUSUjF|yij z_3qU(d_R6;CX~4{vr|A7{Y>=tT>!5Y<>$=x#tS?+YzQJq5k&T3nDI0$(e=sd5FL=EvVpCV4 za^Z%;vCUqan~Nlh_(j88?6=fzMQ!D7?cZjxZSS^E#q8p1C8i~nB_B#zrPsbO`=;uf zh3yI3`^&7$4(!0};O)4x(`o0Ca_REC^08e3yV@)06~z^=cgOC&T4`BXyN9qxxM!rw zzp8Vu=H4B9KU61Gf8VZgt!dq-v~SzKx&7?@LkFA>wA3osmejsK$US(s&a1AyUc0{X z5av+Up{EVu4ZYtozHMq$Y%FQ~c$jy10kG~(0%d4Z_dB<%|ym1DNytC3hBe0004pNklZt~5Jf*xBs$kVfeR!Kl8%mZf0cTBY4i)=0s!#-%p_yX-PYN*4Ru|Eh^l`92m`W|QqWps97l9r_b~1VP__iA z;GzB?pp=4AN}O8+kP>I#_dNh$nkFpEQnW@Apd@=~T+W4J2RQf{*&hNplI=824oYi% z4uCOcH^x9~?I0wWrfJYLjeGYYa%B*=;kIoUf5#C3(6%kK*3M!nOCJKjp^}IIbzP(D zIsm{h3=Sj|fAiJ%y@Sa?RMLHbO90$5iv^2;v2)y@)>`pUN&@&DAKJ?rhQR^&+43%7 z&GQ@uICK<;HpXE5G3&YlxH&^a;@Tnr5mmkmegpEhi-B-(|GEEsi2sD*gNQ+-lEh$A zT`C6f`+@7vP)7n50T5B;FPdsbDR|2MEI>+O_RlH{z%H!o3L=8F_F+se`>*d$aeeU| tNXZzp^EE6MFx2S)XX@p*;tSvc_yuQ6&%fCjC~yD(002ovPDHLkV1lea?_dA` literal 18861 zcmeI32T)U6w}20#fFMN$8{!S1h)75$B!*Bz6%c_SU{5&-p(KGsDP9p!6w4J6r3zw2 zs)~vtpok4rKrC25QE7sL_kxO71>Om$;8FALym#Nc`Dc=uBxmil*IL=%UVH7cGjp~s zUSzMTJVO}(098i^8+Yg%A$cn)K%b)U@VC&{c%g%j2mn+jOWtxo>b_|JpzO+{(H1ZE z6^I2QUx5(eNTVTy!2%9100e;0$LStix<|(p^S-BVt({^c_c#gMwUiL<*4raB;|+{- z$7?K%)jjY?%k9!cTidbPm6@^fJ9kFz&~h`Luub`)VvFvyYi+L35&)iyBkBf>QKx1^E>MUJ95^_qd#vwD zmCQAL+c|~mmS=#>j>lfTLJ1q&1G|bJJ!)-fdARV3^)ki{uk{1midE%a{Q-YRP(Js) zdv@W)>?rJtDEqM=o>km>>wIKp?e6iLn2l|5_MgwH41U(Rt9QkbS?q13+3YqcXs1o; zj$Z5$y{*=}=Utt1XOR7($@r5zwTS?n@T1DDi$@+?!IFRPG*`o0T>hdD0D4LUm+l!V z$w&Hbd|n$e_{O5&K64Hb$#L8r1OO{-W}DD&oU*vC1OPUfQAQ`MwBKHuW?Zf?^U}D+ zODdmNn{Kk6eWk)$!&;dgIWu_myu4^@!_Czvbc|M`?pf;K%iVl8CkWL{Dm>4rnG4lF zGL$kd8J0$kA8S>qG?}6MI986i&0Bw`($tig54x8e#!lKk8&MUj>89rtPjJAvZ=)kT z9dvrkgU67zEVnx!zn~JpMt|O1YLD3yRp@4ZZ^9W`@iF3zO?C%WZnMRh)VL{`X}5z< z&oJL%dZ7JwuCMyzI4bQry8PudMckDDw8^#0)+f!3$0x9Ep47{mkb7;$i6wdRC0pOI zYEOoYofKtTKHhX}h&6&S%gVvq*?ZALhhvDDv+)xjk0*|o-{e*?S1;k1(`keA6aT(4 zjfur<@pdrQub&h*8Kto)9*~WV|Rz|uHRvtorZUqp`TFo znC)MvNZMnJm|q#wlHPK;1=ph8qT91fIh|=4bohhE3q$uCeha6!YP8~86~JVymFJ;U z_b0~=&?ge&mRjc@C~`mUw&mDl{F+o!^~NcVPDk<&?!7z1cdBn6@Aymc`H4^V&RUdo z+w0EF4*Qo$FXi8cOivS{`^D4PLMLk8} z>1|YG^t)F44duNH_ZsZgHbT*}bB^Xb%~A2}^}I=s%UzU)dn?3Q_QRdeYzgbHi=sZe8Gf7RU0YoZ8O z3{F-*`hBfYNpinV$#(Oc>;ohkZXwR=lzZI8&@+fz1`!H z$CE7OtSK($iT>~eVPM7XfcbDR$^NucXUf_Ja`d0P9>iQHynmOhHwmq#q?Lk`8+0{!! zml_uxD>?@{7Pc%s>eF3R%8yw}@;Tz|xpc)TyZrS0IrSy^C0P@*iWem;%FU?fUOw?x zQB_g)+36=*A1X8y6a^NoXK4spaY{)rk#gMc*_@qMD>> zUwcwn*0NCiE@;K`@H_9)(@v#TbRBCr-fh~=>)z71{}z7#ybK?l==SAG+B3J-It!Kk zd(r+)c@eHO*C_6pc6}5J74Mb*;KbP@Avt}FH&dzaslof3sm&DPQ|wcpRkw)cXDiR% zbiFLdSQXPm+n_(l9t1F|CL$Z_SjMp;EI8}sQy`0u(GcUq7e!1slZx~z6&7F%gq z#YN{ww_eKE^{srpD_^&-J-H^nhNl*@IO1jfZAC^KWBcWZ33Fq%#CUDC*eQ(lo>7NM zB81d6(nL)*A8itCo~CgzuB7A0g#;sNj)@=TG4VY9yu~#Wj?b<8-s#?s0ZubXCPoFO z{D2EhpSyauyhwkc(!6eJGOBWgFzi50#oL&yDcL5IjLC_X&asQk_WWt3VRUTDjyXM( zL+0#M4y(|q;Oe33OzUDF(v};|TGZoU$5#!e4O>?t%l{%|BKS?8J zOi5jf2*jF`%P<>v$L|WV&e3&ADB^Z<+c;})=7BMV16TRm&!T4SRjl$qwJUF&4^p|v z`shpgQo{#EiiKRzi*vDh>kU$3ZpQrTu3M*WH0&bod$WJAYf{Ce=evuJYUg)6 z<@u2cDM4Wk%FSBi=5Jo2kViSUt;i_wzH4rmS5iSlnL)UVf7HrLH=-|{k@J70;;Gyk zv;I}%gRT{>-YB1@GmMX$)3vEuTelTxHcU;@+VIe@F|<{Ci{Qq^l*T=$vvaQ$vuinb zI2~5_6K;lGOOBj~<^^ZCY}=>)m_X22@hDVMEErB3kjGi|H-ub*0Vp}|wm)8#(rKKRM;)2Tj-f~`3n z9}+(WuE<{$7}RxL{*HXVqP|+ugW`Mlb?%tc-Q()#zp_`m{@aCt^fw_$RZ~^ZKlWXF zp)a%vYw744-_$otmHc?^j&*s@74QDGR)?#D^0Q9uNwrJ!Nd2^ox$L~_EoxnT=hN`d z_6@(O@557k!WQ<@t9Xw)qVFbfdun&2?@eDHVe)t5>V|_w>)Kg0O@8WvH|I6P&+pg{ zZf{>ux}aux&pB~VVMFU=uXA3h$H}V#JH?%pfrPuR*Gu-5q!tt}_b=`aFFUi2)7PP$ zL9BW5wk+(gDTDR*Gf3u7%6h{EeOLS5HBEUE5j?lQ=4Q#Gkh$IYrLLu`-dc89J)%9? za^GUvK;y$VjT`*RLo$2o8twZOVm8(e#J`JEr;UqCiMzR3b@QtXGb)Mn!Xmi8<8v0R zmR)O*F?HbJz|DfGQ&15f?!S6aQU+#0JAb-@i}3^SGV$DPej-!r)l>Owc4WPzc?K0szG#RLEfYgJJ{|LGY+b3HGD3))3U1ATc8 z;lZFs_#!$h+@D2a>se5hDWPP@K_Dn*AVLEJ_#$$sx!#apGIT9zM(H7jx`_SF^{gZT z5#BC~5i~(Ch#;7lB3WotB7#UV!4QZX>zL*h;^UH8xDDM|$63wvLP$~@15CzIV zGA$Tnhy}rPfgpf7oMj{DC+PSj$tr}Q7mv>tgox%*P;irx`5y5G+Azc*6^q8=kZ24N zV@5|~$XFs7Pgpw2ez+6N+yzQ|Hbcx9<$#35;^|ln8BZi*aq}ThX!Nj`@A|_12-rMM z*gx_z((`*CE-qw8zDUgAvp`21Dl}{p9*<3C5(#KC9D#(yvzaWUDF<(cWDq$dB!@vD zun7bvhsfa!{k-qZe{gLhV6Bm)0OWdj&9en8$o;pBBAekjBoYq7M_^)@NDKx9kxY=t zL9#(Kp1}q|Qv&H*pi$0#2;>^fgGv%3U{oK;SlCc7JV-zjh&UFK1mf684hGLel89!| zfXqlF5RYe=;@FI@WBG}jA3{0sL{K7yjY=>m&4!AO2N?8y>sLhpZ>V?(8Nnh@vL?;- zzAnmd)#h6geA_WHdU+&u*)sn7wu|ARRYG1mU?W`M;oW0Tl8 z4w8t&V~{u|9*Z=?l2}MH5KCg3vIuBsioVY9f9?#7EXrasb5N2}qcBbJ_g zo|uaL5)IZo%1UyZNghgA59mY$QlX*2o8Y|{^FqM@ZyO$THzbnm>NqIMkPTe%Q$wF$ z8IDqXF&v)WQRkMSoE>h3PDRjx4E60q_Cq>BKq>D0K()qx&GF&hq(nT3A>3m>X87>$Q>7opmbUrYx3>OTD zbWw&&Iv3$03as=z*NERRafl*K<=WWjTJrg@$00Meie%~HxKR+3uDi+3s!jwBtR+e$SR?nU^#9my6DRek#(~`W}eiS^GpKym~zF;g-jvO+g3MJq8Bm zd0#j@eRUhp1~m>bxr@mc8S0tqL@qq}hPo%i>aZx*FnMYE;@kv*pfXXnP{p}AvKR*d z$QjX@y_)v69WemHbGJie&xNQ(>i}R{?fIEDnk8+X$4Sr8?Ff3xyLcfi%R+~UwWrO>U4u?g(f8}jo!l*pJp1_ie1^-NSvdvw( z;iyGj!{QwSeyeO=RXZ>a-8&h%cN{fyOx>W}>%GCh+ZCE>S{NB!y`WNkcV$i!dgq?k hwTAK^`Tz@g;4{BQ2UA=1S@P7oqwOM_0_)Y${{=Kb;#B|u