From f450398df70dffdeee802926d36e34336157d42c Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Mon, 6 Feb 2023 00:03:53 -0500 Subject: [PATCH] More anomalies (#13766) --- Content.Client/Anomaly/AnomalySystem.cs | 18 +- .../Anomaly/AnomalySystem.Generator.cs | 27 ++- Content.Server/Anomaly/AnomalySystem.cs | 7 +- .../Effects/ElectricityAnomalySystem.cs | 42 ++++- .../Anomaly/Effects/FleshAnomalySystem.cs | 97 +++++++++++ .../Effects/PyroclasticAnomalySystem.cs | 2 +- Content.Server/Maps/TileSystem.cs | 23 +++ .../Anomaly/Components/AnomalyComponent.cs | 39 +++-- .../Anomaly/Effects/BluespaceAnomalySystem.cs | 73 ++++++++ .../Components/BluespaceAnomalyComponent.cs | 40 +++++ .../Components/ElectricityAnomalyComponent.cs | 31 +++- .../Components/FleshAnomalyComponent.cs | 43 +++++ .../Components/GravityAnomalyComponent.cs | 6 +- .../Components/PyroclasticAnomalyComponent.cs | 4 +- .../Effects/SharedGravityAnomalySystem.cs | 4 +- Content.Shared/Anomaly/SharedAnomalySystem.cs | 7 + Resources/Locale/en-US/tiles/tiles.ftl | 1 + .../Markers/Spawners/Random/anomaly.yml | 2 + .../Prototypes/Entities/Mobs/NPCs/flesh.yml | 160 ++++++++++++++++++ .../Entities/Objects/Misc/kudzu.yml | 53 ++++++ .../Structures/Decoration/flesh_blockers.yml | 40 +++++ .../Structures/Specific/anomalies.yml | 81 ++++++++- Resources/Prototypes/Tiles/floors.yml | 16 ++ Resources/Prototypes/tags.yml | 3 + .../Textures/Mobs/Aliens/flesh.rsi/clamp.png | Bin 0 -> 613 bytes .../Textures/Mobs/Aliens/flesh.rsi/dead.png | Bin 0 -> 311 bytes .../Textures/Mobs/Aliens/flesh.rsi/golem.png | Bin 0 -> 1620 bytes .../Textures/Mobs/Aliens/flesh.rsi/jared.png | Bin 0 -> 741 bytes .../Textures/Mobs/Aliens/flesh.rsi/lover.png | Bin 0 -> 723 bytes .../Textures/Mobs/Aliens/flesh.rsi/meta.json | 27 +++ .../Objects/Misc/fleshkudzu.rsi/base.png | Bin 0 -> 1047 bytes .../Objects/Misc/fleshkudzu.rsi/meta.json | 14 ++ .../Decoration/flesh_decoration.rsi/ajar.png | Bin 0 -> 508 bytes .../flesh_decoration.rsi/closed.png | Bin 0 -> 505 bytes .../Decoration/flesh_decoration.rsi/meta.json | 20 +++ .../Decoration/flesh_decoration.rsi/open.png | Bin 0 -> 436 bytes .../Specific/anomaly.rsi/anom5-pulse.png | Bin 0 -> 1195 bytes .../Structures/Specific/anomaly.rsi/anom5.png | Bin 0 -> 429 bytes .../Structures/Specific/anomaly.rsi/meta.json | 18 +- Resources/Textures/Tiles/attributions.yml | 4 + Resources/Textures/Tiles/meat.png | Bin 0 -> 1858 bytes 41 files changed, 855 insertions(+), 47 deletions(-) create mode 100644 Content.Server/Anomaly/Effects/FleshAnomalySystem.cs create mode 100644 Content.Shared/Anomaly/Effects/BluespaceAnomalySystem.cs create mode 100644 Content.Shared/Anomaly/Effects/Components/BluespaceAnomalyComponent.cs create mode 100644 Content.Shared/Anomaly/Effects/Components/FleshAnomalyComponent.cs create mode 100644 Resources/Prototypes/Entities/Mobs/NPCs/flesh.yml create mode 100644 Resources/Prototypes/Entities/Structures/Decoration/flesh_blockers.yml create mode 100644 Resources/Textures/Mobs/Aliens/flesh.rsi/clamp.png create mode 100644 Resources/Textures/Mobs/Aliens/flesh.rsi/dead.png create mode 100644 Resources/Textures/Mobs/Aliens/flesh.rsi/golem.png create mode 100644 Resources/Textures/Mobs/Aliens/flesh.rsi/jared.png create mode 100644 Resources/Textures/Mobs/Aliens/flesh.rsi/lover.png create mode 100644 Resources/Textures/Mobs/Aliens/flesh.rsi/meta.json create mode 100644 Resources/Textures/Objects/Misc/fleshkudzu.rsi/base.png create mode 100644 Resources/Textures/Objects/Misc/fleshkudzu.rsi/meta.json create mode 100644 Resources/Textures/Structures/Decoration/flesh_decoration.rsi/ajar.png create mode 100644 Resources/Textures/Structures/Decoration/flesh_decoration.rsi/closed.png create mode 100644 Resources/Textures/Structures/Decoration/flesh_decoration.rsi/meta.json create mode 100644 Resources/Textures/Structures/Decoration/flesh_decoration.rsi/open.png create mode 100644 Resources/Textures/Structures/Specific/anomaly.rsi/anom5-pulse.png create mode 100644 Resources/Textures/Structures/Specific/anomaly.rsi/anom5.png create mode 100644 Resources/Textures/Tiles/meat.png diff --git a/Content.Client/Anomaly/AnomalySystem.cs b/Content.Client/Anomaly/AnomalySystem.cs index 57f1f90f10..b8e3e74393 100644 --- a/Content.Client/Anomaly/AnomalySystem.cs +++ b/Content.Client/Anomaly/AnomalySystem.cs @@ -1,4 +1,5 @@ -using Content.Shared.Anomaly; +using Content.Client.Gravity; +using Content.Shared.Anomaly; using Content.Shared.Anomaly.Components; using Robust.Client.GameObjects; using Robust.Shared.Timing; @@ -8,6 +9,7 @@ namespace Content.Client.Anomaly; public sealed class AnomalySystem : SharedAnomalySystem { [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly FloatingVisualizerSystem _floating = default!; /// public override void Initialize() @@ -15,6 +17,20 @@ public sealed class AnomalySystem : SharedAnomalySystem base.Initialize(); SubscribeLocalEvent(OnAppearanceChanged); + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnAnimationComplete); + } + + private void OnStartup(EntityUid uid, AnomalyComponent component, ComponentStartup args) + { + _floating.FloatAnimation(uid, component.FloatingOffset, component.AnimationKey, component.AnimationTime); + } + + private void OnAnimationComplete(EntityUid uid, AnomalyComponent component, AnimationCompletedEvent args) + { + if (args.Key != component.AnimationKey) + return; + _floating.FloatAnimation(uid, component.FloatingOffset, component.AnimationKey, component.AnimationTime); } private void OnAppearanceChanged(EntityUid uid, AnomalyComponent component, ref AppearanceChangeEvent args) diff --git a/Content.Server/Anomaly/AnomalySystem.Generator.cs b/Content.Server/Anomaly/AnomalySystem.Generator.cs index 2baacf6b52..7a2deb8611 100644 --- a/Content.Server/Anomaly/AnomalySystem.Generator.cs +++ b/Content.Server/Anomaly/AnomalySystem.Generator.cs @@ -4,7 +4,10 @@ using Content.Server.Power.EntitySystems; using Content.Shared.Anomaly; using Content.Shared.CCVar; using Content.Shared.Materials; +using Content.Shared.Physics; using Robust.Shared.Map.Components; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; namespace Content.Server.Anomaly; @@ -91,12 +94,32 @@ public sealed partial class AnomalySystem var randomY = Random.Next((int) gridBounds.Bottom, (int)gridBounds.Top); var tile = new Vector2i(randomX, randomY); - if (_atmosphere.IsTileSpace(grid, xform.MapUid, tile, - mapGridComp: gridComp) || _atmosphere.IsTileAirBlocked(grid, tile, mapGridComp: gridComp)) + + // no air-blocked areas. + if (_atmosphere.IsTileSpace(grid, xform.MapUid, tile, mapGridComp: gridComp) || + _atmosphere.IsTileAirBlocked(grid, tile, mapGridComp: gridComp)) { continue; } + // don't spawn inside of solid objects + var physQuery = GetEntityQuery(); + var valid = true; + foreach (var ent in gridComp.GetAnchoredEntities(tile)) + { + if (!physQuery.TryGetComponent(ent, out var body)) + continue; + if (body.BodyType != BodyType.Static || + !body.Hard || + (body.CollisionLayer & (int) CollisionGroup.Impassable) == 0) + continue; + + valid = false; + break; + } + if (!valid) + continue; + targetCoords = gridComp.GridTileToLocal(tile); break; } diff --git a/Content.Server/Anomaly/AnomalySystem.cs b/Content.Server/Anomaly/AnomalySystem.cs index 8dce08c406..e48fc328c4 100644 --- a/Content.Server/Anomaly/AnomalySystem.cs +++ b/Content.Server/Anomaly/AnomalySystem.cs @@ -23,7 +23,6 @@ public sealed partial class AnomalySystem : SharedAnomalySystem [Dependency] private readonly DoAfterSystem _doAfter = default!; [Dependency] private readonly ExplosionSystem _explosion = default!; [Dependency] private readonly MaterialStorageSystem _material = default!; - [Dependency] private readonly TransformSystem _transform = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!; public const float MinParticleVariation = 0.8f; @@ -100,13 +99,13 @@ public sealed partial class AnomalySystem : SharedAnomalySystem var multiplier = 1f; if (component.Stability > component.GrowthThreshold) multiplier = component.GrowingPointMultiplier; //more points for unstable - else if (component.Stability < component.DecayThreshold) - multiplier = component.DecayingPointMultiplier; //less points if it's dying //penalty of up to 50% based on health multiplier *= MathF.Pow(1.5f, component.Health) - 0.5f; - return (int) ((component.MaxPointsPerSecond - component.MinPointsPerSecond) * component.Severity * multiplier); + var severityValue = 1 / (1 + MathF.Pow(MathF.E, -7 * (component.Severity - 0.5f))); + + return (int) ((component.MaxPointsPerSecond - component.MinPointsPerSecond) * severityValue * multiplier) + component.MinPointsPerSecond; } /// diff --git a/Content.Server/Anomaly/Effects/ElectricityAnomalySystem.cs b/Content.Server/Anomaly/Effects/ElectricityAnomalySystem.cs index 55c7b1bfa5..6c473d3570 100644 --- a/Content.Server/Anomaly/Effects/ElectricityAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/ElectricityAnomalySystem.cs @@ -6,11 +6,13 @@ using Content.Shared.Anomaly.Effects.Components; using Content.Shared.Mobs.Components; using Content.Shared.StatusEffect; using Robust.Shared.Random; +using Robust.Shared.Timing; namespace Content.Server.Anomaly.Effects; public sealed class ElectricityAnomalySystem : EntitySystem { + [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly LightningSystem _lightning = default!; [Dependency] private readonly ElectrocutionSystem _electrocution = default!; @@ -25,16 +27,12 @@ public sealed class ElectricityAnomalySystem : EntitySystem private void OnPulse(EntityUid uid, ElectricityAnomalyComponent component, ref AnomalyPulseEvent args) { - var range = component.MaxElectrocuteRange * args.Stabiltiy; - var damage = (int) (component.MaxElectrocuteDamage * args.Severity); - var duration = component.MaxElectrocuteDuration * args.Severity; - + var range = component.MaxElectrocuteRange * args.Stability; var xform = Transform(uid); - foreach (var comp in _lookup.GetComponentsInRange(xform.MapPosition, range)) + foreach (var comp in _lookup.GetComponentsInRange(xform.MapPosition, range)) { var ent = comp.Owner; - - _electrocution.TryDoElectrocution(ent, uid, damage, duration, true, statusEffects: comp, ignoreInsulation: true); + _lightning.ShootLightning(uid, ent); } } @@ -48,7 +46,7 @@ public sealed class ElectricityAnomalySystem : EntitySystem if (mobQuery.HasComponent(ent)) validEnts.Add(ent); - if (_random.Prob(0.1f) && poweredQuery.HasComponent(ent)) + if (_random.Prob(0.2f) && poweredQuery.HasComponent(ent)) validEnts.Add(ent); } @@ -58,4 +56,32 @@ public sealed class ElectricityAnomalySystem : EntitySystem _lightning.ShootLightning(uid, ent); } } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + foreach (var (elec, anom, xform) in EntityQuery()) + { + if (_timing.CurTime < elec.NextSecond) + continue; + elec.NextSecond = _timing.CurTime + TimeSpan.FromSeconds(1); + + var owner = xform.Owner; + + if (!_random.Prob(elec.PassiveElectrocutionChance * anom.Stability)) + continue; + + var range = elec.MaxElectrocuteRange * anom.Stability; + var damage = (int) (elec.MaxElectrocuteDamage * anom.Severity); + var duration = elec.MaxElectrocuteDuration * anom.Severity; + + foreach (var comp in _lookup.GetComponentsInRange(xform.MapPosition, range)) + { + var ent = comp.Owner; + + _electrocution.TryDoElectrocution(ent, owner, damage, duration, true, statusEffects: comp, ignoreInsulation: true); + } + } + } } diff --git a/Content.Server/Anomaly/Effects/FleshAnomalySystem.cs b/Content.Server/Anomaly/Effects/FleshAnomalySystem.cs new file mode 100644 index 0000000000..227721fd7a --- /dev/null +++ b/Content.Server/Anomaly/Effects/FleshAnomalySystem.cs @@ -0,0 +1,97 @@ +using System.Linq; +using Content.Server.Maps; +using Content.Shared.Anomaly.Components; +using Content.Shared.Anomaly.Effects.Components; +using Content.Shared.Maps; +using Content.Shared.Physics; +using Robust.Shared.Map; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; +using Robust.Shared.Random; + +namespace Content.Server.Anomaly.Effects; + +public sealed class FleshAnomalySystem : EntitySystem +{ + [Dependency] private readonly IMapManager _map = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly ITileDefinitionManager _tiledef = default!; + [Dependency] private readonly TileSystem _tile = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnPulse); + SubscribeLocalEvent(OnSupercritical); + SubscribeLocalEvent(OnSeverityChanged); + } + + private void OnPulse(EntityUid uid, FleshAnomalyComponent component, ref AnomalyPulseEvent args) + { + var range = component.SpawnRange * args.Stability; + var amount = (int) (component.MaxSpawnAmount * args.Severity + 0.5f); + + var xform = Transform(uid); + SpawnMonstersOnOpenTiles(component, xform, amount, range); + } + + private void OnSupercritical(EntityUid uid, FleshAnomalyComponent component, ref AnomalySupercriticalEvent args) + { + var xform = Transform(uid); + SpawnMonstersOnOpenTiles(component, xform, component.MaxSpawnAmount, component.SpawnRange); + Spawn(component.SupercriticalSpawn, xform.Coordinates); + } + + private void OnSeverityChanged(EntityUid uid, FleshAnomalyComponent component, ref AnomalyStabilityChangedEvent args) + { + var xform = Transform(uid); + if (!_map.TryGetGrid(xform.GridUid, out var grid)) + return; + + var radius = component.SpawnRange * args.Stability; + var fleshTile = (ContentTileDefinition) _tiledef[component.FleshTileId]; + var localpos = xform.Coordinates.Position; + var tilerefs = grid.GetLocalTilesIntersecting( + new Box2(localpos + (-radius, -radius), localpos + (radius, radius))); + foreach (var tileref in tilerefs) + { + if (!_random.Prob(0.33f)) + continue; + _tile.ReplaceTile(tileref, fleshTile); + } + } + + private void SpawnMonstersOnOpenTiles(FleshAnomalyComponent component, TransformComponent xform, int amount, float radius) + { + if (!_map.TryGetGrid(xform.GridUid, out var grid)) + return; + + var localpos = xform.Coordinates.Position; + var tilerefs = grid.GetLocalTilesIntersecting( + new Box2(localpos + (-radius, -radius), localpos + (radius, radius))).ToArray(); + _random.Shuffle(tilerefs); + var physQuery = GetEntityQuery(); + var amountCounter = 0; + foreach (var tileref in tilerefs) + { + var valid = true; + foreach (var ent in grid.GetAnchoredEntities(tileref.GridIndices)) + { + if (!physQuery.TryGetComponent(ent, out var body)) + continue; + if (body.BodyType != BodyType.Static || + !body.Hard || + (body.CollisionLayer & (int) CollisionGroup.Impassable) == 0) + continue; + valid = false; + break; + } + if (!valid) + continue; + amountCounter++; + Spawn(_random.Pick(component.Spawns), tileref.GridIndices.ToEntityCoordinates(xform.GridUid.Value, _map)); + if (amountCounter >= amount) + return; + } + } +} diff --git a/Content.Server/Anomaly/Effects/PyroclasticAnomalySystem.cs b/Content.Server/Anomaly/Effects/PyroclasticAnomalySystem.cs index 12f0b31343..8e656a58c8 100644 --- a/Content.Server/Anomaly/Effects/PyroclasticAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/PyroclasticAnomalySystem.cs @@ -29,7 +29,7 @@ public sealed class PyroclasticAnomalySystem : EntitySystem private void OnPulse(EntityUid uid, PyroclasticAnomalyComponent component, ref AnomalyPulseEvent args) { var xform = Transform(uid); - var ignitionRadius = component.MaximumIgnitionRadius * args.Stabiltiy; + var ignitionRadius = component.MaximumIgnitionRadius * args.Stability; IgniteNearby(xform.Coordinates, args.Severity, ignitionRadius); } diff --git a/Content.Server/Maps/TileSystem.cs b/Content.Server/Maps/TileSystem.cs index 0b888cf225..ddf5efc7f1 100644 --- a/Content.Server/Maps/TileSystem.cs +++ b/Content.Server/Maps/TileSystem.cs @@ -3,6 +3,7 @@ using Content.Server.Decals; using Content.Shared.Decals; using Content.Shared.Maps; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Random; namespace Content.Server.Maps; @@ -54,6 +55,28 @@ public sealed class TileSystem : EntitySystem return DeconstructTile(tileRef); } + public bool ReplaceTile(TileRef tileref, ContentTileDefinition replacementTile) + { + if (!TryComp(tileref.GridUid, out var grid)) + return false; + return ReplaceTile(tileref, replacementTile, tileref.GridUid, grid); + } + + public bool ReplaceTile(TileRef tileref, ContentTileDefinition replacementTile, EntityUid grid, MapGridComponent? component = null) + { + if (!Resolve(grid, ref component)) + return false; + + var variant = _robustRandom.Pick(replacementTile.PlacementVariants); + var decals = _decal.GetDecalsInRange(tileref.GridUid, tileref.GridPosition().SnapToGrid(EntityManager, _mapManager).Position, 0.5f); + foreach (var (id, _) in decals) + { + _decal.RemoveDecal(tileref.GridUid, id); + } + component.SetTile(tileref.GridIndices, new Tile(replacementTile.TileId, 0, variant)); + return true; + } + private bool DeconstructTile(TileRef tileRef) { var indices = tileRef.GridIndices; diff --git a/Content.Shared/Anomaly/Components/AnomalyComponent.cs b/Content.Shared/Anomaly/Components/AnomalyComponent.cs index cdee844b1f..50f128d145 100644 --- a/Content.Shared/Anomaly/Components/AnomalyComponent.cs +++ b/Content.Shared/Anomaly/Components/AnomalyComponent.cs @@ -62,7 +62,7 @@ public sealed class AnomalyComponent : Component /// The amount of health lost when the stability is below the /// [DataField("healthChangePerSecond"), ViewVariables(VVAccess.ReadWrite)] - public float HealthChangePerSecond = -0.05f; + public float HealthChangePerSecond = -0.01f; #endregion #region Growth @@ -208,21 +208,14 @@ public sealed class AnomalyComponent : Component /// This doesn't include the point bonus for being unstable. /// [DataField("maxPointsPerSecond")] - public int MaxPointsPerSecond = 65; + public int MaxPointsPerSecond = 100; /// /// The multiplier applied to the point value for the /// anomaly being above the /// [DataField("growingPointMultiplier")] - public float GrowingPointMultiplier = 1.2f; - - /// - /// The multiplier applied to the point value for the - /// anomaly being below the - /// - [DataField("decayingPointMultiplier")] - public float DecayingPointMultiplier = 0.75f; + public float GrowingPointMultiplier = 1.5f; #endregion /// @@ -238,6 +231,24 @@ public sealed class AnomalyComponent : Component /// [DataField("anomalyContactDamageSound")] public SoundSpecifier AnomalyContactDamageSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg"); + + #region Floating Animation + /// + /// How long it takes to go from the bottom of the animation to the top. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("animationTime")] + public readonly float AnimationTime = 2f; + + /// + /// How far it goes in any direction. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("offset")] + public readonly Vector2 FloatingOffset = (0, 0.15f); + + public readonly string AnimationKey = "anomalyfloat"; + #endregion } [Serializable, NetSerializable] @@ -260,14 +271,10 @@ public sealed class AnomalyComponentState : ComponentState /// /// Event raised at regular intervals on an anomaly to do whatever its effect is. /// -/// +/// /// [ByRefEvent] -public readonly record struct AnomalyPulseEvent(float Stabiltiy, float Severity) -{ - public readonly float Stabiltiy = Stabiltiy; - public readonly float Severity = Severity; -} +public readonly record struct AnomalyPulseEvent(float Stability, float Severity); /// /// Event raised on an anomaly when it reaches a supercritical point. diff --git a/Content.Shared/Anomaly/Effects/BluespaceAnomalySystem.cs b/Content.Shared/Anomaly/Effects/BluespaceAnomalySystem.cs new file mode 100644 index 0000000000..920cc26e52 --- /dev/null +++ b/Content.Shared/Anomaly/Effects/BluespaceAnomalySystem.cs @@ -0,0 +1,73 @@ +using System.Linq; +using Content.Shared.Anomaly.Components; +using Content.Shared.Anomaly.Effects.Components; +using Content.Shared.Mobs.Components; +using Content.Shared.Teleportation.Components; +using Robust.Shared.Map; +using Robust.Shared.Random; + +namespace Content.Shared.Anomaly.Effects; + +public sealed class BluespaceAnomalySystem : EntitySystem +{ + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly SharedTransformSystem _xform = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnPulse); + SubscribeLocalEvent(OnSupercritical); + SubscribeLocalEvent(OnSeverityChanged); + } + + private void OnPulse(EntityUid uid, BluespaceAnomalyComponent component, ref AnomalyPulseEvent args) + { + var xform = Transform(uid); + var range = component.MaxShuffleRadius * args.Severity; + var allEnts = _lookup.GetComponentsInRange(xform.Coordinates, range) + .Select(x => x.Owner).ToList(); + allEnts.Add(uid); + + var xformQuery = GetEntityQuery(); + var coords = new List(); + foreach (var ent in allEnts) + { + if (xformQuery.TryGetComponent(ent, out var xf)) + coords.Add(xf.Coordinates); + } + + _random.Shuffle(coords); + for (var i = 0; i < allEnts.Count; i++) + { + _xform.SetCoordinates(allEnts[i], coords[i]); + } + } + + private void OnSupercritical(EntityUid uid, BluespaceAnomalyComponent component, ref AnomalySupercriticalEvent args) + { + var xform = Transform(uid); + var mapPos = _xform.GetWorldPosition(xform); + var radius = component.SupercriticalTeleportRadius; + var gridBounds = new Box2(mapPos - (radius, radius), mapPos + (radius, radius)); + foreach (var comp in _lookup.GetComponentsInRange(xform.Coordinates, component.MaxShuffleRadius)) + { + var ent = comp.Owner; + var randomX = _random.NextFloat(gridBounds.Left, gridBounds.Right); + var randomY = _random.NextFloat(gridBounds.Bottom, gridBounds.Top); + + var pos = new Vector2(randomX, randomY); + _xform.SetWorldPosition(ent, pos); + _audio.PlayPvs(component.TeleportSound, ent); + } + } + + private void OnSeverityChanged(EntityUid uid, BluespaceAnomalyComponent component, ref AnomalySeverityChangedEvent args) + { + if (!TryComp(uid, out var portal)) + return; + portal.MaxRandomRadius = (component.MaxPortalRadius - component.MinPortalRadius) * args.Severity + component.MinPortalRadius; + } +} diff --git a/Content.Shared/Anomaly/Effects/Components/BluespaceAnomalyComponent.cs b/Content.Shared/Anomaly/Effects/Components/BluespaceAnomalyComponent.cs new file mode 100644 index 0000000000..446194188b --- /dev/null +++ b/Content.Shared/Anomaly/Effects/Components/BluespaceAnomalyComponent.cs @@ -0,0 +1,40 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Anomaly.Effects.Components; + +[RegisterComponent, NetworkedComponent] +[Access(typeof(BluespaceAnomalySystem))] +public sealed class BluespaceAnomalyComponent : Component +{ + /// + /// The maximum radius that the shuffle effect will extend for + /// scales with stability + /// + [DataField("maxShuffleRadius"), ViewVariables(VVAccess.ReadWrite)] + public float MaxShuffleRadius = 10; + + /// + /// The maximum MAX distance the portal this anomaly is tied to can teleport you. + /// + [DataField("maxPortalRadius"), ViewVariables(VVAccess.ReadWrite)] + public float MaxPortalRadius = 25; + + /// + /// The minimum MAX distance the portal this anomaly is tied to can teleport you. + /// + [DataField("minPortalRadius"), ViewVariables(VVAccess.ReadWrite)] + public float MinPortalRadius = 10; + + /// + /// How far the supercritical event can teleport you + /// + [DataField("superCriticalTeleportRadius"), ViewVariables(VVAccess.ReadWrite)] + public float SupercriticalTeleportRadius = 50f; + + /// + /// The sound played after players are shuffled/teleported around + /// + [DataField("teleportSound"), ViewVariables(VVAccess.ReadWrite)] + public SoundSpecifier TeleportSound = new SoundPathSpecifier("/Audio/Effects/teleport_arrival.ogg"); +} diff --git a/Content.Shared/Anomaly/Effects/Components/ElectricityAnomalyComponent.cs b/Content.Shared/Anomaly/Effects/Components/ElectricityAnomalyComponent.cs index fc430127ef..9afdd0aaa2 100644 --- a/Content.Shared/Anomaly/Effects/Components/ElectricityAnomalyComponent.cs +++ b/Content.Shared/Anomaly/Effects/Components/ElectricityAnomalyComponent.cs @@ -1,14 +1,41 @@ -namespace Content.Shared.Anomaly.Effects.Components; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Anomaly.Effects.Components; [RegisterComponent] public sealed class ElectricityAnomalyComponent : Component { + /// + /// The maximum radius of the passive electrocution effect + /// scales with stability + /// [DataField("maxElectrocutionRange"), ViewVariables(VVAccess.ReadWrite)] - public float MaxElectrocuteRange = 6f; + public float MaxElectrocuteRange = 7f; + /// + /// The maximum amount of damage the electrocution can do + /// scales with severity + /// [DataField("maxElectrocuteDamage"), ViewVariables(VVAccess.ReadWrite)] public float MaxElectrocuteDamage = 20f; + /// + /// The maximum amount of time the electrocution lasts + /// scales with severity + /// [DataField("maxElectrocuteDuration"), ViewVariables(VVAccess.ReadWrite)] public TimeSpan MaxElectrocuteDuration = TimeSpan.FromSeconds(8); + + /// + /// The maximum chance that each second, when in range of the anomaly, you will be electrocuted. + /// scales with stability + /// + [DataField("passiveElectrocutionChance"), ViewVariables(VVAccess.ReadWrite)] + public float PassiveElectrocutionChance = 0.05f; + + /// + /// Used for tracking seconds, so that we can shock people in a non-tick-dependent way. + /// + [DataField("nextSecond", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + public TimeSpan NextSecond = TimeSpan.Zero; } diff --git a/Content.Shared/Anomaly/Effects/Components/FleshAnomalyComponent.cs b/Content.Shared/Anomaly/Effects/Components/FleshAnomalyComponent.cs new file mode 100644 index 0000000000..abd0b01939 --- /dev/null +++ b/Content.Shared/Anomaly/Effects/Components/FleshAnomalyComponent.cs @@ -0,0 +1,43 @@ +using Content.Shared.Maps; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; + +namespace Content.Shared.Anomaly.Effects.Components; + +[RegisterComponent] +public sealed class FleshAnomalyComponent : Component +{ + /// + /// A list of entities that are random picked to be spawned on each pulse + /// + [DataField("spawns", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer)), ViewVariables(VVAccess.ReadWrite)] + public List Spawns = new(); + + /// + /// The maximum number of entities that spawn per pulse + /// scales with severity. + /// + [DataField("maxSpawnAmount"), ViewVariables(VVAccess.ReadWrite)] + public int MaxSpawnAmount = 8; + + /// + /// 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 = 4f; + + /// + /// The tile that is spawned by the anomaly's effect + /// + [DataField("fleshTileId", customTypeSerializer: typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)] + public string FleshTileId = "FloorFlesh"; + + /// + /// The entity spawned when the anomaly goes supercritical + /// + [DataField("superCriticalSpawn", customTypeSerializer: typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)] + public string SupercriticalSpawn = "FleshKudzu"; +} diff --git a/Content.Shared/Anomaly/Effects/Components/GravityAnomalyComponent.cs b/Content.Shared/Anomaly/Effects/Components/GravityAnomalyComponent.cs index a6f80aeda0..761bc9daec 100644 --- a/Content.Shared/Anomaly/Effects/Components/GravityAnomalyComponent.cs +++ b/Content.Shared/Anomaly/Effects/Components/GravityAnomalyComponent.cs @@ -1,6 +1,8 @@ -namespace Content.Shared.Anomaly.Effects.Components; +using Robust.Shared.GameStates; -[RegisterComponent] +namespace Content.Shared.Anomaly.Effects.Components; + +[RegisterComponent, NetworkedComponent] public sealed class GravityAnomalyComponent : Component { /// diff --git a/Content.Shared/Anomaly/Effects/Components/PyroclasticAnomalyComponent.cs b/Content.Shared/Anomaly/Effects/Components/PyroclasticAnomalyComponent.cs index 5f3c1c2595..9cfa56bcc2 100644 --- a/Content.Shared/Anomaly/Effects/Components/PyroclasticAnomalyComponent.cs +++ b/Content.Shared/Anomaly/Effects/Components/PyroclasticAnomalyComponent.cs @@ -13,7 +13,7 @@ public sealed class PyroclasticAnomalyComponent : Component /// I have no clue if this is balanced. /// [DataField("heatPerSecond")] - public float HeatPerSecond = 50; + public float HeatPerSecond = 25; /// /// The maximum distance from which you can be ignited by the anomaly. @@ -50,5 +50,5 @@ public sealed class PyroclasticAnomalyComponent : Component /// The amount of gas released when the anomaly goes supercritical /// [DataField("supercriticalMoleAmount")] - public float SupercriticalMoleAmount = 50f; + public float SupercriticalMoleAmount = 75f; } diff --git a/Content.Shared/Anomaly/Effects/SharedGravityAnomalySystem.cs b/Content.Shared/Anomaly/Effects/SharedGravityAnomalySystem.cs index d7cf92c17d..09f8ec35ee 100644 --- a/Content.Shared/Anomaly/Effects/SharedGravityAnomalySystem.cs +++ b/Content.Shared/Anomaly/Effects/SharedGravityAnomalySystem.cs @@ -29,9 +29,8 @@ public abstract class SharedGravityAnomalySystem : EntitySystem foreach (var ent in lookup) { var tempXform = Transform(ent); - var foo = tempXform.MapPosition.Position - xform.MapPosition.Position; - _throwing.TryThrow(ent, foo.Normalized * 10, strength, uid, 0); + _throwing.TryThrow(ent, foo * 10, strength, uid, 0); } } @@ -54,7 +53,6 @@ public abstract class SharedGravityAnomalySystem : EntitySystem var tempXform = Transform(ent); var foo = tempXform.MapPosition.Position - xform.MapPosition.Position; - Logger.Debug($"{ToPrettyString(ent)}: {foo}: {foo.Normalized}: {foo.Normalized * 10}"); _throwing.TryThrow(ent, foo * 5, strength, uid, 0); } } diff --git a/Content.Shared/Anomaly/SharedAnomalySystem.cs b/Content.Shared/Anomaly/SharedAnomalySystem.cs index 6106112a1d..874e28ebcd 100644 --- a/Content.Shared/Anomaly/SharedAnomalySystem.cs +++ b/Content.Shared/Anomaly/SharedAnomalySystem.cs @@ -119,6 +119,9 @@ public abstract class SharedAnomalySystem : EntitySystem if (!Resolve(uid, ref component)) return; + if (!Timing.IsFirstTimePredicted) + return; + DebugTools.Assert(component.MinPulseLength > TimeSpan.FromSeconds(3)); // this is just to prevent lagspikes mispredicting pulses var variation = Random.NextFloat(-component.PulseVariation, component.PulseVariation) + 1; component.NextPulseTime = Timing.CurTime + GetPulseLength(component) * variation; @@ -173,6 +176,10 @@ public abstract class SharedAnomalySystem : EntitySystem { if (!Resolve(uid, ref component)) return; + + if (!Timing.IsFirstTimePredicted) + return; + Audio.PlayPvs(component.SupercriticalSound, uid); var ev = new AnomalySupercriticalEvent(); diff --git a/Resources/Locale/en-US/tiles/tiles.ftl b/Resources/Locale/en-US/tiles/tiles.ftl index a53fa1988f..974db2ab6e 100644 --- a/Resources/Locale/en-US/tiles/tiles.ftl +++ b/Resources/Locale/en-US/tiles/tiles.ftl @@ -82,6 +82,7 @@ tiles-asteroid-ironsand-pebbles = asteroid ironsand pebbles tiles-asteroid-ironsand-rock = asteroid ironsand rock tiles-cave = cave tiles-cave-drought = cave drought +tiles-flesh-floor = flesh floor tiles-techmaint3-floor = grated maintenance floor tiles-techmaint2-floor = steel maintenance floor tiles-wood2 = wood pattern floor diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml index a082fae7d6..a21437fd77 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml @@ -13,4 +13,6 @@ - AnomalyPyroclastic - AnomalyGravity - AnomalyElectricity + - AnomalyFlesh + - AnomalyBluespace chance: 1 diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/flesh.yml b/Resources/Prototypes/Entities/Mobs/NPCs/flesh.yml new file mode 100644 index 0000000000..68dde1d1b5 --- /dev/null +++ b/Resources/Prototypes/Entities/Mobs/NPCs/flesh.yml @@ -0,0 +1,160 @@ +- type: entity + parent: SimpleMobBase + id: BaseMobFlesh + name: aberrant flesh + description: A shambling mass of flesh, animated through anomalous energy. + abstract: true + components: + - type: HTN + rootTask: SimpleHostileCompound + - type: Faction + factions: + - SimpleHostile + - type: Tag + tags: + - DoorBumpOpener + - Flesh + - type: Sprite + drawdepth: Mobs + sprite: Mobs/Aliens/flesh.rsi + - type: MovementAlwaysTouching + - type: MovementSpeedModifier + baseWalkSpeed: 1 + baseSprintSpeed: 1.5 + - type: MobState + allowedStates: + - Alive + - Dead + - type: MobThresholds + thresholds: + 0: Alive + 75: Dead + - type: Stamina + excess: 50 + - type: Appearance + - type: Butcherable + spawned: + - id: FoodMeat + amount: 1 + - type: Bloodstream + bloodMaxVolume: 500 + - type: CombatMode + disarmAction: + enabled: false + autoPopulate: false + name: action-name-disarm + - type: MeleeWeapon + hidden: true + soundHit: + path: /Audio/Weapons/Xeno/alien_claw_flesh3.ogg + angle: 0 + animation: WeaponArcClaw + damage: + types: + Slash: 3 + - type: ReplacementAccent + accent: genericAggressive + +- type: entity + parent: BaseMobFlesh + id: MobFleshJared + components: + - type: Sprite + layers: + - map: [ "enum.DamageStateVisualLayers.Base" ] + state: jared + - type: DamageStateVisuals + states: + Alive: + Base: jared + Critical: + Base: dead + Dead: + Base: dead + - type: MeleeWeapon + hidden: true + soundHit: + path: /Audio/Weapons/Xeno/alien_claw_flesh3.ogg + angle: 0 + animation: WeaponArcClaw + damage: + types: + Slash: 5 + +- type: entity + parent: BaseMobFlesh + id: MobFleshGolem + components: + - type: Sprite + layers: + - map: [ "enum.DamageStateVisualLayers.Base" ] + state: golem + - type: DamageStateVisuals + states: + Alive: + Base: golem + Critical: + Base: dead + Dead: + Base: dead + - type: MobThresholds + thresholds: + 0: Alive + 50: Dead + - type: MeleeWeapon + hidden: true + soundHit: + path: /Audio/Weapons/Xeno/alien_claw_flesh3.ogg + angle: 0 + animation: WeaponArcClaw + damage: + types: + Slash: 5 + +- type: entity + parent: BaseMobFlesh + id: MobFleshClamp + components: + - type: Sprite + layers: + - map: [ "enum.DamageStateVisualLayers.Base" ] + state: clamp + - type: DamageStateVisuals + states: + Alive: + Base: clamp + Critical: + Base: dead + Dead: + Base: dead + - type: MobThresholds + thresholds: + 0: Alive + 30: Dead + - type: MovementSpeedModifier + baseWalkSpeed: 2 + baseSprintSpeed: 2.5 + +- type: entity + parent: BaseMobFlesh + id: MobFleshLover + components: + - type: Sprite + layers: + - map: [ "enum.DamageStateVisualLayers.Base" ] + state: lover + - type: DamageStateVisuals + states: + Alive: + Base: lover + Critical: + Base: dead + Dead: + Base: dead + - type: MobThresholds + thresholds: + 0: Alive + 30: Dead + - type: MovementSpeedModifier + baseWalkSpeed: 2 + baseSprintSpeed: 2.5 diff --git a/Resources/Prototypes/Entities/Objects/Misc/kudzu.yml b/Resources/Prototypes/Entities/Objects/Misc/kudzu.yml index d2942f45cc..280ce2c7e3 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/kudzu.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/kudzu.yml @@ -14,6 +14,7 @@ "/Audio/Weapons/slash.ogg" - type: Sprite sprite: Objects/Misc/kudzu.rsi + color: "#ff0000" state: kudzu_11 drawdepth: Overdoors netsync: false @@ -77,3 +78,55 @@ - type: SlowContacts walkSpeedModifier: 0.2 sprintSpeedModifier: 0.2 + +- type: entity + id: FleshKudzu + name: tendons + description: A rapidly growing cluster of meaty tendons. WHY ARE YOU STOPPING TO LOOK AT IT?! + placement: + mode: SnapgridCenter + snap: + - Wall + components: + - type: MeleeSound + soundGroups: + Brute: + path: + "/Audio/Weapons/slash.ogg" + - type: Sprite + sprite: Objects/Misc/fleshkudzu.rsi + state: base + drawdepth: Overdoors + netsync: false + - type: Appearance + - type: Clickable + - type: Transform + anchored: true + - type: Physics + - type: Fixtures + fixtures: + - hard: false + density: 7 + shape: + !type:PhysShapeAabb + bounds: "-0.5,-0.5,0.5,0.5" + layer: + - MidImpassable + - type: Damageable + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 10 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - type: Spreader + growthResult: FleshKudzu + chance: 1 + - type: SlowContacts + walkSpeedModifier: 0.2 + sprintSpeedModifier: 0.2 + ignoreWhitelist: + tags: + - Flesh diff --git a/Resources/Prototypes/Entities/Structures/Decoration/flesh_blockers.yml b/Resources/Prototypes/Entities/Structures/Decoration/flesh_blockers.yml new file mode 100644 index 0000000000..e883177707 --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Decoration/flesh_blockers.yml @@ -0,0 +1,40 @@ +- type: entity + id: FleshBlocker + parent: BaseStructure + name: flesh clump + description: An annoying clump of flesh. + components: + - type: InteractionOutline + - type: Sprite + noRot: true + sprite: Structures/Decoration/flesh_decoration.rsi + layers: + - state: closed + map: [ "enum.DamageStateVisualLayers.Base" ] + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.3 + density: 190 + mask: + - MachineMask + layer: + - Impassable + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + closed: "" + - enum.DamageStateVisualLayers.Base: + ajar: "" + - enum.DamageStateVisualLayers.Base: + open: "" + - type: Damageable + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 25 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] diff --git a/Resources/Prototypes/Entities/Structures/Specific/anomalies.yml b/Resources/Prototypes/Entities/Structures/Specific/anomalies.yml index 5d57d343a7..1dfeefff36 100644 --- a/Resources/Prototypes/Entities/Structures/Specific/anomalies.yml +++ b/Resources/Prototypes/Entities/Structures/Specific/anomalies.yml @@ -20,7 +20,7 @@ - type: Transform anchored: true - type: Physics - bodyType: Static + bodyType: Static - type: Fixtures fixtures: - shape: @@ -33,12 +33,14 @@ - MobLayer - type: Sprite netsync: false - drawdepth: Items + noRot: true + drawdepth: Effects #it needs to draw over stuff. sprite: Structures/Specific/anomaly.rsi - type: InteractionOutline - type: Clickable - type: Damageable - type: Appearance + - type: AnimationPlayer - type: GuideHelp guides: - AnomalousResearch @@ -71,7 +73,6 @@ suffix: Gravity components: - type: Sprite - drawdepth: Effects #it needs to draw over stuff. layers: - state: anom2 map: ["enum.AnomalyVisualLayers.Base"] @@ -105,4 +106,76 @@ color: "#ffffaa" castShadows: false - type: ElectricityAnomaly - - type: Electrified \ No newline at end of file + - type: Electrified + +- type: entity + id: AnomalyFlesh + parent: BaseAnomaly + suffix: Flesh + components: + - type: Sprite + layers: + - state: anom5 + map: ["enum.AnomalyVisualLayers.Base"] + - state: anom5-pulse + map: ["enum.AnomalyVisualLayers.Animated"] + visible: false + - type: PointLight + radius: 2.0 + energy: 7.5 + color: "#cb5b7e" + castShadows: false + - type: FleshAnomaly + spawns: + - MobFleshJared + - MobFleshGolem + - MobFleshClamp + - MobFleshLover + - FleshBlocker + +- type: entity + id: AnomalyBluespace + parent: BaseAnomaly + suffix: Bluespace + components: + - type: Sprite + layers: + - state: anom4 + map: ["enum.AnomalyVisualLayers.Base"] + - state: anom4-pulse + map: ["enum.AnomalyVisualLayers.Animated"] + visible: false + - type: PointLight + radius: 2.0 + energy: 7.5 + color: "#00ccff" + castShadows: false + - type: BluespaceAnomaly + - type: Portal + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.35 + density: 50 + mask: + - MobMask + layer: + - MobLayer + - id: portalFixture + shape: + !type:PhysShapeAabb + bounds: "-0.25,-0.48,0.25,0.48" + mask: + - FullTileMask + layer: + - WallLayer + hard: false + - type: Anomaly + pulseSound: + collection: RadiationPulse + params: + volume: 5 + anomalyContactDamage: + types: + Radiation: 10 diff --git a/Resources/Prototypes/Tiles/floors.yml b/Resources/Prototypes/Tiles/floors.yml index 9043d57afa..a23e9493a4 100644 --- a/Resources/Prototypes/Tiles/floors.yml +++ b/Resources/Prototypes/Tiles/floors.yml @@ -1367,6 +1367,22 @@ thermalConductivity: 0.04 heatCapacity: 10000 +- type: tile + id: FloorFlesh + name: tiles-flesh-floor + sprite: /Textures/Tiles/meat.png + variants: 4 + placementVariants: [0, 1, 2, 3] + baseTurfs: + - Plating + isSubfloor: false + canCrowbar: true + footstepSounds: + collection: BarestepCarpet + friction: 0.20 #slippy + thermalConductivity: 0.04 + heatCapacity: 10000 + - type: tile id: FloorTechMaint2 name: tiles-techmaint2-floor diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 859eff49db..dbb2562846 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -216,6 +216,9 @@ - type: Tag id: FireAxe +- type: Tag + id: Flesh + - type: Tag id: WhitelistChameleon diff --git a/Resources/Textures/Mobs/Aliens/flesh.rsi/clamp.png b/Resources/Textures/Mobs/Aliens/flesh.rsi/clamp.png new file mode 100644 index 0000000000000000000000000000000000000000..d9085d75b9609deab2fca9c02fb905a185119f9c GIT binary patch literal 613 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 XAc?LPld5Ch00000NkvXXu0mjfp4d>` literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Aliens/flesh.rsi/lover.png b/Resources/Textures/Mobs/Aliens/flesh.rsi/lover.png new file mode 100644 index 0000000000000000000000000000000000000000..0b5229c37f85e1d26dbab44f8a8c8cc4298a7b3c GIT binary patch literal 723 zcmV;^0xbQBP)Px%jY&j7R9J=WmN97CKoo|5)d7RBX$D2b#aU!;DFh|ZC2NO5>6j^lySP&+ow62n z^c1pW$WqN+J7)D*cXB61OH7R~hS=B~xQjX{?{Yfd$x0gN;(rm+o!DCE)>`X7 z%X;j9f#WCYv(Mw7M$WwqQo#y&uN0B?I)rM(_q#*DUiLRj^zY9gyPW8PxVb;P}b+$w1tn?ComewmnLn8FOtt_Zzi;9ge?wIvkE|B%K8Xxe!DN_BfFbeh>iyP% zkVh665(*IV$f8Whh$_lhegFN7=IsnWDYP4sJiCe=cT)t-m{UX<>yn_gA>HJ%Cba8- zdKSq0k7Zbwjd9>Q88ab|th^)HQU&g|Px&(Md!>R9J3U@q>01_P*FuR+w6~Qnlw== zDn7u{Hd`QVnT9^HR&Xng>z7iGKBIeAvKrI zOs%jET0UnIn%JRp=R}rw6v>%_io6o9BD1W=lxt8Z8-+Gx3HMdX-`uJz~jj(_=Oy`X2cmCNg@i$5M{F^W*Zi zsJm)yfsjZeG6*^Ibv9)XZj|kqf(cR`u|z;#RA2GIxeIE7Ve#-ffm^w3fKqMeiz#1F zx|wWDndau72q`qNgW0lhDH_TQzzGqYxPY38psUON-2R{g4^8a2@&R={8JCSG=Q!}% zwfh0dd@%)POLi)glIJQ^OpaxpWhaLwcGml(vRctQ3ZBYFwj`%WinsE>$nSi)Y>*=| zr1hv@Y^8b^d{PR4*ozLfxE9-k*0wi?S)lB%V=vJbV=B7liCCNTZH}3VV%M78R8{L(QrrhhLbDLAC!yB{+ z;@pJD4;PmfkN5Att&3*eg+k7+F9Iay03C!)WJ1*Bjl>*yWaM)BRYU5#fpj*A03pRm3w8-s*`k-UDc88td`47KQY4dAp` z>g7^iK9n&zUhfm@T`&1T^S_Oh&Mu_@xSsR@BOTZ6{}lN3MNsLLZqqAK@gJ%Ko+qZW Rzv=)0002ovPDHLkV1nH{>MQ^N literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Misc/fleshkudzu.rsi/meta.json b/Resources/Textures/Objects/Misc/fleshkudzu.rsi/meta.json new file mode 100644 index 0000000000..fc8bf10c30 --- /dev/null +++ b/Resources/Textures/Objects/Misc/fleshkudzu.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC0-1.0", + "copyright": "Created by EmoGarbage404 (github) for space-station-14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "base" + } + ] +} diff --git a/Resources/Textures/Structures/Decoration/flesh_decoration.rsi/ajar.png b/Resources/Textures/Structures/Decoration/flesh_decoration.rsi/ajar.png new file mode 100644 index 0000000000000000000000000000000000000000..c4e0b26773f868de5b8c83c4735288713d350dd4 GIT binary patch literal 508 zcmVPx$wn;=mR9J=WRlQ2XP#8T*V_KU2Q0~??P!YjFp@XZC-8_I$U%h917P+VLJLOY2O5)8C4)i{*zlB7v<)6&VD>3;X#eCK@Ue)k5*kRd~c4F4Tl>n70U zmgkTA&ReRSxpf5qfL5!+bR7!4G$OXwA=c%V*Df(Ag&eAq3;<}C*n%q?6952>auN1q z#^b6arxLNU0IEJrZn_S4W1|9yFlx@%51SQ0FkJ_IW5maea#8pgRuVw=6XD_YF<%S! zL=sY6L#n7_U}(pdhsS~ zULEmqx7UHrRE%$4@ci+Kp=|~BrfI@hd&quZ?!v%&htAZ%D@R1+l0P<_DgW-#9mVoQ yF8I%01Vk1!4*;)ID^|qPYZ$IDYAr6#Ac{X(?7M}7!Zo4*0000Px$vq?ljR9J=Wlp#;UKp2J}$VRuU+X$&+G=X3chzS&G8ipkp1d?BX#)9DwU{L7& z0K|gEfgvH8ThfF!G}$g46hXdAJ2u*~q3Emn^{)56_w>7iT)A@P%Jtv1FzW(sV?B)4 z9rcoF&BCk!09q@nxPg)~%o1X87UQ*UAB=DVg`sy*>a(Ya1H-v+rRUB>*1YoWz?kkwB|xhigk_%(&z9*t=qcZ>rD4f#|Px$Zb?KzR9J=Wl(9;~P!xv0swD-hky`0c8)$LqBKiOwx{7&#g3f}AgR^g-gNuuk zDEI(%@6ZS6rkg^8Lm_BO0&SW?9BM+E-lU*|2>09apL@>v@4e>+Boc{4B9TZWe@rSV zSWjzSRBO52#GGi}qV+3DMXDK95YaqQ(Qs2gFRx_CTFZgnbl&Fjga&k_?Cr1R*+xs=uuM(Y^0T-K^%VLypjpN<4g#jQ}`ME2H%K}$VBXaAY35H eNVJLM-|+=Qh@R}L-ZlvU0000Px(Wl2OqRCt{2T03qVF%W$l1QMXmW+5nT0vRq`8&Hu8q{;z&iyR}j&;e5A0x1lr zcA;2++XyNsbplom(|Fb+YDms5*ES6E0S1iaF5lyDH2ll}1qB5K1>JEExYyQ@gAcDQ z;I&b8{ZN|ui;Vud@=uMy%G%EStv?{*2LQK|YitgCj0Ypk)(d=oeCIh0(Ko;PMW6V* z8Ug^8^$wTAGXTKW)z4-KXN+4}tLC2?gUZ?@ze?ae;Czdd01^Q}6w-$gXz=sLf%8H0 z{|Q@H<7T~389^Ncxz+jL0UU{;_S?y|w(BJL;C);U&#7oMm4G0MR&v@nDp-8It&Ud`V&J>LkBv8T4m?M8pO! zeb*JdADaEP--VDgzy(l!#P^U7#k;>0Ehs1`C@3f>c(ZWEWbH)X z{Z2630J$^J2X~H!&IY\fA?ha!K_U5yaE6qUfw0K7b3Lc5QyXEx%tM zz(LQSr9ObjFNbGMPQVARADH)8AHexFXv43n4_H~NCZ`1Ic{Rk!+Uy%6ntfg$km3f= z@TY>K$^*DHV<~DPmcGk@-%qGW!=EG#f2;Zco)PxTVnTv)>I3}Q=lzDz)(fHrm>Sbu zJyTMGTR#+tIBqA`ssx1(5*_nCDNz#gf{+n{2H+p?0tKl+$`>OUM!QjQ#yII+J^|GK z=CD68Ld+wjzJnW~%G$~q0Dy1*{zUf!o$CYm;3W?^uZF+?Ss7yT!nwdt z8i3Q1oMpYk2K%NwCgy#rW$-3ZrP1cQE(rC*y^rf4T^fE>eZbV1qhO;+Q*T|3sWI6H zqsrP7ey$-@CPVzaZH0M$J{1^gFWx7*)CXwL=`{E=QXkOvG}eWm4rQ?-X)XVos}G3X z2XrxfR($~9;jOHF(fqu$S?bf{vV^=OcWCGMZcwhp3knKy@E^obSQm=gLnr_M002ov JPDHLkV1m63HmU#s literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/anomaly.rsi/anom5.png b/Resources/Textures/Structures/Specific/anomaly.rsi/anom5.png new file mode 100644 index 0000000000000000000000000000000000000000..6117776649f15449eccd5d7ab6683ca17d41a968 GIT binary patch literal 429 zcmV;e0aE^nP)Px$XGugsR9J=WmN9OGFc3vQAp#jG#j*uA$ZE?yz#f8=atIDU$r+FWbRZ)kry69u zHXcw`Y51kF{ofzP2H@1GQ~#{s=)znGWsVi&xO>0d3&^;eXFRVDG}C}AN>H{H(lFc& z!k%avr$Gz=sAZ3Pd;tJ-O6~?>0pvm`Gcf@W1OO|D58{IZ0AQ6`H`k2`Bn@IbuMgI~ zUI0p;1~F>cBa0I2JQ~*_x_P!X>n;EQt2AbMecXiORACc9PtTD#k5dJ21@shIl%SUV zQf8MrC9Ugi`t$*i$dpci+4=gMW*X37SUq!z)dO_a@9||Rvwq}EK#nmRplmDahGg7K z!%KAtu$Dc_w%Xi(^A!~18012zPRW-BYo=i_aw&@v{CF-S)+;bmPM#W)6O z7_K_InfwjbDfzcoaoJWY2%kA8J#g@A`2BTrHs)KthAt5Ol6m|8fD1&|kw2nSr%wF> X39-#Z{0ZNi00000NkvXXu0mjf>4mXC literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Specific/anomaly.rsi/meta.json b/Resources/Textures/Structures/Specific/anomaly.rsi/meta.json index f9d4be792f..c318e8116b 100644 --- a/Resources/Textures/Structures/Specific/anomaly.rsi/meta.json +++ b/Resources/Textures/Structures/Specific/anomaly.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC0-1.0", - "copyright": "Created by EmoGarbage; anom3, anom3-pulse, anom4, anom4-pulse are CC-BY-SA-3.0 at https://github.com/ParadiseSS13/Paradise/blob/master/icons/effects/effects.dmi", + "copyright": "Created by EmoGarbage; anom3, anom3-pulse, anom4, anom4-pulse are CC-BY-SA-3.0 at https://github.com/ParadiseSS13/Paradise/blob/master/icons/effects/effects.dmi; anom5, anom5-pulse are CC-BY-SA-3.0 by Aleksh#7552 (discord) for space-station-14", "size": { "x": 32, "y": 32 @@ -92,6 +92,20 @@ 0.15 ] ] + }, + { + "name": "anom5" + }, + { + "name": "anom5-pulse", + "delays": [ + [ + 0.25, + 0.25, + 0.25, + 0.25 + ] + ] } ] -} \ No newline at end of file +} diff --git a/Resources/Textures/Tiles/attributions.yml b/Resources/Textures/Tiles/attributions.yml index 9fec6d6c0e..9ce6c90cd0 100644 --- a/Resources/Textures/Tiles/attributions.yml +++ b/Resources/Textures/Tiles/attributions.yml @@ -56,3 +56,7 @@ copyright: "by brainfood for space-station-14, ." source: "https://github.com/space-wizards/space-station-14/pull/12193" +- files: ["meat.png"] + license: "CC0-1.0" + copyright: "Created by EmoGarbage404 (github) for space-station-14." + source: "https://github.com/space-wizards/space-station-14/pull/13766" diff --git a/Resources/Textures/Tiles/meat.png b/Resources/Textures/Tiles/meat.png new file mode 100644 index 0000000000000000000000000000000000000000..d593c1bdfcdb6857938739208bd57f3acf876a30 GIT binary patch literal 1858 zcmV-I2fg@-P)Px*{7FPXRCt{2n@w&cMG%G4R$0bUBfMb4o-H@vL>z__a)enJ$&#mKOT#KWuU~&J zA{(}ZWNEr8Gk!87OQ`-^)K#_(VExGQ_FIl@c%S=g(&}r+ZI^&;p*Gj`jNXvCZFYIXxX0zhB=z zF6^fTu6LxjZkWq2y>)Kq1j?)ClKkg~$4@;-{^1Lk6mVneT`f{Aj&8L6PK%&M)O&Rj zm*+avCaVqpT;J)x6MvVbd|Y-%X=7Y|cbbXZaci#gD7l^d!(S@%v_Zc4L}ZY9qx019 z>I9vmsrh~5tXN#zmu-IXyws@=Fq}B&rXjNcI&xsj5@RH*ExZv4my;bbChmJ=V5996&7jZ z-KdV}guC;(3|g>yPQ{Mv(S>_GeNHLIPX(Qhp;Jq?==|LpjreFvtaqvd?hpy=jP4Yi zoTLNdhqKC=TmC924J#y^S4xNKNKRjMKKv#6R zS5GG-g-lXR1?as66iIw{ss*GE)k>`{T#ozU{)0oxpUuy8K85 zB%y`3=vTZF2&Fm@M5@2Zh6Ijvhb7stBQNoEA|2fUJcV5$fy9WYLkD*Xv~GS^5$k-a z?ENIAQ>Y`M_=;?WK_AbiO26xd*9ptXAgFC}^J-9pVRIK@&sUn`nO#Df= z3GYY+*`zCld|JmTa?-}H#Vw{o<%x&Vu~vWW>B5N86>kEDoKN!J4kjj@5-8*2d~;NO z$D_uUK8`gg@8ad?U$S4<%-72=%}B3w^QrR4x$mdV_iJ6Ms#Pg1ut;I&4PKBJ0 zA)Q<=C8~&(6aiG5N{`diab-VM^9kbaIw@TT*G1)(ZUiOM@8YYG?NfRxmeNgA8AqYl zPg^?CDw~wusf1~4>aTYInl3dsa!8v;HHe4*=|htQ^Qtb%uBm(R6m)d$SyGxdCgmh@ zkR-DUrAfz$Qc7|?D0Hj71RA}*eOy7*2~U}D7H+IczA+N2JFbSxdN z+CUE#ep+trtM#3OH`Im^O~!VMIHfF=Pbq;GjUq@YzNjX0`EH}?(g9JOW0U@_>+{3o zIwpjxL-q)@+W~)4XHm~~KIG^^au*p01DM8=)A|^iqk2#qOY)P$>htNqknW|wZvI+! z9Zb1Y``KFfzh3{os1rJru!uJ8zrd?ykdN=?-ztBt{!&HxdanjUoz+h%A5`U!r>DCHn3ZNeNNHmADQ!v`y?J}kpKVy07*qoM6N<$f^B-RVE_OC literal 0 HcmV?d00001 -- 2.52.0