diff --git a/Content.Client/Dragon/DragonRiftComponent.cs b/Content.Client/Dragon/DragonRiftComponent.cs new file mode 100644 index 0000000000..6aa98a66c5 --- /dev/null +++ b/Content.Client/Dragon/DragonRiftComponent.cs @@ -0,0 +1,9 @@ +using Content.Shared.Dragon; + +namespace Content.Client.Dragon; + +[RegisterComponent] +public sealed class DragonRiftComponent : SharedDragonRiftComponent +{ + +} diff --git a/Content.Client/Dragon/DragonSystem.cs b/Content.Client/Dragon/DragonSystem.cs new file mode 100644 index 0000000000..d11fac8de7 --- /dev/null +++ b/Content.Client/Dragon/DragonSystem.cs @@ -0,0 +1,51 @@ +using Content.Shared.Dragon; +using Robust.Client.GameObjects; +using Robust.Shared.GameStates; + +namespace Content.Client.Dragon; + +public sealed class DragonSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnRiftHandleState); + } + + private void OnRiftHandleState(EntityUid uid, DragonRiftComponent component, ref ComponentHandleState args) + { + if (args.Current is not DragonRiftComponentState state) + return; + + if (component.State == state.State) return; + + component.State = state.State; + TryComp(uid, out var sprite); + TryComp(uid, out var light); + + if (sprite == null && light == null) + return; + + switch (state.State) + { + case DragonRiftState.Charging: + sprite?.LayerSetColor(0, Color.FromHex("#569fff")); + + if (light != null) + light.Color = Color.FromHex("#366db5"); + break; + case DragonRiftState.AlmostFinished: + sprite?.LayerSetColor(0, Color.FromHex("#cf4cff")); + + if (light != null) + light.Color = Color.FromHex("#9e2fc1"); + break; + case DragonRiftState.Finished: + sprite?.LayerSetColor(0, Color.FromHex("#edbc36")); + + if (light != null) + light.Color = Color.FromHex("#cbaf20"); + break; + } + } +} diff --git a/Content.Client/Sprite/RandomSpriteSystem.cs b/Content.Client/Sprite/RandomSpriteSystem.cs new file mode 100644 index 0000000000..a38d543b4a --- /dev/null +++ b/Content.Client/Sprite/RandomSpriteSystem.cs @@ -0,0 +1,58 @@ +using Content.Shared.Sprite; +using Robust.Client.GameObjects; +using Robust.Shared.GameStates; +using Robust.Shared.Reflection; + +namespace Content.Client.Sprite; + +public sealed class RandomSpriteSystem : SharedRandomSpriteSystem +{ + [Dependency] private readonly IReflectionManager _reflection = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnHandleState); + } + + private void OnHandleState(EntityUid uid, RandomSpriteComponent component, ref ComponentHandleState args) + { + if (args.Current is not RandomSpriteColorComponentState state) + return; + + if (state.Selected.Equals(component.Selected)) + return; + + component.Selected.Clear(); + component.Selected.EnsureCapacity(state.Selected.Count); + + foreach (var layer in state.Selected) + { + component.Selected.Add(layer.Key, layer.Value); + } + + UpdateAppearance(uid, component); + } + + private void UpdateAppearance(EntityUid uid, RandomSpriteComponent component, SpriteComponent? sprite = null) + { + if (!Resolve(uid, ref sprite, false)) + return; + + foreach (var layer in component.Selected) + { + object key; + if (_reflection.TryParseEnumReference(layer.Key, out var @enum)) + { + key = @enum; + } + else + { + key = layer.Key; + } + + sprite.LayerSetState(key, layer.Value.State); + sprite.LayerSetColor(key, layer.Value.Color ?? Color.White); + } + } +} diff --git a/Content.Server/Dragon/DragonComponent.cs b/Content.Server/Dragon/Components/DragonComponent.cs similarity index 66% rename from Content.Server/Dragon/DragonComponent.cs rename to Content.Server/Dragon/Components/DragonComponent.cs index 941a2ccf2f..789dc81147 100644 --- a/Content.Server/Dragon/DragonComponent.cs +++ b/Content.Server/Dragon/Components/DragonComponent.cs @@ -32,11 +32,42 @@ namespace Content.Server.Dragon [DataField("devourAction")] public EntityTargetAction? DevourAction; - [DataField("spawnActionId", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string SpawnActionId = "DragonSpawn"; + /// + /// If we have active rifts. + /// + [ViewVariables, DataField("rifts")] + public List Rifts = new(); - [DataField("spawnAction")] - public InstantAction? SpawnAction; + public bool Weakened => WeakenedAccumulator > 0f; + + /// + /// When any rift is destroyed how long is the dragon weakened for + /// + [ViewVariables(VVAccess.ReadWrite), DataField("weakenedDuration")] + public float WeakenedDuration = 120f; + + /// + /// Has a rift been destroyed and the dragon in a temporary weakened state? + /// + [ViewVariables(VVAccess.ReadWrite), DataField("weakenedAccumulator")] + public float WeakenedAccumulator = 0f; + + [ViewVariables(VVAccess.ReadWrite), DataField("riftAccumulator")] + public float RiftAccumulator = 0f; + + /// + /// Maximum time the dragon can go without spawning a rift before they die. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("maxAccumulator")] public float RiftMaxAccumulator = 300f; + + /// + /// Spawns a rift which can summon more mobs. + /// + [ViewVariables, DataField("spawnRiftAction")] + public InstantAction? SpawnRiftAction; + + [ViewVariables(VVAccess.ReadWrite), DataField("riftPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string RiftPrototype = "CarpRift"; /// /// The amount of time it takes to devour something @@ -48,14 +79,7 @@ namespace Content.Server.Dragon public float StructureDevourTime = 10f; [DataField("devourTime")] - public float DevourTime = 2f; - - [DataField("spawnCount")] public int SpawnsLeft = 2; - - [DataField("maxSpawnCount")] public int MaxSpawns = 2; - - [DataField("spawnProto", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? SpawnPrototype = "MobCarpDragon"; + public float DevourTime = 3f; [ViewVariables(VVAccess.ReadWrite), DataField("soundDeath")] public SoundSpecifier? SoundDeath = new SoundPathSpecifier("/Audio/Animals/space_dragon_roar.ogg"); @@ -76,7 +100,7 @@ namespace Content.Server.Dragon public SoundSpecifier? SoundRoar = new SoundPathSpecifier("/Audio/Animals/space_dragon_roar.ogg") { - Params = AudioParams.Default.WithVolume(-3f), + Params = AudioParams.Default.WithVolume(3f), }; public CancellationTokenSource? CancelToken; @@ -103,5 +127,5 @@ namespace Content.Server.Dragon public sealed class DragonDevourActionEvent : EntityTargetActionEvent {} - public sealed class DragonSpawnActionEvent : InstantActionEvent {} + public sealed class DragonSpawnRiftActionEvent : InstantActionEvent {} } diff --git a/Content.Server/Dragon/Components/DragonRiftComponent.cs b/Content.Server/Dragon/Components/DragonRiftComponent.cs new file mode 100644 index 0000000000..3a55709778 --- /dev/null +++ b/Content.Server/Dragon/Components/DragonRiftComponent.cs @@ -0,0 +1,40 @@ +using Content.Shared.Dragon; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.Dragon; + +[RegisterComponent] +public sealed class DragonRiftComponent : SharedDragonRiftComponent +{ + /// + /// Dragon that spawned this rift. + /// + [ViewVariables, DataField("dragon")] public EntityUid Dragon; + + /// + /// How long the rift has been active. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("accumulator")] + public float Accumulator = 0f; + + /// + /// The maximum amount we can accumulate before becoming impervious. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("maxAccumuluator")] public float MaxAccumulator = 300f; + + /// + /// Accumulation of the spawn timer. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("spawnAccumulator")] + public float SpawnAccumulator = 60f; + + /// + /// How long it takes for a new spawn to be added. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("spawnCooldown")] + public float SpawnCooldown = 60f; + + [ViewVariables(VVAccess.ReadWrite), DataField("spawn", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string SpawnPrototype = "MobCarpDragon"; +} diff --git a/Content.Server/Dragon/DragonSystem.Rule.cs b/Content.Server/Dragon/DragonSystem.Rule.cs new file mode 100644 index 0000000000..9fe7f49fba --- /dev/null +++ b/Content.Server/Dragon/DragonSystem.Rule.cs @@ -0,0 +1,67 @@ +using System.Linq; +using Content.Server.GameTicking; +using Content.Server.StationEvents.Components; +using Content.Shared.Dragon; +using Robust.Server.GameObjects; +using Robust.Shared.Random; + +namespace Content.Server.Dragon; + +public sealed partial class DragonSystem +{ + public override string Prototype => "Dragon"; + + private int RiftsMet(DragonComponent component) + { + var finished = 0; + + foreach (var rift in component.Rifts) + { + if (!TryComp(rift, out var drift) || + drift.State != DragonRiftState.Finished) + continue; + + finished++; + } + + return finished; + } + + public override void Started() + { + var spawnLocations = EntityManager.EntityQuery().ToList(); + + if (spawnLocations.Count == 0) + return; + + var location = _random.Pick(spawnLocations); + Spawn("MobDragon", location.Item2.MapPosition); + } + + public override void Ended() + { + return; + } + + private void OnRiftRoundEnd(RoundEndTextAppendEvent args) + { + if (!RuleAdded) + return; + + args.AddLine(Loc.GetString("dragon-round-end-summary")); + + foreach (var dragon in EntityQuery(true)) + { + var met = RiftsMet(dragon); + + if (TryComp(dragon.Owner, out var actor)) + { + args.AddLine(Loc.GetString("dragon-round-end-dragon-player", ("name", dragon.Owner), ("rifts", met), ("player", actor.PlayerSession))); + } + else + { + args.AddLine(Loc.GetString("dragon-round-end-dragon", ("name", dragon.Owner), ("rifts", met))); + } + } + } +} diff --git a/Content.Server/Dragon/DragonSystem.cs b/Content.Server/Dragon/DragonSystem.cs index 161f171f21..5adb70ec6c 100644 --- a/Content.Server/Dragon/DragonSystem.cs +++ b/Content.Server/Dragon/DragonSystem.cs @@ -9,15 +9,27 @@ using Content.Shared.MobState.Components; using Robust.Shared.Containers; using Robust.Shared.Player; using System.Threading; +using Content.Server.Chat.Systems; +using Content.Server.GameTicking; +using Content.Server.GameTicking.Rules; +using Content.Shared.Damage; +using Content.Shared.Dragon; +using Content.Shared.Examine; +using Content.Shared.Movement.Systems; +using Robust.Shared.GameStates; +using Robust.Shared.Random; namespace Content.Server.Dragon { - public sealed class DragonSystem : EntitySystem + public sealed partial class DragonSystem : GameRuleSystem { + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; + [Dependency] private readonly MovementSpeedModifierSystem _movement = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; @@ -26,13 +38,200 @@ namespace Content.Server.Dragon base.Initialize(); SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnDragonDevourComplete); SubscribeLocalEvent(OnDevourAction); - SubscribeLocalEvent(OnDragonSpawnAction); + SubscribeLocalEvent(OnDragonRift); + SubscribeLocalEvent(OnDragonMove); SubscribeLocalEvent(OnDragonStructureDevourComplete); SubscribeLocalEvent(OnDragonDevourCancelled); SubscribeLocalEvent(OnMobStateChanged); + + SubscribeLocalEvent(OnRiftShutdown); + SubscribeLocalEvent(OnRiftGetState); + SubscribeLocalEvent(OnAnchorChange); + SubscribeLocalEvent(OnRiftExamined); + + SubscribeLocalEvent(OnRiftRoundEnd); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + foreach (var comp in EntityQuery()) + { + if (comp.WeakenedAccumulator > 0f) + { + comp.WeakenedAccumulator -= frameTime; + + // No longer weakened. + if (comp.WeakenedAccumulator < 0f) + { + comp.WeakenedAccumulator = 0f; + _movement.RefreshMovementSpeedModifiers(comp.Owner); + } + } + + // At max rifts + if (comp.Rifts.Count >= 3) + { + continue; + } + + // If there's an active rift don't accumulate. + if (comp.Rifts.Count > 0) + { + var lastRift = comp.Rifts[^1]; + + if (TryComp(lastRift, out var rift) && rift.State != DragonRiftState.Finished) + { + comp.RiftAccumulator = 0f; + continue; + } + } + + comp.RiftAccumulator += frameTime; + + // Delete it, naughty dragon! + if (comp.RiftAccumulator >= comp.RiftMaxAccumulator) + { + Roar(comp); + QueueDel(comp.Owner); + } + } + + foreach (var comp in EntityQuery()) + { + if (comp.State != DragonRiftState.Finished && comp.Accumulator >= comp.MaxAccumulator) + { + // TODO: When we get autocall you can buff if the rift finishes / 3 rifts are up + // for now they just keep 3 rifts up. + + comp.Accumulator = comp.MaxAccumulator; + RemComp(comp.Owner); + comp.State = DragonRiftState.Finished; + Dirty(comp); + } + else + { + comp.Accumulator += frameTime; + } + + comp.SpawnAccumulator += frameTime; + + if (comp.State < DragonRiftState.AlmostFinished && comp.SpawnAccumulator > comp.MaxAccumulator / 2f) + { + comp.State = DragonRiftState.AlmostFinished; + Dirty(comp); + var location = Transform(comp.Owner).LocalPosition; + + _chat.DispatchGlobalAnnouncement(Loc.GetString("carp-rift-warning", ("location", location)), playSound: false, colorOverride: Color.Red); + _audioSystem.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast()); + } + + if (comp.SpawnAccumulator > comp.SpawnCooldown) + { + comp.SpawnAccumulator -= comp.SpawnCooldown; + Spawn(comp.SpawnPrototype, Transform(comp.Owner).MapPosition); + // TODO: When NPC refactor make it guard the rift. + } + } + } + + #region Rift + + private void OnRiftExamined(EntityUid uid, DragonRiftComponent component, ExaminedEvent args) + { + args.PushMarkup(Loc.GetString("carp-rift-examine", ("percentage", MathF.Round(component.Accumulator / component.MaxAccumulator * 100)))); + } + + private void OnAnchorChange(EntityUid uid, DragonRiftComponent component, ref AnchorStateChangedEvent args) + { + if (!args.Anchored && component.State == DragonRiftState.Charging) + { + QueueDel(uid); + } + } + + private void OnRiftShutdown(EntityUid uid, DragonRiftComponent component, ComponentShutdown args) + { + if (TryComp(component.Dragon, out var dragon) && !dragon.Weakened) + { + foreach (var rift in dragon.Rifts) + { + QueueDel(rift); + } + + dragon.Rifts.Clear(); + + // We can't predict the rift being destroyed anyway so no point adding weakened to shared. + dragon.WeakenedAccumulator = dragon.WeakenedDuration; + _movement.RefreshMovementSpeedModifiers(component.Dragon); + _popupSystem.PopupEntity(Loc.GetString("carp-rift-destroyed"), component.Dragon, Filter.Entities(component.Dragon)); + } + } + + private void OnRiftGetState(EntityUid uid, DragonRiftComponent component, ref ComponentGetState args) + { + args.State = new DragonRiftComponentState() + { + State = component.State + }; + } + + private void OnDragonMove(EntityUid uid, DragonComponent component, RefreshMovementSpeedModifiersEvent args) + { + if (component.Weakened) + { + args.ModifySpeed(0.5f, 0.5f); + } + } + + private void OnDragonRift(EntityUid uid, DragonComponent component, DragonSpawnRiftActionEvent args) + { + if (component.Weakened) + { + _popupSystem.PopupEntity(Loc.GetString("carp-rift-weakened"), uid, Filter.Entities(uid)); + return; + } + + if (component.Rifts.Count >= 3) + { + _popupSystem.PopupEntity(Loc.GetString("carp-rift-max"), uid, Filter.Entities(uid)); + return; + } + + if (component.Rifts.Count > 0 && TryComp(component.Rifts[^1], out var rift) && rift.State != DragonRiftState.Finished) + { + _popupSystem.PopupEntity(Loc.GetString("carp-rift-duplicate"), uid, Filter.Entities(uid)); + return; + } + + var xform = Transform(uid); + + // Have to be on a grid fam + if (xform.GridUid == null) + { + _popupSystem.PopupEntity(Loc.GetString("carp-rift-anchor"), uid, Filter.Entities(uid)); + return; + } + + var carpUid = Spawn(component.RiftPrototype, xform.MapPosition); + component.Rifts.Add(carpUid); + Comp(carpUid).Dragon = uid; + _audioSystem.Play("/Audio/Weapons/Guns/Gunshots/rocket_launcher.ogg", Filter.Pvs(carpUid, entityManager: EntityManager), carpUid); + } + + #endregion + + private void OnShutdown(EntityUid uid, DragonComponent component, ComponentShutdown args) + { + foreach (var rift in component.Rifts) + { + QueueDel(rift); + } } private void OnMobStateChanged(EntityUid uid, DragonComponent component, MobStateChangedEvent args) @@ -59,13 +258,7 @@ namespace Content.Server.Dragon var ichorInjection = new Solution(component.DevourChem, component.DevourHealRate); //Humanoid devours allow dragon to get eggs, corpses included - if (EntityManager.HasComponent(args.Target)) - { - // Add a spawn for a consumed humanoid - component.SpawnsLeft = Math.Min(component.SpawnsLeft + 1, component.MaxSpawns); - } - //Non-humanoid mobs can only heal dragon for half the normal amount, with no additional spawn tickets - else + if (!EntityManager.HasComponent(args.Target)) { ichorInjection.ScaleSolution(0.5f); } @@ -87,10 +280,14 @@ namespace Content.Server.Dragon _audioSystem.PlayPvs(component.SoundDevour, uid, component.SoundDevour.Params); } + private void Roar(DragonComponent component) + { + if (component.SoundRoar != null) + _audioSystem.Play(component.SoundRoar, Filter.Pvs(component.Owner, 4f, EntityManager), component.Owner, component.SoundRoar.Params); + } + private void OnStartup(EntityUid uid, DragonComponent component, ComponentStartup args) { - component.SpawnsLeft = Math.Min(component.SpawnsLeft, component.MaxSpawns); - //Dragon doesn't actually chew, since he sends targets right into his stomach. //I did it mom, I added ERP content into upstream. Legally! component.DragonStomach = _containerSystem.EnsureContainer(uid, "dragon_stomach"); @@ -98,11 +295,10 @@ namespace Content.Server.Dragon if (component.DevourAction != null) _actionsSystem.AddAction(uid, component.DevourAction, null); - if (component.SpawnAction != null) - _actionsSystem.AddAction(uid, component.SpawnAction, null); + if (component.SpawnRiftAction != null) + _actionsSystem.AddAction(uid, component.SpawnRiftAction, null); - if (component.SoundRoar != null) - _audioSystem.Play(component.SoundRoar, Filter.Pvs(uid, 4f, EntityManager), uid, component.SoundRoar.Params); + Roar(component); } /// @@ -117,7 +313,6 @@ namespace Content.Server.Dragon return; } - args.Handled = true; var target = args.Target; @@ -164,22 +359,6 @@ namespace Content.Server.Dragon }); } - private void OnDragonSpawnAction(EntityUid dragonuid, DragonComponent component, DragonSpawnActionEvent args) - { - if (component.SpawnPrototype == null) - return; - - // If dragon has spawns then add one. - if (component.SpawnsLeft > 0) - { - Spawn(component.SpawnPrototype, Transform(dragonuid).Coordinates); - component.SpawnsLeft--; - return; - } - - _popupSystem.PopupEntity(Loc.GetString("dragon-spawn-action-popup-message-fail-no-eggs"), dragonuid, Filter.Entities(dragonuid)); - } - private sealed class DragonDevourComplete : EntityEventArgs { public EntityUid User { get; } diff --git a/Content.Server/RatKing/RatKingSystem.cs b/Content.Server/RatKing/RatKingSystem.cs index 530012cd7e..81176e4221 100644 --- a/Content.Server/RatKing/RatKingSystem.cs +++ b/Content.Server/RatKing/RatKingSystem.cs @@ -15,8 +15,6 @@ namespace Content.Server.RatKing { [Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly ActionsSystem _action = default!; - [Dependency] private readonly DiseaseSystem _disease = default!; - [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly AtmosphereSystem _atmos = default!; [Dependency] private readonly TransformSystem _xform = default!; diff --git a/Content.Server/Sprite/Components/RandomSpriteColorComponent.cs b/Content.Server/Sprite/Components/RandomSpriteColorComponent.cs deleted file mode 100644 index 84c6590534..0000000000 --- a/Content.Server/Sprite/Components/RandomSpriteColorComponent.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Content.Server.Sprite.Components -{ - [RegisterComponent] - public sealed class RandomSpriteColorComponent : Component - { - // This should handle random states + colors for layers. - // Saame with RandomSpriteState - [DataField("selected")] public string? SelectedColor; - [DataField("state")] public string BaseState = "error"; - - [DataField("colors")] public readonly Dictionary Colors = new(); - } -} diff --git a/Content.Server/Sprite/Components/RandomSpriteStateComponent.cs b/Content.Server/Sprite/Components/RandomSpriteStateComponent.cs deleted file mode 100644 index c99637a09a..0000000000 --- a/Content.Server/Sprite/Components/RandomSpriteStateComponent.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Content.Server.Sprite.Components -{ - [RegisterComponent] - public sealed class RandomSpriteStateComponent : Component - { - [DataField("spriteStates")] public List? SpriteStates; - - [DataField("spriteLayer")] public int SpriteLayer; - } -} diff --git a/Content.Server/Sprite/RandomSpriteSystem.cs b/Content.Server/Sprite/RandomSpriteSystem.cs index 45e0619ac3..78ac695258 100644 --- a/Content.Server/Sprite/RandomSpriteSystem.cs +++ b/Content.Server/Sprite/RandomSpriteSystem.cs @@ -1,46 +1,53 @@ -using Content.Server.Sprite.Components; -using Content.Shared.Random.Helpers; -using Robust.Server.GameObjects; +using System.Linq; +using Content.Shared.Decals; +using Content.Shared.Sprite; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Server.Sprite; -public sealed class RandomSpriteSystem: EntitySystem +public sealed class RandomSpriteSystem: SharedRandomSpriteSystem { + [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IRobustRandom _random = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnSpriteColorStartup); - SubscribeLocalEvent(OnSpriteColorMapInit); - - SubscribeLocalEvent(OnSpriteStateMapInit); + SubscribeLocalEvent(OnGetState); + SubscribeLocalEvent(OnMapInit); } - private void OnSpriteColorStartup(EntityUid uid, RandomSpriteColorComponent component, ComponentStartup args) + private void OnMapInit(EntityUid uid, RandomSpriteComponent component, MapInitEvent args) { - UpdateColor(component); + if (component.Selected.Count > 0) + return; + + if (component.Available.Count == 0) + return; + + var group = _random.Pick(component.Available); + component.Selected.EnsureCapacity(group.Count); + + foreach (var layer in group) + { + Color? color = null; + + if (!string.IsNullOrEmpty(layer.Value.Color)) + color = _random.Pick(_prototype.Index(layer.Value.Color).Colors.Values); + + component.Selected.Add(layer.Key, (layer.Value.State, color)); + } + + Dirty(component); } - private void OnSpriteColorMapInit(EntityUid uid, RandomSpriteColorComponent component, MapInitEvent args) + private void OnGetState(EntityUid uid, RandomSpriteComponent component, ref ComponentGetState args) { - component.SelectedColor = _random.Pick(component.Colors.Keys); - UpdateColor(component); - } - - private void OnSpriteStateMapInit(EntityUid uid, RandomSpriteStateComponent component, MapInitEvent args) - { - if (component.SpriteStates == null) return; - if (!TryComp(uid, out var spriteComponent)) return; - spriteComponent.LayerSetState(component.SpriteLayer, _random.Pick(component.SpriteStates)); - } - - private void UpdateColor(RandomSpriteColorComponent component) - { - if (!TryComp(component.Owner, out var spriteComponent) || component.SelectedColor == null) return; - - spriteComponent.LayerSetState(0, component.BaseState); - spriteComponent.LayerSetColor(0, component.Colors[component.SelectedColor]); + args.State = new RandomSpriteColorComponentState() + { + Selected = component.Selected, + }; } } diff --git a/Content.Shared/Dragon/DragonRiftComponentState.cs b/Content.Shared/Dragon/DragonRiftComponentState.cs new file mode 100644 index 0000000000..e301add486 --- /dev/null +++ b/Content.Shared/Dragon/DragonRiftComponentState.cs @@ -0,0 +1,9 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.Dragon; + +[Serializable, NetSerializable] +public sealed class DragonRiftComponentState : ComponentState +{ + public DragonRiftState State; +} diff --git a/Content.Shared/Dragon/SharedDragonRiftComponent.cs b/Content.Shared/Dragon/SharedDragonRiftComponent.cs new file mode 100644 index 0000000000..702e1d0667 --- /dev/null +++ b/Content.Shared/Dragon/SharedDragonRiftComponent.cs @@ -0,0 +1,19 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Dragon; + +[NetworkedComponent] +public abstract class SharedDragonRiftComponent : Component +{ + [ViewVariables, DataField("state")] + public DragonRiftState State = DragonRiftState.Charging; +} + +[Serializable, NetSerializable] +public enum DragonRiftState : byte +{ + Charging, + AlmostFinished, + Finished, +} diff --git a/Content.Shared/Movement/Components/MovementAlwaysTouchingComponent.cs b/Content.Shared/Movement/Components/MovementAlwaysTouchingComponent.cs new file mode 100644 index 0000000000..97470c19de --- /dev/null +++ b/Content.Shared/Movement/Components/MovementAlwaysTouchingComponent.cs @@ -0,0 +1,13 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Movement.Components; + +/// +/// Is this entity always considered to be touching a wall? +/// i.e. when weightless they're floaty but still have free movement. +/// +[RegisterComponent, NetworkedComponent] +public sealed class MovementAlwaysTouchingComponent : Component +{ + +} diff --git a/Content.Shared/Movement/Components/MovementIgnoreGravityComponent.cs b/Content.Shared/Movement/Components/MovementIgnoreGravityComponent.cs index 5761a7f929..0e28257d3b 100644 --- a/Content.Shared/Movement/Components/MovementIgnoreGravityComponent.cs +++ b/Content.Shared/Movement/Components/MovementIgnoreGravityComponent.cs @@ -8,6 +8,9 @@ using Robust.Shared.Serialization; namespace Content.Shared.Movement.Components { + /// + /// Ignores gravity entirely. + /// [RegisterComponent, NetworkedComponent] public sealed class MovementIgnoreGravityComponent : Component { @@ -17,7 +20,6 @@ namespace Content.Shared.Movement.Components [DataField("gravityState")] public bool Weightless = false; } - [NetSerializable, Serializable] public sealed class MovementIgnoreGravityComponentState : ComponentState { diff --git a/Content.Shared/Movement/Components/MovementSpeedModifierComponent.cs b/Content.Shared/Movement/Components/MovementSpeedModifierComponent.cs index b84922678b..e55c45bba5 100644 --- a/Content.Shared/Movement/Components/MovementSpeedModifierComponent.cs +++ b/Content.Shared/Movement/Components/MovementSpeedModifierComponent.cs @@ -56,55 +56,55 @@ namespace Content.Shared.Movement.Components /// /// Minimum speed a mob has to be moving before applying movement friction. /// - [DataField("minimumFrictionSpeed")] + [ViewVariables(VVAccess.ReadWrite), DataField("minimumFrictionSpeed")] public float MinimumFrictionSpeed = DefaultMinimumFrictionSpeed; /// /// The negative velocity applied for friction when weightless and providing inputs. /// - [DataField("weightlessFriction")] + [ViewVariables(VVAccess.ReadWrite), DataField("weightlessFriction")] public float WeightlessFriction = DefaultWeightlessFriction; /// /// The negative velocity applied for friction when weightless and not providing inputs. /// This is essentially how much their speed decreases per second. /// - [DataField("weightlessFrictionNoInput")] + [ViewVariables(VVAccess.ReadWrite), DataField("weightlessFrictionNoInput")] public float WeightlessFrictionNoInput = DefaultWeightlessFrictionNoInput; /// /// The movement speed modifier applied to a mob's total input velocity when weightless. /// - [DataField("weightlessModifier")] + [ViewVariables(VVAccess.ReadWrite), DataField("weightlessModifier")] public float WeightlessModifier = DefaultWeightlessModifier; /// /// The acceleration applied to mobs when moving and weightless. /// - [DataField("weightlessAcceleration")] + [ViewVariables(VVAccess.ReadWrite), DataField("weightlessAcceleration")] public float WeightlessAcceleration = DefaultWeightlessAcceleration; /// /// The acceleration applied to mobs when moving. /// - [DataField("acceleration")] + [ViewVariables(VVAccess.ReadWrite), DataField("acceleration")] public float Acceleration = DefaultAcceleration; /// /// The negative velocity applied for friction. /// - [DataField("friction")] + [ViewVariables(VVAccess.ReadWrite), DataField("friction")] public float Friction = DefaultFriction; /// /// The negative velocity applied for friction. /// - [DataField("frictionNoInput")] public float? FrictionNoInput = null; + [ViewVariables(VVAccess.ReadWrite), DataField("frictionNoInput")] public float? FrictionNoInput = null; - [DataField("baseWalkSpeed")] + [ViewVariables(VVAccess.ReadWrite), DataField("baseWalkSpeed")] public float BaseWalkSpeed { get; set; } = DefaultBaseWalkSpeed; - [DataField("baseSprintSpeed")] + [ViewVariables(VVAccess.ReadWrite), DataField("baseSprintSpeed")] public float BaseSprintSpeed { get; set; } = DefaultBaseSprintSpeed; [ViewVariables] diff --git a/Content.Shared/Movement/Systems/MovementIgnoreGravitySystem.cs b/Content.Shared/Movement/Systems/MovementIgnoreGravitySystem.cs index 4ea0e08b97..52cdf219e5 100644 --- a/Content.Shared/Movement/Systems/MovementIgnoreGravitySystem.cs +++ b/Content.Shared/Movement/Systems/MovementIgnoreGravitySystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Movement.Components; +using Content.Shared.Movement.Events; using Robust.Shared.GameStates; namespace Content.Shared.Movement.Systems; @@ -9,6 +10,12 @@ public sealed class MovementIgnoreGravitySystem : EntitySystem { SubscribeLocalEvent(GetState); SubscribeLocalEvent(HandleState); + SubscribeLocalEvent(OnWeightless); + } + + private void OnWeightless(EntityUid uid, MovementAlwaysTouchingComponent component, ref CanWeightlessMoveEvent args) + { + args.CanMove = true; } private void HandleState(EntityUid uid, MovementIgnoreGravityComponent component, ref ComponentHandleState args) diff --git a/Content.Shared/Sprite/RandomSpriteComponent.cs b/Content.Shared/Sprite/RandomSpriteComponent.cs new file mode 100644 index 0000000000..d511b2b123 --- /dev/null +++ b/Content.Shared/Sprite/RandomSpriteComponent.cs @@ -0,0 +1,20 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Sprite; + +[RegisterComponent, NetworkedComponent] +public sealed class RandomSpriteComponent : Component +{ + /// + /// Available colors based on group, parsed layer enum, state, and color. + /// Stored as a list so we can have groups of random sprites (e.g. tech_base + tech_flare for holoparasite) + /// + [ViewVariables(VVAccess.ReadWrite), DataField("available")] + public List> Available = new(); + + /// + /// Selected colors + /// + [ViewVariables(VVAccess.ReadWrite), DataField("selected")] + public Dictionary Selected = new(); +} diff --git a/Content.Shared/Sprite/SharedRandomSpriteSystem.cs b/Content.Shared/Sprite/SharedRandomSpriteSystem.cs new file mode 100644 index 0000000000..4d9958093e --- /dev/null +++ b/Content.Shared/Sprite/SharedRandomSpriteSystem.cs @@ -0,0 +1,11 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.Sprite; + +public abstract class SharedRandomSpriteSystem : EntitySystem {} + +[Serializable, NetSerializable] +public sealed class RandomSpriteColorComponentState : ComponentState +{ + public Dictionary Selected = default!; +} diff --git a/Resources/Audio/Weapons/Guns/Gunshots/license.txt b/Resources/Audio/Weapons/Guns/Gunshots/license.txt index 238c8056c4..6487f71076 100644 --- a/Resources/Audio/Weapons/Guns/Gunshots/license.txt +++ b/Resources/Audio/Weapons/Guns/Gunshots/license.txt @@ -1,5 +1,5 @@ atreides.ogg, c-20r.ogg, flaregun.ogg, mateba.ogg, minigun.ogg, mk58.ogg were taken from https://gitlab.com/cmdevs/colonial-warfare/-/tree/32cb5892413243cc74bb2d11df8e3085f8ef1164/sound/weapons They are licensed under CC-BY-SA 3.0 -taser2.ogg and kinetic_accel.ogg were taken from https://github.com/tgstation/tgstation/tree/88d7dbfc105fbf40284d7b7c4587f8d23c0ac3ac +rocket_launcher.ogg and taser2.ogg and kinetic_accel.ogg were taken from https://github.com/tgstation/tgstation/tree/88d7dbfc105fbf40284d7b7c4587f8d23c0ac3ac It is licensed under CC-BY-SA 3.0 \ No newline at end of file diff --git a/Resources/Audio/Weapons/Guns/Gunshots/rocket_launcher.ogg b/Resources/Audio/Weapons/Guns/Gunshots/rocket_launcher.ogg new file mode 100644 index 0000000000..e671fbff15 Binary files /dev/null and b/Resources/Audio/Weapons/Guns/Gunshots/rocket_launcher.ogg differ diff --git a/Resources/Locale/en-US/actions/actions/dragon.ftl b/Resources/Locale/en-US/actions/actions/dragon.ftl index eaa98259c6..09d75c6290 100644 --- a/Resources/Locale/en-US/actions/actions/dragon.ftl +++ b/Resources/Locale/en-US/actions/actions/dragon.ftl @@ -2,7 +2,7 @@ devour-action-popup-message-structure = Your jaws dig into thick material.. devour-action-popup-message-fail-target-not-valid = That doesn't look particularly edible. devour-action-popup-message-fail-target-alive = You can't consume creatures that are alive! -dragon-spawn-action-popup-message-fail-no-eggs = You don't have the stamina to create a carp! +dragon-spawn-action-popup-message-fail-no-eggs = You don't have the stamina to do that! action-name-devour = [color=red]Devour[/color] @@ -10,3 +10,17 @@ action-description-devour = Attempt to break a structure with your jaws or swall action-name-carp-summon = Summon carp action-description-carp-summon = Summon a carp to aid you at seizing the station! + +# Rifts +carp-rift-warning = A rift is causing an unnaturally large energy flux at {$location}. Stop it at all costs! +carp-rift-duplicate = Cannot have 2 charging rifts at the same time! +carp-rift-examine = It is [color=yellow]{$percentage}%[/color] charged! +carp-rift-max = You have reached your maximum amount of rifts +carp-rift-anchor = Rifts require a stable surface to spawn. +carp-rift-weakened = You are unable to summon more rifts in your weakened state. +carp-rift-destroyed = A rift has been destroyed! You are now weakened temporarily. + +# Round end +dragon-round-end-summary = The dragons were: +dragon-round-end-dragon = {$name} with {$count} rifts +dragon-round-end-dragon-player = {$name} ({$player}) with {$count} rifts diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 68d6e0a9cc..32bea0c94a 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -307,6 +307,7 @@ baseSprintSpeed : 6 - type: Sprite drawdepth: Mobs + netsync: false layers: - map: ["enum.DamageStateVisualLayers.Base"] state: butterfly @@ -327,16 +328,10 @@ 0: Alive 5: Critical 10: Dead - - type: RandomSpriteColor - state: butterfly - colors: - blue: "#1861d5" - red: "#951710" - pink: "#d5188d" - brown: "#a05212" - green: "#0e7f1b" - cyan: "#18a2d5" - yellow: "#d58c18" + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + butterfly: Rainbow - type: Appearance - type: DamageStateVisuals states: diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/bear.yml b/Resources/Prototypes/Entities/Mobs/NPCs/bear.yml index 5624ba715d..421cb7d380 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/bear.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/bear.yml @@ -29,7 +29,7 @@ - MobMask layer: - MobLayer - - type: MovementIgnoreGravity + - type: MovementAlwaysTouching - type: MobState thresholds: 0: Alive diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml index 78738555a0..1445bdb0c2 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml @@ -1,77 +1,95 @@ - type: entity name: space carp - id: MobCarp + id: BaseMobCarp parent: SimpleSpaceMobBase description: It's a space carp. + abstract: true components: - - type: InputMover - - type: MobMover - - type: UtilityNPC - behaviorSets: - - Idle - - UnarmedAttackHostiles - - type: AiFactionTag - factions: - - SimpleHostile - - type: Sprite - drawdepth: Mobs - layers: - - map: ["enum.DamageStateVisualLayers.Base"] - state: alive - sprite: Mobs/Aliens/Carps/space.rsi - - type: CombatMode - disarmAction: - enabled: false - autoPopulate: false - name: action-name-disarm - - type: Physics - - type: Fixtures - fixtures: - - shape: - !type:PhysShapeCircle - radius: 0.40 - mass: 40 - mask: - - MobMask - layer: - - MobLayer - - type: MobState - thresholds: - 0: Alive - 50: Critical - 100: Dead - - type: MovementIgnoreGravity - - type: Appearance - - type: DamageStateVisuals - states: - Alive: - Base: alive - Critical: - Base: crit - Dead: - Base: dead - - type: Butcherable - spawned: - - id: FoodMeatFish - amount: 2 - - type: MeleeWeapon - range: 1.5 - arcwidth: 0 - arc: bite - hitSound: - path: /Audio/Effects/bite.ogg - damage: - types: - Piercing: 5 - Slash: 10 - - type: ReplacementAccent - accent: genericAggressive - - type: TypingIndicator - proto: alien - - type: NoSlip - - type: Tag - tags: - - Carp + - type: InputMover + - type: MobMover + - type: UtilityNPC + behaviorSets: + - Idle + - UnarmedAttackHostiles + - type: AiFactionTag + factions: + - SimpleHostile + - type: Sprite + drawdepth: Mobs + netsync: false + layers: + - map: [ "enum.DamageStateVisualLayers.Base" ] + state: base + sprite: Mobs/Aliens/Carps/space.rsi + - map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ] + state: mouth + sprite: Mobs/Aliens/Carps/space.rsi + shader: unshaded + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + base: Rainbow + enum.DamageStateVisualLayers.BaseUnshaded: + mouth: "" + - type: CombatMode + disarmAction: + enabled: false + autoPopulate: false + name: action-name-disarm + - type: Physics + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.40 + mass: 40 + mask: + - MobMask + layer: + - MobLayer + - type: MobState + thresholds: + 0: Alive + 50: Critical + 100: Dead + - type: MovementAlwaysTouching + - type: Appearance + - type: DamageStateVisuals + states: + Alive: + Base: base + BaseUnshaded: mouth + Dead: + Base: base_dead + BaseUnshaded: dead_mouth + - type: Butcherable + spawned: + - id: FoodMeatFish + amount: 2 + - type: MeleeWeapon + range: 1.5 + arcwidth: 0 + arc: bite + hitSound: + path: /Audio/Effects/bite.ogg + damage: + types: + Piercing: 5 + Slash: 10 + - type: TypingIndicator + proto: alien + - type: NoSlip + - type: Tag + tags: + - Carp + - DoorBumpOpener + +- type: entity + parent: BaseMobCarp + id: MobCarp + components: + - type: ReplacementAccent + accent: genericAggressive - type: entity name: magicarp @@ -79,14 +97,14 @@ id: MobCarpMagic description: Looks like some kind of fish. Might be magical. components: - - type: Sprite - drawdepth: Mobs - layers: - - map: ["enum.DamageStateVisualLayers.Base"] - state: alive - sprite: Mobs/Aliens/Carps/magic.rsi - - type: TypingIndicator - proto: guardian + - type: Sprite + drawdepth: Mobs + layers: + - map: [ "enum.DamageStateVisualLayers.Base" ] + state: base + sprite: Mobs/Aliens/Carps/magic.rsi + - type: TypingIndicator + proto: guardian - type: entity name: holocarp @@ -94,37 +112,37 @@ id: MobCarpHolo description: Carp made out of holographic energies. Sadly for you, it is very much real. components: - - type: Sprite - drawdepth: Mobs - layers: - - map: ["enum.DamageStateVisualLayers.Base"] - state: alive - sprite: Mobs/Aliens/Carps/holo.rsi - - type: Physics - - type: Fixtures - fixtures: - - shape: - !type:PhysShapeCircle - radius: 0.40 - mass: 5 - mask: - - MobMask - layer: - - Opaque - - type: TypingIndicator - proto: robot + - type: Sprite + drawdepth: Mobs + layers: + - map: [ "enum.DamageStateVisualLayers.Base" ] + state: base + sprite: Mobs/Aliens/Carps/holo.rsi + - type: Physics + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.40 + mass: 5 + mask: + - MobMask + layer: + - Opaque + - type: TypingIndicator + proto: robot - type: entity id: MobCarpSalvage parent: MobCarp suffix: "Salvage Ruleset" components: - - type: GhostTakeoverAvailable - prob: 0.33 - name: space carp on salvage wreck - description: | - Defend the loot inside the salvage wreck! - - type: SalvageMobRestrictions + - type: GhostTakeoverAvailable + prob: 0.33 + name: space carp on salvage wreck + description: | + Defend the loot inside the salvage wreck! + - type: SalvageMobRestrictions - type: entity name: space carp @@ -132,8 +150,7 @@ suffix: DragonBrood parent: MobCarp components: - - type: GhostTakeoverAvailable - makeSentient: true - name: Sentient Carp - description: Help the dragon flood the station with carps! - + - type: GhostTakeoverAvailable + makeSentient: true + name: Sentient Carp + description: Help the dragon flood the station with carps! diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml b/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml index 8985d204bb..52a4b9d5a5 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml @@ -38,7 +38,7 @@ thresholds: 0: Alive 15: Dead - - type: MovementIgnoreGravity + - type: MovementAlwaysTouching - type: Appearance - type: DamageStateVisuals states: diff --git a/Resources/Prototypes/Entities/Mobs/Player/dragon.yml b/Resources/Prototypes/Entities/Mobs/Player/dragon.yml index f743205475..5a964b8269 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/dragon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/dragon.yml @@ -5,106 +5,112 @@ suffix: description: A flying leviathan, loosely related to space carps. components: - - type: GhostTakeoverAvailable - makeSentient: true - name: Space dragon! - description: Crash, roast, flood the station with carps! - - type: Speech - - type: CombatMode - disarmAction: - enabled: false - autoPopulate: false - name: action-name-disarm - - type: MobMover - - type: InputMover - - type: MovementSpeedModifier - baseWalkSpeed : 5 - baseSprintSpeed : 5 - - type: Sprite - sprite: Mobs/Aliens/Carps/dragon.rsi - noRot: true - # TODO: Randomise colors when RandomSpriteColor isn't poopoo - layers: - - map: [ "enum.DamageStateVisualLayers.Base" ] - state: alive - - map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ] - state: alive-unshaded - shader: unshaded - - type: Appearance - - type: DamageStateVisuals - states: - Alive: - Base: alive - BaseUnshaded: alive-unshaded - Critical: - Base: crit - Dead: - Base: dead - BaseUnshaded: dead-unshaded - - type: Physics - bodyType: KinematicController - - type: Fixtures - fixtures: - - shape: - !type:PhysShapeCircle - radius: 0.40 - mass: 50 - mask: - - FlyingMobMask - layer: - - FlyingMobLayer - - type: MobState - thresholds: - 0: Alive - 450: Critical - 500: Dead - - type: Metabolizer - solutionOnBody: false - updateFrequency: 0.25 - metabolizerTypes: [Dragon] - groups: - - id: Medicine - - id: Poison - - type: MovementIgnoreGravity - - type: NoSlip - - type: Butcherable - spawned: - - id: FoodMeatDragon - amount: 2 - - type: InteractionPopup - successChance: 0.25 # It's no goose, but you better smell like carp. - interactSuccessString: petting-success-dragon - interactFailureString: petting-failure-dragon - interactFailureSound: - path: /Audio/Animals/space_dragon_roar.ogg - soundPerceivedByOthers: false # A 75% chance for a loud roar would get old fast. - - type: MeleeWeapon - hitSound: - path: /Audio/Effects/bite.ogg - damage: - types: - Piercing: 15 - Slash: 15 - - type: Dragon - spawnsLeft: 2 - spawnsProto: MobCarpDragon - devourAction: - event: !type:DragonDevourActionEvent - icon: Interface/Actions/devour.png - name: action-name-devour - description: action-description-devour - devourChemical: Ichor - devourHealRate: 15.0 - whitelist: - components: - - MobState - - Door - tags: - - Wall - spawnAction: - event: !type:DragonSpawnActionEvent - icon: Interface/Actions/carp_summon.png - name: action-name-carp-summon - description: action-description-carp-summon - useDelay: 5 - + - type: GhostTakeoverAvailable + makeSentient: true + name: Space dragon + description: Call in 3 carp rifts and take over this quadrant! You have only 5 minutes in between each rift before you will disappear. + - type: Speech + - type: CombatMode + disarmAction: + enabled: false + autoPopulate: false + name: action-name-disarm + - type: MobMover + - type: InputMover + - type: MovementSpeedModifier + baseWalkSpeed: 3 + baseSprintSpeed: 5 + weightlessModifier: 1.5 + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + alive: Rainbow + - type: Sprite + sprite: Mobs/Aliens/Carps/dragon.rsi + netsync: false + noRot: true + layers: + - map: [ "enum.DamageStateVisualLayers.Base" ] + state: alive + - map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ] + state: alive-unshaded + shader: unshaded + - type: Appearance + - type: DamageStateVisuals + states: + Alive: + Base: alive + BaseUnshaded: alive-unshaded + Critical: + Base: crit + Dead: + Base: dead + BaseUnshaded: dead-unshaded + - type: Physics + bodyType: KinematicController + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.40 + mass: 50 + mask: + - FlyingMobMask + layer: + - FlyingMobLayer + - type: MobState + thresholds: + 0: Alive + 450: Critical + 500: Dead + - type: Metabolizer + solutionOnBody: false + updateFrequency: 0.25 + metabolizerTypes: [ Dragon ] + groups: + - id: Medicine + - id: Poison + - type: MovementAlwaysTouching + - type: NoSlip + - type: Butcherable + spawned: + - id: FoodMeatDragon + amount: 2 + - type: InteractionPopup + successChance: 0.25 # It's no goose, but you better smell like carp. + interactSuccessString: petting-success-dragon + interactFailureString: petting-failure-dragon + interactFailureSound: + path: /Audio/Animals/space_dragon_roar.ogg + soundPerceivedByOthers: false # A 75% chance for a loud roar would get old fast. + - type: MeleeWeapon + hitSound: + path: /Audio/Effects/bite.ogg + damage: + types: + Piercing: 15 + Slash: 15 + - type: Dragon + spawnsLeft: 2 + spawnsProto: MobCarpDragon + devourAction: + event: !type:DragonDevourActionEvent + icon: Interface/Actions/devour.png + name: action-name-devour + description: action-description-devour + devourChemical: Ichor + devourHealRate: 15.0 + whitelist: + components: + - MobState + - Door + tags: + - Wall + spawnRiftAction: + event: !type:DragonSpawnRiftActionEvent + icon: + sprite: Interface/Actions/carp_rift.rsi + state: icon + name: action-name-carp-rift + description: action-description-carp-rift + useDelay: 1 diff --git a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml index e43924f917..db46da8d3e 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml @@ -5,78 +5,94 @@ id: MobGuardianBase description: guardian components: - - type: GhostTakeoverAvailable - makeSentient: true - name: Guardian - description: Listen to your owner. Don't tank damage. Punch people hard. - - type: Input - context: "human" - - type: MobMover - - type: InputMover - - type: MovementSpeedModifier - baseWalkSpeed : 7 - baseSprintSpeed : 7 - - type: DamageOnHighSpeedImpact - damage: - types: - Blunt: 5 - soundHit: - path: /Audio/Effects/hit_kick.ogg - # TODO: Randomise sprites and randomise the layer color - - type: Sprite - drawdepth: Mobs - sprite: Mobs/Aliens/Guardians/guardians.rsi - layers: - - state: tech_base - - state: tech_flare - color: "#40a7d7" - shader: unshaded - noRot: true - - type: Clickable - - type: InteractionOutline - - type: Physics - bodyType: KinematicController - - type: Fixtures - fixtures: - - shape: - !type:PhysShapeCircle - radius: 0.35 - mass: 10 - mask: - - FlyingMobMask - layer: - - FlyingMobLayer - - type: Damageable - damageContainer: Biological - - type: MobState - thresholds: - 0: Alive - - type: HeatResistance - - type: CombatMode - - type: Internals - - type: Examiner - - type: Speech - - type: TypingIndicator - proto: guardian - - type: Pullable - - type: MeleeWeapon - range: 2 - arcwidth: 30 - arc: fist - cooldownTime: 0.7 - arcCooldownTime: 0.7 - damage: - types: - Blunt: 22 - - type: Actions - - type: Guardian - - type: InteractionPopup - interactSuccessString: petting-success-holo - interactFailureString: petting-failure-holo - successChance: 0.7 - - type: Tag - tags: - - CannotSuicide + - type: GhostTakeoverAvailable + makeSentient: true + name: Guardian + description: Listen to your owner. Don't tank damage. Punch people hard. + - type: Input + context: "human" + - type: MobMover + - type: InputMover + - type: MovementSpeedModifier + baseWalkSpeed: 4 + baseSprintSpeed: 5.5 + - type: DamageOnHighSpeedImpact + damage: + types: + Blunt: 5 + soundHit: + path: /Audio/Effects/hit_kick.ogg + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + magic_base: "" + enum.DamageStateVisualLayers.BaseUnshaded: + magic_flare: Sixteen + - enum.DamageStateVisualLayers.Base: + miner_base: "" + enum.DamageStateVisualLayers.BaseUnshaded: + miner_flare: Sixteen + - enum.DamageStateVisualLayers.Base: + tech_base: "" + enum.DamageStateVisualLayers.BaseUnshaded: + tech_flare: Sixteen + - type: Sprite + drawdepth: Mobs + sprite: Mobs/Aliens/Guardians/guardians.rsi + netsync: false + layers: + - state: tech_base + map: [ "enum.DamageStateVisualLayers.Base" ] + - state: tech_flare + map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ] + color: "#40a7d7" + shader: unshaded + noRot: true + - type: Clickable + - type: InteractionOutline + - type: Physics + bodyType: KinematicController + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.35 + mass: 10 + mask: + - FlyingMobMask + layer: + - FlyingMobLayer + - type: Damageable + damageContainer: Biological + - type: MobState + thresholds: + 0: Alive + - type: HeatResistance + - type: CombatMode + - type: Internals + - type: Examiner + - type: Speech + - type: TypingIndicator + proto: guardian + - type: Pullable + - type: MeleeWeapon + range: 2 + arcwidth: 30 + arc: fist + cooldownTime: 0.7 + arcCooldownTime: 0.7 + damage: + types: + Blunt: 22 + - type: Actions + - type: Guardian + - type: InteractionPopup + interactSuccessString: petting-success-holo + interactFailureString: petting-failure-holo + successChance: 0.7 + - type: Tag + tags: + - CannotSuicide # From the uplink injector - type: entity @@ -85,20 +101,22 @@ parent: MobGuardianBase description: A mesmerising whirl of hard-light patterns weaves a marvelous, yet oddly familiar visage. It stands proud, tuning into its owner's life to sustain itself. components: - - type: GhostTakeoverAvailable - makeSentient: true - name: Holoparasite - description: Listen to your owner. Don't tank damage. Punch people hard. - - type: NameIdentifier - group: Holoparasite - - type: TypingIndicator - proto: holo - - type: Sprite - layers: - - state: tech_base - - state: tech_flare - color: "#40a7d7" - shader: unshaded + - type: GhostTakeoverAvailable + makeSentient: true + name: Holoparasite + description: Listen to your owner. Don't tank damage. Punch people hard. + - type: NameIdentifier + group: Holoparasite + - type: TypingIndicator + proto: holo + - type: Sprite + layers: + - state: tech_base + map: [ "enum.DamageStateVisualLayers.Base" ] + - state: tech_flare + map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ] + color: "#40a7d7" + shader: unshaded # From Wizard deck of cards - type: entity @@ -107,13 +125,19 @@ id: MobIfritGuardian description: A corrupted jinn, ripped from fitra to serve the wizard's petty needs. It stands wicked, tuning into it's owner's life to sustain itself. components: - - type: GhostTakeoverAvailable - makeSentient: true - name: Ifrit - description: Listen to your owner. Don't tank damage. Punch people hard. - - type: Sprite - layers: - - state: magic_base - - state: magic_flare - color: "#d14730" - shader: unshaded + - type: GhostTakeoverAvailable + makeSentient: true + name: Ifrit + description: Listen to your owner. Don't tank damage. Punch people hard. + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.BaseUnshaded: + magic_flare: Sixteen + - type: Sprite + layers: + - state: magic_base + map: [ "enum.DamageStateVisualLayers.Base" ] + - state: magic_flare + map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ] + color: "#40a7d7" + shader: unshaded diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/misc.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/misc.yml index 52b950ee5d..a800be6423 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/misc.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/misc.yml @@ -176,14 +176,20 @@ - Nugget - type: Sprite sprite: Objects/Consumable/Food/Baked/nuggets.rsi - state: tendie - netsync: true - - type: RandomSpriteState - spriteStates: - - tendie - - lizard - - star - - corgi + layers: + - state: tendie + map: [ "enum.DamageStateVisualLayers.Base" ] + netsync: false + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + tendie: "" + - enum.DamageStateVisualLayers.Base: + lizard: "" + - enum.DamageStateVisualLayers.Base: + star: "" + - enum.DamageStateVisualLayers.Base: + corgi: "" - type: SolutionContainerManager solutions: food: diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml index 4ed4efd412..844a6c81f2 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml @@ -126,8 +126,13 @@ components: - type: Sprite sprite: Objects/Consumable/Food/egg.rsi - state: icon - - type: RandomSpriteState - spriteStates: - - icon - - white + layers: + - state: icon + map: [ "enum.DamageStateVisualLayers.Base" ] + netsync: false + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + icon: "" + - enum.DamageStateVisualLayers.Base: + white: "" diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/frozen.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/frozen.yml index 57368e2f9c..3f98c656f0 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/frozen.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/frozen.yml @@ -237,11 +237,16 @@ components: - type: Sprite sprite: Objects/Consumable/Food/frozen.rsi - state: stick - - type: RandomSpriteState - spriteStates: - - stick - - stick2 + netsync: false + layers: + - state: stick + map: [ "enum.DamageStateVisualLayers.Base" ] + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + stick: "" + - enum.DamageStateVisualLayers.Base: + stick2: "" - type: Tag tags: - Trash diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml index 21fa3593c5..39a6f04413 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml @@ -87,12 +87,14 @@ tags: - Raw - type: Sprite - netsync: true + netsync: false state: bacon - - type: RandomSpriteState - spriteStates: - - bacon - - bacon2 + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + bacon: "" + - enum.DamageStateVisualLayers.Base: + bacon2: "" - type: SolutionContainerManager solutions: food: @@ -501,11 +503,13 @@ layers: - state: plate-meat - state: bacon-cooked - - type: RandomSpriteState - spriteLayer: 1 - spriteStates: - - bacon-cooked - - bacon2-cooked + map: [ "enum.DamageStateVisualLayers.Base" ] + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + bacon-cooked: "" + - enum.DamageStateVisualLayers.Base: + bacon2-cooked: "" - type: SolutionContainerManager solutions: food: @@ -608,12 +612,16 @@ - type: Food trash: FoodPlateSmall - type: Sprite - netsync: true - state: chicken-fried - - type: RandomSpriteState - spriteStates: - - chicken-fried - - chicken2-fried + netsync: false + layers: + - state: chicken-fried + map: [ "enum.DamageStateVisualLayers.Base" ] + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + chicken-fried: "" + - enum.DamageStateVisualLayers.Base: + chicken2-fried: "" - type: SolutionContainerManager solutions: food: diff --git a/Resources/Prototypes/Entities/Objects/Materials/shards.yml b/Resources/Prototypes/Entities/Objects/Materials/shards.yml index 801f62c2cd..719f4d9193 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/shards.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/shards.yml @@ -5,13 +5,19 @@ description: It's a shard of some unknown material. components: - type: Sprite - sprite: Objects/Materials/Shards/shard.rsi - state: shard1 - - type: RandomSpriteState - spriteStates: - - shard1 - - shard2 - - shard3 + layers: + - sprite: Objects/Materials/Shards/shard.rsi + state: shard1 + map: [ "enum.DamageStateVisualLayers.Base" ] + netsync: false + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + shard1: "" + - enum.DamageStateVisualLayers.Base: + shard2: "" + - enum.DamageStateVisualLayers.Base: + shard3: "" - type: ItemCooldown - type: MeleeWeapon damage: diff --git a/Resources/Prototypes/Entities/Objects/Misc/books.yml b/Resources/Prototypes/Entities/Objects/Misc/books.yml index 6de29605b2..04b21d846a 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/books.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/books.yml @@ -6,8 +6,10 @@ components: - type: Sprite sprite: Objects/Misc/books.rsi + netsync: false layers: - state: book0 + map: [ "enum.DamageStateVisualLayers.Base" ] - type: Paper - type: ActivatableUI key: enum.PaperUiKey.Key @@ -21,15 +23,23 @@ id: BookRandom suffix: random components: - - type: RandomSpriteState - spriteLayer: 0 - spriteStates: - - book0 - - book1 - - book2 - - book3 - - book4 - - book5 - - book6 - - book7 - - book8 + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + book0: "" + - enum.DamageStateVisualLayers.Base: + book1: "" + - enum.DamageStateVisualLayers.Base: + book2: "" + - enum.DamageStateVisualLayers.Base: + book3: "" + - enum.DamageStateVisualLayers.Base: + book4: "" + - enum.DamageStateVisualLayers.Base: + book5: "" + - enum.DamageStateVisualLayers.Base: + book6: "" + - enum.DamageStateVisualLayers.Base: + book7: "" + - enum.DamageStateVisualLayers.Base: + book8: "" diff --git a/Resources/Prototypes/Entities/Objects/Tools/lighters.yml b/Resources/Prototypes/Entities/Objects/Tools/lighters.yml index faa8aeb51c..7291c509fa 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/lighters.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/lighters.yml @@ -4,21 +4,34 @@ id: Lighter description: "A simple plastic cigarette lighter." components: - - type: RandomSpriteState #this has to be before sprite component for the flame to toggle right because weldercomponent behaves weird (and i dont trust myself to fix it right) - spriteStates: - - basic_icon_base-1 - - basic_icon_base-2 - - basic_icon_base-3 - - basic_icon_base-4 - - basic_icon_base-5 - - basic_icon_base-6 - - basic_icon_base-7 - - basic_icon_base-8 - - basic_icon_base-9 - - basic_icon_base-10 - - basic_icon_base-11 + # Sloth: What is this comment ????????? + - type: RandomSprite #this has to be before sprite component for the flame to toggle right because weldercomponent behaves weird (and i dont trust myself to fix it right) + available: + - enum.WelderLayers.Base: + basic_icon_base-1: "" + - enum.WelderLayers.Base: + basic_icon_base-2: "" + - enum.WelderLayers.Base: + basic_icon_base-3: "" + - enum.WelderLayers.Base: + basic_icon_base-4: "" + - enum.WelderLayers.Base: + basic_icon_base-5: "" + - enum.WelderLayers.Base: + basic_icon_base-6: "" + - enum.WelderLayers.Base: + basic_icon_base-7: "" + - enum.WelderLayers.Base: + basic_icon_base-8: "" + - enum.WelderLayers.Base: + basic_icon_base-9: "" + - enum.WelderLayers.Base: + basic_icon_base-10: "" + - enum.WelderLayers.Base: + basic_icon_base-11: "" - type: Sprite sprite: Objects/Tools/lighters.rsi + netsync: false layers: - state: icon_map map: ["enum.WelderLayers.Base"] @@ -69,16 +82,10 @@ id: CheapLighter description: "A dangerously inexpensive plastic lighter, don't burn your thumb!" components: - - type: RandomSpriteColor - state: cheap_icon_base - colors: - blue: "#1861d5" - red: "#951710" - pink: "#d5188d" - brown: "#a05212" - green: "#0e7f1b" - cyan: "#18a2d5" - yellow: "#d58c18" #all colours proudly stolen from wirecutters + - type: RandomSprite + available: + - enum.WelderLayers.Base: + cheap_icon_base: Rainbow - type: Sprite sprite: Objects/Tools/lighters.rsi layers: diff --git a/Resources/Prototypes/Entities/Objects/Tools/tools.yml b/Resources/Prototypes/Entities/Objects/Tools/tools.yml index cda5848762..110f362bc9 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/tools.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/tools.yml @@ -13,8 +13,10 @@ - Wirecutter - type: Sprite sprite: Objects/Tools/wirecutters.rsi + netsync: false layers: - - state: cutters-map + - state: cutters + map: [ "enum.DamageStateVisualLayers.Base" ] - state: cutters-cutty-thingy - type: ItemCooldown - type: MeleeWeapon @@ -26,16 +28,10 @@ - Cutting useSound: path: /Audio/Items/wirecutter.ogg - - type: RandomSpriteColor - state: cutters - colors: - blue: "#1861d5" - red: "#951710" - pink: "#d5188d" - brown: "#a05212" - green: "#0e7f1b" - cyan: "#18a2d5" - yellow: "#d58c18" + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + cutters: Rainbow - type: Item sprite: Objects/Tools/wirecutters.rsi @@ -53,8 +49,10 @@ - Screwdriver - type: Sprite sprite: Objects/Tools/screwdriver.rsi + netsync: false layers: - - state: screwdriver-map + - state: screwdriver + map: [ "enum.DamageStateVisualLayers.Base" ] - state: screwdriver-screwybits - type: Item sprite: Objects/Tools/screwdriver.rsi @@ -68,16 +66,10 @@ - Screwing useSound: collection: Screwdriver - - type: RandomSpriteColor - state: screwdriver - colors: - blue: "#1861d5" - red: "#ff0000" - pink: "#d5188d" - brown: "#a05212" - green: "#0e7f1b" - cyan: "#18a2d5" - yellow: "#ffa500" + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + screwdriver: Rainbow - type: entity name: wrench diff --git a/Resources/Prototypes/Entities/Structures/Furniture/bookshelf.yml b/Resources/Prototypes/Entities/Structures/Furniture/bookshelf.yml index adb457c74f..15dc71d097 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/bookshelf.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/bookshelf.yml @@ -9,15 +9,21 @@ layers: - state: base - state: book-0 - - type: RandomSpriteState - spriteLayer: 1 - spriteStates: - - book-0 - - book-1 - - book-2 - - book-3 - - book-4 - - book-5 + map: [ "enum.DamageStateVisualLayers.Base" ] + - type: RandomSprite + available: + - enum.DamageStateVisualLayers.Base: + book-0: "" + - enum.DamageStateVisualLayers.Base: + book-1: "" + - enum.DamageStateVisualLayers.Base: + book-2: "" + - enum.DamageStateVisualLayers.Base: + book-3: "" + - enum.DamageStateVisualLayers.Base: + book-4: "" + - enum.DamageStateVisualLayers.Base: + book-5: "" - type: Damageable damageModifierSet: Wood damageContainer: Inorganic diff --git a/Resources/Prototypes/Entities/Structures/Specific/dragon.yml b/Resources/Prototypes/Entities/Structures/Specific/dragon.yml new file mode 100644 index 0000000000..c4a98c593d --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Specific/dragon.yml @@ -0,0 +1,39 @@ +- type: entity + id: CarpRift + name: carp rift + description: A rift akin to the ones space carp use to travel long distances. + placement: + mode: SnapgridCenter + components: + - type: DragonRift + - type: Transform + anchored: true + - type: Physics + bodyType: Static + - type: Fixtures + - type: Sprite + netsync: false + layers: + - sprite: Structures/Specific/carp_rift.rsi + state: icon + color: "#569fff" + shader: unshaded + - type: InteractionOutline + - type: Clickable + - type: PointLight + enabled: true + color: "#366db5" + radius: 10.0 + energy: 5.0 + netsync: false + - type: Damageable + damageContainer: Inorganic + damageModifierSet: Metallic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 300 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index ee67e9b636..f2849448d7 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -32,6 +32,17 @@ earliestStart: 15 maxOccurrences: 3 +- type: gameRule + id: Dragon + config: + !type:StationEventRuleConfiguration + id: Dragon + weight: 10 + endAfter: 2 + earliestStart: 15 + maxOccurrences: 7 + minimumPlayers: 15 + - type: gameRule id: FalseAlarm config: diff --git a/Resources/Prototypes/Palettes/sixteen.yml b/Resources/Prototypes/Palettes/sixteen.yml index b46d44482c..cd6efe7757 100644 --- a/Resources/Prototypes/Palettes/sixteen.yml +++ b/Resources/Prototypes/Palettes/sixteen.yml @@ -1,4 +1,16 @@ - type: palette + id: Rainbow + name: Rainbow + colors: + blue: "#1861d5" + red: "#951710" + pink: "#d5188d" + brown: "#a05212" + green: "#0e7f1b" + cyan: "#18a2d5" + yellow: "#d58c18" + +- type: palette id: Sixteen name: Sixteen colors: diff --git a/Resources/Textures/Interface/Actions/carp_rift.rsi/icon.png b/Resources/Textures/Interface/Actions/carp_rift.rsi/icon.png new file mode 100644 index 0000000000..9c7706308c Binary files /dev/null and b/Resources/Textures/Interface/Actions/carp_rift.rsi/icon.png differ diff --git a/Resources/Textures/Interface/Actions/carp_rift.rsi/meta.json b/Resources/Textures/Interface/Actions/carp_rift.rsi/meta.json new file mode 100644 index 0000000000..2567d69886 --- /dev/null +++ b/Resources/Textures/Interface/Actions/carp_rift.rsi/meta.json @@ -0,0 +1,21 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/tgstation/tgstation/blob/19da0cee1869bad0186d54d6bcd8a55ed30b9db6/icons/obj/carp_rift.dmi", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon", + "delays": [ + [ + 0.2, + 0.2, + 0.2 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Aliens/Carps/holo.rsi/alive.png b/Resources/Textures/Mobs/Aliens/Carps/holo.rsi/base.png similarity index 100% rename from Resources/Textures/Mobs/Aliens/Carps/holo.rsi/alive.png rename to Resources/Textures/Mobs/Aliens/Carps/holo.rsi/base.png diff --git a/Resources/Textures/Mobs/Aliens/Carps/holo.rsi/crit.png b/Resources/Textures/Mobs/Aliens/Carps/holo.rsi/crit.png deleted file mode 100644 index 2a00379baf..0000000000 Binary files a/Resources/Textures/Mobs/Aliens/Carps/holo.rsi/crit.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Aliens/Carps/holo.rsi/meta.json b/Resources/Textures/Mobs/Aliens/Carps/holo.rsi/meta.json index 52da404bc3..da6dadc94b 100644 --- a/Resources/Textures/Mobs/Aliens/Carps/holo.rsi/meta.json +++ b/Resources/Textures/Mobs/Aliens/Carps/holo.rsi/meta.json @@ -33,29 +33,7 @@ ] }, { - "name": "crit", - "delays": [ - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ] - ] - }, - { - "name": "alive", + "name": "base", "directions": 4, "delays": [ [ diff --git a/Resources/Textures/Mobs/Aliens/Carps/magic.rsi/alive.png b/Resources/Textures/Mobs/Aliens/Carps/magic.rsi/base.png similarity index 100% rename from Resources/Textures/Mobs/Aliens/Carps/magic.rsi/alive.png rename to Resources/Textures/Mobs/Aliens/Carps/magic.rsi/base.png diff --git a/Resources/Textures/Mobs/Aliens/Carps/magic.rsi/crit.png b/Resources/Textures/Mobs/Aliens/Carps/magic.rsi/crit.png deleted file mode 100644 index ed5b23705a..0000000000 Binary files a/Resources/Textures/Mobs/Aliens/Carps/magic.rsi/crit.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Aliens/Carps/magic.rsi/meta.json b/Resources/Textures/Mobs/Aliens/Carps/magic.rsi/meta.json index c35dd71e41..cf70ff589b 100644 --- a/Resources/Textures/Mobs/Aliens/Carps/magic.rsi/meta.json +++ b/Resources/Textures/Mobs/Aliens/Carps/magic.rsi/meta.json @@ -14,10 +14,7 @@ "name": "dead" }, { - "name": "crit" - }, - { - "name": "alive", + "name": "base", "directions": 4, "delays": [ [ diff --git a/Resources/Textures/Mobs/Aliens/Carps/space.rsi/alive.png b/Resources/Textures/Mobs/Aliens/Carps/space.rsi/alive.png deleted file mode 100644 index de6b4c960b..0000000000 Binary files a/Resources/Textures/Mobs/Aliens/Carps/space.rsi/alive.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Aliens/Carps/space.rsi/base.png b/Resources/Textures/Mobs/Aliens/Carps/space.rsi/base.png new file mode 100644 index 0000000000..0bc0960efa Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Carps/space.rsi/base.png differ diff --git a/Resources/Textures/Mobs/Aliens/Carps/space.rsi/base_dead.png b/Resources/Textures/Mobs/Aliens/Carps/space.rsi/base_dead.png new file mode 100644 index 0000000000..faf6d1be60 Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Carps/space.rsi/base_dead.png differ diff --git a/Resources/Textures/Mobs/Aliens/Carps/space.rsi/crit.png b/Resources/Textures/Mobs/Aliens/Carps/space.rsi/crit.png deleted file mode 100644 index 1492ef26f2..0000000000 Binary files a/Resources/Textures/Mobs/Aliens/Carps/space.rsi/crit.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Aliens/Carps/space.rsi/dead.png b/Resources/Textures/Mobs/Aliens/Carps/space.rsi/dead.png deleted file mode 100644 index 87cdf63757..0000000000 Binary files a/Resources/Textures/Mobs/Aliens/Carps/space.rsi/dead.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Aliens/Carps/space.rsi/dead_mouth.png b/Resources/Textures/Mobs/Aliens/Carps/space.rsi/dead_mouth.png new file mode 100644 index 0000000000..bccea47b3a Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Carps/space.rsi/dead_mouth.png differ diff --git a/Resources/Textures/Mobs/Aliens/Carps/space.rsi/meta.json b/Resources/Textures/Mobs/Aliens/Carps/space.rsi/meta.json index a45b246fc8..4539505970 100644 --- a/Resources/Textures/Mobs/Aliens/Carps/space.rsi/meta.json +++ b/Resources/Textures/Mobs/Aliens/Carps/space.rsi/meta.json @@ -11,13 +11,39 @@ "name": "icon" }, { - "name": "dead" + "name": "mouth", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ] + ] }, { - "name": "crit" + "name": "dead_mouth" }, { - "name": "alive", + "name": "base_dead" + }, + { + "name": "base", "directions": 4, "delays": [ [ diff --git a/Resources/Textures/Mobs/Aliens/Carps/space.rsi/mouth.png b/Resources/Textures/Mobs/Aliens/Carps/space.rsi/mouth.png new file mode 100644 index 0000000000..8e504f91ae Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Carps/space.rsi/mouth.png differ diff --git a/Resources/Textures/Mobs/Animals/chicken.rsi/note.txt b/Resources/Textures/Mobs/Animals/chicken.rsi/note.txt deleted file mode 100644 index 872109e92f..0000000000 --- a/Resources/Textures/Mobs/Animals/chicken.rsi/note.txt +++ /dev/null @@ -1 +0,0 @@ -Eventually we'll have some kind of unifying "RandomSpriteStateComponent" but til now i'm just leaving these here in protest. \ No newline at end of file diff --git a/Resources/Textures/Mobs/Animals/duck.rsi/note.txt b/Resources/Textures/Mobs/Animals/duck.rsi/note.txt deleted file mode 100644 index 872109e92f..0000000000 --- a/Resources/Textures/Mobs/Animals/duck.rsi/note.txt +++ /dev/null @@ -1 +0,0 @@ -Eventually we'll have some kind of unifying "RandomSpriteStateComponent" but til now i'm just leaving these here in protest. \ No newline at end of file diff --git a/Resources/Textures/Structures/Specific/carp_rift.rsi/icon.png b/Resources/Textures/Structures/Specific/carp_rift.rsi/icon.png new file mode 100644 index 0000000000..2c29e29d30 Binary files /dev/null and b/Resources/Textures/Structures/Specific/carp_rift.rsi/icon.png differ diff --git a/Resources/Textures/Structures/Specific/carp_rift.rsi/meta.json b/Resources/Textures/Structures/Specific/carp_rift.rsi/meta.json new file mode 100644 index 0000000000..2567d69886 --- /dev/null +++ b/Resources/Textures/Structures/Specific/carp_rift.rsi/meta.json @@ -0,0 +1,21 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/tgstation/tgstation/blob/19da0cee1869bad0186d54d6bcd8a55ed30b9db6/icons/obj/carp_rift.dmi", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon", + "delays": [ + [ + 0.2, + 0.2, + 0.2 + ] + ] + } + ] +} \ No newline at end of file