Compare commits

...
Author SHA1 Message Date
NullWanderer 28a6d4baeb Merge branch 'master' of https://github.com/DeltaV-Station/Delta-v into april-fools-2024 2024-04-01 00:52:41 +02:00
trollbreeder b4fb5ddc2b Mobs with combat mode now only mouselook when combat mode is OFF (#26562)
inverts whether you mouselook or not for mobs with combat mode
2024-04-01 00:47:53 +02:00
Kara b2ebeabe83 better animal sprites (fools) (#26275)
better animal sprites
2024-04-01 00:47:51 +02:00
Vasilis ebd2c9b968 Quick hotfix since panda is screaming at me in vc 2024-04-01 00:47:41 +02:00
NullWanderer c578732c5c Revert "Adds a new medication for headache & pain relief (#26591)"
This reverts commit 9d0e47c300.
2024-03-31 17:04:17 +02:00
Ubaser 0ba0632b35 Switch around budget and normal insuls (#26558)
* add

* Update colored.yml

* Update colored.yml

* Update colored.yml

* death
2024-03-31 16:57:34 +02:00
Vyacheslav Kovalevsky 1b05a76ade Cancer mouse (#26132)
* cancer mouse

* minor tweaks
2024-03-31 16:57:31 +02:00
Leon Friedrich 9d0e47c300 Adds a new medication for headache & pain relief (#26591)
* Well damn it kinda works

* And this is to go even further ...

* Add drugs
2024-03-31 16:56:57 +02:00
SlamBamActionman de42819c0b Bring back tippy from april fools last year (#26112)
Tippy is BACK
2024-03-31 16:55:54 +02:00
Pieter-Jan Briers 76c415380a You can FTL to the Chess Dimension. (#26536) 2024-03-31 16:55:50 +02:00
Simon f0943ef42f Arcade that sends you to OpenDream Paradise station (#26476)
* The actual april fools joke is the shitcode I produced

* Make text clearer.

* Spawner adjustments

* Improve image size.
Thanks .landwhale (discord)!

* Fix mismatching duration
2024-03-31 16:55:03 +02:00
Vyacheslav Kovalevskyandmetalgearsloth 0c3c4d2d32 replace boring items with fun items on spawn (#26087)
* ReplaceRandom

* maybe use polymorph

* Revert "maybe use polymorph"

This reverts commit 28ecd64d122a335dd999d52a9795afc1df09c991.

* handle containers also

* better name

* chance to grow hot potato too

* replace banana peel with explosive

* fix containers

* more fun

* even more fun

* extra fun

* Update Content.Server/ReplaceOnSpawn/ReplaceOnSpawnSystem.cs

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2024-03-31 16:54:45 +02:00
lzk 2e09441d76 Clown goblins (April Fools) (#26306)
* Clown goblins migration

* remove some stuff

* fx
2024-03-31 16:53:46 +02:00
Hannah Giovanna Dawson e189a8f71f Skug brainrot wawa rain world backflip cat (#26168)
* wawa

* Minor cleanup, change intro/outro sfx

* Fix yaml

* wawaskillissue

* challenge

* Remove unusable audio, update spriting

* Kill remaining wawa sfx

* Fix name prefix

* these sound effects cost £460

* these attributations cost £0

* louder, mono wawa noises

* Audio fixes

* Tidy server system

* Code tidy-up, wawa

* Remove locstring hardcodes

* Bug fixes, wawa

* meta update, wawa

* Force antagprotoid to be hardcoded because yaml validation cringe, wawa
2024-03-27 23:25:17 +01:00
Keer-Sar e74f92556e Wehvitational Wehularity Engine UNCOOKED! (#26219)
* creat uncooked version of PR #26201

* removed cooked code from cooked branch, fixed sprite directory
2024-03-27 23:25:13 +01:00
Crotalus 216a0790b1 Any crew member can be a traitor (#26333)
All jobs can be traitor
2024-03-27 23:24:53 +01:00
Vyacheslav Kovalevsky 08e134c3ea Add new "oof" body fall sound (#26384) 2024-03-27 23:23:36 +01:00
Alzore cb08bfa498 Smoking now does very not minor cellular damage (April fools) (#26298)
* stage7lungcancer

* tumors
2024-03-27 23:23:01 +01:00
GeneralGawsandGeneralGaws 9d083b6914 Clown ghost skin (april fools) (#26272)
clownghost

Co-authored-by: GeneralGaws <limonmessi@mail.ru>
2024-03-27 23:22:56 +01:00
chromiumboy e0ad8c0da0 Syndicate traitors can now purchase nuke codes (#26280) 2024-03-27 23:22:54 +01:00
deltanedasanddeltanedas f21b2275b4 swap carp and carp plushie sprites (april 1) (#26080)
* add plushie textures

* swap carp and plushie sprites

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
2024-03-27 23:22:39 +01:00
lzk 06b13f39e6 Give every job sad trombone implant (april fools) (#26084)
Give every job sad trombone implant
2024-03-27 23:21:01 +01:00
Vyacheslav Kovalevsky 42a9317d3f reverse lights (#26117) 2024-03-27 23:16:51 +01:00
Vyacheslav Kovalevsky 182657e73e Blood is fuel (#26140)
* blood is fuel

* ultrakill silicon laws

* red welders

* fix jrpacman desc

* only junior runs on blood (bloodpacks are not material)
2024-03-27 23:15:07 +01:00
Vyacheslav Kovalevsky 02a6bb7d23 Color all wires green to save planet(s) (#26115)
* use green coil for everything

* replace cables too

* wires in panels too

* fix cable sprites (a)

* Revert "fix cable sprites (a)"

This reverts commit d789f78ff024a1ffdc70336515db9a0e43fdadc1.

* Revert "replace cables too"

This reverts commit f321eca49b11b04d346c7037d05af0928be797e4.

* color cables green

* no orange
2024-03-27 23:14:23 +01:00
280 changed files with 2661 additions and 164 deletions
@@ -0,0 +1,54 @@
using System.Threading.Tasks;
using Content.Shared.Arcade;
using JetBrains.Annotations;
using Robust.Client;
using Robust.Shared.Timing;
using Serilog;
namespace Content.Client.Arcade.UI;
[UsedImplicitly]
public sealed class ParadiseArcadeBoundUserInterface : BoundUserInterface
{
[Dependency]
private IGameController _gameController = default!;
private ParadiseArcadeWindow? _window;
public ParadiseArcadeBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
IoCManager.InjectDependencies(this);
}
protected override void Open()
{
base.Open();
_window = new();
_window.OpenCentered();
_window.OnClose += Close;
_window.OnConnectButtonPressed = () =>
{
SendMessage(new ParadiesMessages.ParadiseArcadeConnectButtonPressedEvent());
};
}
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
{
base.ReceiveMessage(message);
if (message is not ParadiesMessages.ParadiseArcadeConnectEvent connectEvent)
return;
_gameController.Redial(connectEvent.Destination, "Paradise arcade used to connect to another server.");
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_window?.Dispose();
}
}
@@ -0,0 +1,10 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'paradise-arcade-window-title'}"
Resizable="False">
<BoxContainer Orientation="Vertical" Margin="4" MinWidth="500">
<Label Text="{Loc 'paradise-arcade-button-label'}"></Label>
<Button Name="ConnectButton" Text="{Loc 'paradise-arcade-button-text'}"></Button>
</BoxContainer>
</controls:FancyWindow>
@@ -0,0 +1,20 @@
using Content.Client.UserInterface.Controls;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Arcade.UI;
[GenerateTypedNameReferences]
public sealed partial class ParadiseArcadeWindow : FancyWindow
{
public Action? OnConnectButtonPressed;
public ParadiseArcadeWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
ConnectButton.OnPressed += _ => OnConnectButtonPressed?.Invoke();
}
}
@@ -0,0 +1,54 @@
using Content.Shared.LegallyDistinctSpaceFerret;
using Robust.Client.Animations;
using Robust.Client.Audio;
using Robust.Client.GameObjects;
using Robust.Shared.Animations;
using Robust.Shared.Audio;
using Robust.Shared.Player;
namespace Content.Client.LegallyDistinctSpaceFerret;
public sealed class CanBackflipSystem : EntitySystem
{
[Dependency] private readonly AnimationPlayerSystem _animation = default!;
[Dependency] private readonly AudioSystem _audio = default!;
public const string BackflipKey = "backflip";
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<DoABackFlipEvent>(OnBackflipEvent);
}
public void OnBackflipEvent(DoABackFlipEvent args)
{
if (!TryGetEntity(args.Actioner, out var uid))
{
return;
}
_animation.Play(uid.Value, new Animation
{
Length = TimeSpan.FromSeconds(0.66),
AnimationTracks =
{
new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Rotation),
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(0), 0f),
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(180), 0.33f),
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(360), 0.33f),
}
}
}
}, BackflipKey);
_audio.PlayEntity(new SoundPathSpecifier(args.SfxSource), Filter.Local(), uid.Value, false);
}
}
@@ -0,0 +1,31 @@
using Content.Shared.LegallyDistinctSpaceFerret;
using Robust.Client.Audio;
using Robust.Client.GameObjects;
using Robust.Shared.Audio;
namespace Content.Client.LegallyDistinctSpaceFerret;
public sealed class CanHibernateSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<EntityHasHibernated>(OnHibernateEvent);
}
public void OnHibernateEvent(EntityHasHibernated args)
{
if (!TryGetEntity(args.Hibernator, out var uid))
{
return;
}
if (!TryComp<SpriteComponent>(uid, out var comp))
{
return;
}
comp.LayerSetState(0, args.SpriteStateId);
}
}
+11
View File
@@ -0,0 +1,11 @@
<tips:ClippyUI xmlns="https://spacestation14.io"
xmlns:tips="clr-namespace:Content.Client.Tips"
MinSize="64 64"
Visible="False">
<PanelContainer Name="LabelPanel" Access="Public" Visible="False" MaxWidth="300" MaxHeight="200">
<ScrollContainer Name="ScrollingContents" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalExpand="True" VerticalExpand="True" HScrollEnabled="False" ReturnMeasure="True">
<RichTextLabel Name="Label" Access="Public"/>
</ScrollContainer>
</PanelContainer>
<SpriteView Name="Entity" Access="Public" MinSize="128 128"/>
</tips:ClippyUI>
+54
View File
@@ -0,0 +1,54 @@
using Content.Client.Paper;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Tips;
[GenerateTypedNameReferences]
public sealed partial class ClippyUI : UIWidget
{
public ClippyState State = ClippyState.Hidden;
public bool ModifyLayers = true;
public ClippyUI()
{
RobustXamlLoader.Load(this);
}
public void InitLabel(PaperVisualsComponent? visuals, IResourceCache resCache)
{
if (visuals == null)
return;
Label.ModulateSelfOverride = visuals.FontAccentColor;
if (visuals.BackgroundImagePath == null)
return;
LabelPanel.ModulateSelfOverride = visuals.BackgroundModulate;
var backgroundImage = resCache.GetResource<TextureResource>(visuals.BackgroundImagePath);
var backgroundImageMode = visuals.BackgroundImageTile ? StyleBoxTexture.StretchMode.Tile : StyleBoxTexture.StretchMode.Stretch;
var backgroundPatchMargin = visuals.BackgroundPatchMargin;
LabelPanel.PanelOverride = new StyleBoxTexture
{
Texture = backgroundImage,
TextureScale = visuals.BackgroundScale,
Mode = backgroundImageMode,
PatchMarginLeft = backgroundPatchMargin.Left,
PatchMarginBottom = backgroundPatchMargin.Bottom,
PatchMarginRight = backgroundPatchMargin.Right,
PatchMarginTop = backgroundPatchMargin.Top
};
}
public enum ClippyState : byte
{
Hidden,
Revealing,
Speaking,
Hiding,
}
}
+270
View File
@@ -0,0 +1,270 @@
using Content.Client.Gameplay;
using System.Numerics;
using Content.Client.Message;
using Content.Client.Paper;
using Content.Shared.CCVar;
using Content.Shared.Movement.Components;
using Content.Shared.Tips;
using Robust.Client.GameObjects;
using Robust.Client.ResourceManagement;
using Robust.Client.State;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
using Robust.Client.UserInterface.Controls;
using Robust.Client.Audio;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using static Content.Client.Tips.ClippyUI;
namespace Content.Client.Tips;
public sealed class ClippyUIController : UIController
{
[Dependency] private readonly IStateManager _state = default!;
[Dependency] private readonly IConsoleHost _conHost = default!;
[Dependency] private readonly IPrototypeManager _protoMan = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IResourceCache _resCache = default!;
[UISystemDependency] private readonly AudioSystem _audio = default!;
public const float Padding = 50;
public static Angle WaddleRotation = Angle.FromDegrees(10);
private EntityUid _entity;
private float _secondsUntilNextState;
private int _previousStep = 0;
private ClippyEvent? _currentMessage;
private readonly Queue<ClippyEvent> _queuedMessages = new();
public override void Initialize()
{
base.Initialize();
_conHost.RegisterCommand("local_clippy", ClippyCommand);
UIManager.OnScreenChanged += OnScreenChanged;
}
private void ClippyCommand(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length == 0)
{
shell.WriteLine("usage: clippy <message> [entity prototype] [speak time] [animate time] [waddle]");
return;
}
var ev = new ClippyEvent(args[0]);
string proto;
if (args.Length > 1)
{
ev.Proto = args[1];
if (!_protoMan.HasIndex<EntityPrototype>(ev.Proto))
{
shell.WriteError($"Unknown prototype: {ev.Proto}");
return;
}
}
if (args.Length > 2)
ev.SpeakTime = float.Parse(args[2]);
if (args.Length > 3)
ev.SlideTime = float.Parse(args[3]);
if (args.Length > 4)
ev.WaddleInterval = float.Parse(args[4]);
AddMessage(ev);
}
public void AddMessage(ClippyEvent ev)
{
_queuedMessages.Enqueue(ev);
}
public override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
var screen = UIManager.ActiveScreen;
if (screen == null)
{
_queuedMessages.Clear();
return;
}
var clippy = screen.GetOrAddWidget<ClippyUI>();
_secondsUntilNextState -= args.DeltaSeconds;
if (_secondsUntilNextState <= 0)
NextState(clippy);
else
{
var pos = UpdatePosition(clippy, screen.Size, args); ;
LayoutContainer.SetPosition(clippy, pos);
}
}
private Vector2 UpdatePosition(ClippyUI clippy, Vector2 screenSize, FrameEventArgs args)
{
if (_currentMessage == null)
return default;
var slideTime = _currentMessage.SlideTime;
var offset = clippy.State switch
{
ClippyState.Hidden => 0,
ClippyState.Revealing => Math.Clamp(1 - _secondsUntilNextState / slideTime, 0, 1),
ClippyState.Hiding => Math.Clamp(_secondsUntilNextState / slideTime, 0, 1),
_ => 1,
};
var waddle = _currentMessage.WaddleInterval;
if (_currentMessage == null
|| waddle <= 0
|| clippy.State == ClippyState.Hidden
|| clippy.State == ClippyState.Speaking
|| !EntityManager.TryGetComponent(_entity, out SpriteComponent? sprite))
{
return new Vector2(screenSize.X - offset * (clippy.DesiredSize.X + Padding), (screenSize.Y - clippy.DesiredSize.Y) / 2);
}
var numSteps = (int) Math.Ceiling(slideTime / waddle);
var curStep = (int) Math.Floor(numSteps * offset);
var stepSize = (clippy.DesiredSize.X + Padding) / numSteps;
if (curStep != _previousStep)
{
_previousStep = curStep;
sprite.Rotation = sprite.Rotation > 0
? -WaddleRotation
: WaddleRotation;
if (EntityManager.TryGetComponent(_entity, out FootstepModifierComponent? step))
{
var audioParams = step.FootstepSoundCollection.Params
.AddVolume(-7f)
.WithVariation(0.1f);
_audio.PlayGlobal(step.FootstepSoundCollection, EntityUid.Invalid, audioParams);
}
}
return new Vector2(screenSize.X - stepSize * curStep, (screenSize.Y - clippy.DesiredSize.Y) / 2);
}
private void NextState(ClippyUI clippy)
{
SpriteComponent? sprite;
switch (clippy.State)
{
case ClippyState.Hidden:
if (!_queuedMessages.TryDequeue(out var next))
return;
if (next.Proto != null)
{
_entity = EntityManager.SpawnEntity(next.Proto, MapCoordinates.Nullspace);
clippy.ModifyLayers = false;
}
else
{
_entity = EntityManager.SpawnEntity(_cfg.GetCVar(CCVars.ClippyEntity), MapCoordinates.Nullspace);
clippy.ModifyLayers = true;
}
if (!EntityManager.TryGetComponent(_entity, out sprite))
return;
clippy.InitLabel(EntityManager.GetComponentOrNull<PaperVisualsComponent>(_entity), _resCache);
var scale = sprite.Scale;
if (clippy.ModifyLayers)
{
sprite.Scale = Vector2.One;
}
else
{
sprite.Scale = new Vector2(2, 2);
}
clippy.Entity.SetEntity(_entity);
clippy.Entity.Scale = scale;
_currentMessage = next;
_secondsUntilNextState = next.SlideTime;
clippy.State = ClippyState.Revealing;
_previousStep = 0;
if (clippy.ModifyLayers)
{
sprite.LayerSetAnimationTime("revealing", 0);
sprite.LayerSetVisible("revealing", true);
sprite.LayerSetVisible("speaking", false);
sprite.LayerSetVisible("hiding", false);
}
sprite.Rotation = 0;
clippy.Label.SetMarkup(_currentMessage.Msg);
clippy.LabelPanel.Visible = false;
clippy.Visible = true;
sprite.Visible = true;
break;
case ClippyState.Revealing:
clippy.State = ClippyState.Speaking;
if (!EntityManager.TryGetComponent(_entity, out sprite))
return;
sprite.Rotation = 0;
_previousStep = 0;
if (clippy.ModifyLayers)
{
sprite.LayerSetAnimationTime("speaking", 0);
sprite.LayerSetVisible("revealing", false);
sprite.LayerSetVisible("speaking", true);
sprite.LayerSetVisible("hiding", false);
}
clippy.LabelPanel.Visible = true;
clippy.InvalidateArrange();
clippy.InvalidateMeasure();
if (_currentMessage != null)
_secondsUntilNextState = _currentMessage.SpeakTime;
break;
case ClippyState.Speaking:
clippy.State = ClippyState.Hiding;
if (!EntityManager.TryGetComponent(_entity, out sprite))
return;
if (clippy.ModifyLayers)
{
sprite.LayerSetAnimationTime("hiding", 0);
sprite.LayerSetVisible("revealing", false);
sprite.LayerSetVisible("speaking", false);
sprite.LayerSetVisible("hiding", true);
}
clippy.LabelPanel.Visible = false;
if (_currentMessage != null)
_secondsUntilNextState = _currentMessage.SlideTime;
break;
default: // finished hiding
EntityManager.DeleteEntity(_entity);
_entity = default;
clippy.Visible = false;
_currentMessage = null;
_secondsUntilNextState = 0;
clippy.State = ClippyState.Hidden;
break;
}
}
private void OnScreenChanged((UIScreen? Old, UIScreen? New) ev)
{
ev.Old?.RemoveWidget<ClippyUI>();
_currentMessage = null;
EntityManager.DeleteEntity(_entity);
}
}
+20
View File
@@ -0,0 +1,20 @@
using Content.Shared.Tips;
using Robust.Client.UserInterface;
namespace Content.Client.Tips;
public sealed class TipsSystem : EntitySystem
{
[Dependency] private readonly IUserInterfaceManager _uiMan = default!;
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<ClippyEvent>(OnClippyEv);
}
private void OnClippyEv(ClippyEvent ev)
{
_uiMan.GetUIController<ClippyUIController>().AddMessage(ev);
}
}
@@ -0,0 +1,7 @@
namespace Content.Server.Arcade.ParadiseGame;
[RegisterComponent]
public sealed partial class InParadiseComponent : Component
{
}
@@ -0,0 +1,8 @@
namespace Content.Server.Arcade.ParadiseGame;
[RegisterComponent]
public sealed partial class ParadiseArcadeComponent : Component
{
[DataField]
public string Destination;
}
@@ -0,0 +1,68 @@
using Content.Shared.Arcade;
using Content.Shared.Bed.Sleep;
using Content.Shared.Examine;
using Content.Shared.IdentityManagement;
using Content.Shared.StatusEffect;
using Robust.Server.GameObjects;
namespace Content.Server.Arcade.ParadiseGame;
public sealed partial class ParadiseSystem : EntitySystem
{
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
[ValidatePrototypeId<StatusEffectPrototype>]
private const string StatusEffectKey = "ForcedSleep";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ParadiseArcadeComponent, ParadiesMessages.ParadiseArcadeConnectButtonPressedEvent>(OnPress);
SubscribeLocalEvent<InParadiseComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<SleepingComponent, ComponentRemove>(OnRemove);
// This whole thing is a mess, but good enough for april fools. I will never touch UI ever again.
}
private void OnRemove(EntityUid uid, SleepingComponent component, ComponentRemove args)
{
if (HasComp<InParadiseComponent>(uid))
{
RemComp<InParadiseComponent>(uid);
}
}
private void OnExamine(EntityUid uid, InParadiseComponent component, ExaminedEvent args)
{
args.PushMarkup(Loc.GetString("paradise-arcade-on-examine", ("target", Identity.Entity(uid, EntityManager))));
}
private void OnPress(EntityUid uid, ParadiseArcadeComponent component, ParadiesMessages.ParadiseArcadeConnectButtonPressedEvent args)
{
if (!args.Session.AttachedEntity.HasValue)
{
Log.Warning("ParadiseArcadeConnectButtonPressedEvent sent without attached entity.");
return;
}
_statusEffectsSystem.TryAddStatusEffect<ForcedSleepingComponent>(args.Session.AttachedEntity.Value, StatusEffectKey, TimeSpan.FromSeconds(60), true);
AddComp<InParadiseComponent>(args.Session.AttachedEntity.Value);
if (!_userInterface.TryGetUi(uid, args.UiKey, out var userInterface))
{
Log.Warning("UserInterface not found.");
return;
}
var didSend = _userInterface.TrySendUiMessage(
userInterface,
new ParadiesMessages.ParadiseArcadeConnectEvent(component.Destination),
args.Session);
if (!didSend)
{
Log.Error("Failed to send message.");
}
}
}
@@ -13,6 +13,11 @@ using Robust.Shared.Timing;
namespace Content.Server.Interaction;
public sealed class InteractionAttemptFailed(EntityUid target)
{
public EntityUid Target = target;
}
public sealed class InteractionPopupSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
@@ -96,6 +101,8 @@ public sealed class InteractionPopupSystem : EntitySystem
if (component.InteractFailureSpawn != null)
Spawn(component.InteractFailureSpawn, _transform.GetMapCoordinates(uid));
RaiseLocalEvent(target, new InteractionAttemptFailed(target));
}
if (component.MessagePerceivedByOthers != null)
@@ -0,0 +1,154 @@
using System.Threading;
using Content.Server.Popups;
using Content.Server.Speech;
using Content.Shared.LegallyDistinctSpaceFerret;
using Content.Shared.Mind;
using Content.Shared.Physics;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Events;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Random;
using Timer = Robust.Shared.Timing.Timer;
namespace Content.Server.LegallyDistinctSpaceFerret;
/// <summary>
/// Raised locally when a mind gets too close to a Brainrot-causer.
/// </summary>
/// <param name="target">Who got brainrot</param>
/// <param name="cause">Who caused brainrot</param>
/// <param name="time">How long will they have it for</param>
public struct EntityGivenBrainrotEvent(EntityUid target, EntityUid cause, float time)
{
public EntityUid Cause = cause;
public EntityUid Target = target;
public float Time = time;
}
/// <summary>
/// Raised locally when a mind is freed from brainrot
/// </summary>
/// <param name="target">Who had brainrot</param>
public struct EntityLostBrainrotEvent(EntityUid target)
{
public EntityUid Target = target;
}
public sealed class BrainrotSystem : EntitySystem
{
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly FixtureSystem _fixtures = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
public const string BrainrotFixture = "brainrot";
public const string BrainRotApplied = "brainrot-applied";
public const string BrainRotLost = "brainrot-lost";
public readonly string[] BrainRotReplacementStrings =
[
"brainrot-replacement-1",
"brainrot-replacement-2",
"brainrot-replacement-3",
"brainrot-replacement-4",
"brainrot-replacement-5",
"brainrot-replacement-6"
];
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BrainrotAuraComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<BrainrotAuraComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<BrainrotAuraComponent, StartCollideEvent>(OnCollide);
SubscribeLocalEvent<EntityGivenBrainrotEvent>(EntityGivenBrainrot);
SubscribeLocalEvent<EntityLostBrainrotEvent>(EntityLostBrainrot);
SubscribeLocalEvent<BrainrotComponent, AccentGetEvent>(ApplyBrainRot);
}
private void OnStartup(EntityUid uid, BrainrotAuraComponent component, ComponentStartup args)
{
if (!TryComp<PhysicsComponent>(uid, out var body))
return;
var shape = new PhysShapeCircle(component.Range);
_fixtures.TryCreateFixture(uid, shape, BrainrotFixture, collisionLayer: (int) CollisionGroup.MobMask, hard: false, body: body);
}
private void OnShutdown(EntityUid uid, BrainrotAuraComponent component, ComponentShutdown args)
{
if (!TryComp<PhysicsComponent>(uid, out var body) ||
MetaData(uid).EntityLifeStage >= EntityLifeStage.Terminating)
{
return;
}
_fixtures.DestroyFixture(uid, BrainrotFixture, body: body);
}
private void OnCollide(EntityUid uid, BrainrotAuraComponent component, ref StartCollideEvent args)
{
// No effect if the mob is mindless
if (!_mind.TryGetMind(args.OtherEntity, out _, out _))
{
return;
}
// No effect if the mob has brainrot or causes brainrot
if (HasComp<BrainrotAuraComponent>(args.OtherEntity) || HasComp<BrainrotComponent>(args.OtherEntity))
{
return;
}
RaiseLocalEvent(new EntityGivenBrainrotEvent(args.OtherEntity, uid, component.Time));
}
private void EntityGivenBrainrot(EntityGivenBrainrotEvent args)
{
if (TryComp<BrainrotComponent>(args.Target, out var comp))
{
comp.Duration += args.Time;
}
else
{
comp = EnsureComp<BrainrotComponent>(args.Target);
}
var cancel = new CancellationTokenSource();
Timer.Spawn(TimeSpan.FromSeconds(comp.Duration), () =>
{
comp.Duration -= args.Time;
if (comp.Duration <= 0.0f)
{
RaiseLocalEvent(new EntityLostBrainrotEvent(args.Target));
}
}, cancel.Token);
comp.Cancels.Add(cancel);
_popup.PopupEntity(Loc.GetString(BrainRotApplied), args.Target, args.Target);
}
private void EntityLostBrainrot(EntityLostBrainrotEvent args)
{
if (TryComp<BrainrotComponent>(args.Target, out var comp))
{
foreach (var cancel in comp.Cancels)
{
cancel.Cancel();
}
}
RemComp<BrainrotComponent>(args.Target);
_popup.PopupEntity(Loc.GetString(BrainRotLost), args.Target, args.Target);
}
private void ApplyBrainRot(EntityUid entity, BrainrotComponent comp, AccentGetEvent args)
{
args.Message = Loc.GetString(_random.Pick(BrainRotReplacementStrings));
}
}
@@ -0,0 +1,29 @@
using Content.Server.Actions;
using Content.Shared.LegallyDistinctSpaceFerret;
namespace Content.Server.LegallyDistinctSpaceFerret;
public sealed class CanBackflipSystem : EntitySystem
{
[Dependency] private readonly ActionsSystem _actions = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CanBackflipComponent, MapInitEvent>(OnInit);
SubscribeLocalEvent<CanBackflipComponent, BackflipActionEvent>(OnBackflipAction);
}
private void OnInit(EntityUid uid, CanBackflipComponent component, MapInitEvent args)
{
_actions.AddAction(uid, ref component.BackflipActionEntity, component.BackflipAction, uid);
}
public void OnBackflipAction(EntityUid uid, CanBackflipComponent comp, BackflipActionEvent args)
{
RaiseNetworkEvent(new DoABackFlipEvent(GetNetEntity(uid), comp.ClappaSfx));
args.Handled = true;
}
}
@@ -0,0 +1,86 @@
using Content.Server.Actions;
using Content.Server.Atmos.Piping.Unary.Components;
using Content.Server.GameTicking;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Popups;
using Content.Shared.Interaction.Components;
using Content.Shared.LegallyDistinctSpaceFerret;
using Content.Shared.Mind;
using Content.Shared.NPC;
using Content.Shared.Popups;
using Robust.Server.Audio;
using Robust.Shared.Audio;
namespace Content.Server.LegallyDistinctSpaceFerret;
public sealed class CanHibernateSystem : EntitySystem
{
[Dependency] private readonly ActionsSystem _actions = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly GameTicker _ticker = default!;
[Dependency] private readonly AudioSystem _audio = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CanHibernateComponent, MapInitEvent>(OnInit);
SubscribeLocalEvent<CanHibernateComponent, EepyActionEvent>(OnEepyAction);
}
private void OnInit(EntityUid uid, CanHibernateComponent component, MapInitEvent args)
{
_actions.AddAction(uid, ref component.EepyActionEntity, component.EepyAction, uid);
}
public void OnEepyAction(EntityUid uid, CanHibernateComponent comp, EepyActionEvent args)
{
// If you require food before hibernating, assert that this condition has been fulfilled.
if (_mind.TryGetObjectiveComp<ConsumeNutrientsConditionComponent>(uid, out var nutrientsCondition) && nutrientsCondition.NutrientsConsumed / nutrientsCondition.NutrientsRequired < 1.0)
{
_popup.PopupEntity(Loc.GetString(comp.NotEnoughNutrientsMessage), uid, PopupType.SmallCaution);
return;
}
// Assert that you're near a hibernation point (scrubbers)
var scrubbers = _lookup.GetEntitiesInRange<GasVentScrubberComponent>(Transform(uid).Coordinates, 2f);
if (scrubbers.Count <= 0)
{
_popup.PopupEntity(Loc.GetString(comp.TooFarFromHibernationSpot), uid, PopupType.SmallCaution);
return;
}
if (_mind.TryGetObjectiveComp<HibernateConditionComponent>(uid, out var hibernateCondition))
{
_audio.PlayPvs(new SoundPathSpecifier(hibernateCondition.SuccessSfx), uid);
_popup.PopupEntity(Loc.GetString(hibernateCondition.SuccessMessage), uid, PopupType.Large);
hibernateCondition.Hibernated = true;
}
// Kick player out
var mind = _mind.GetMind(uid);
if (mind != null)
{
_ticker.OnGhostAttempt(mind.Value, false);
}
// End ghost-role
AddComp<BlockMovementComponent>(uid);
RemComp<ActiveNPCComponent>(uid);
RemComp<GhostTakeoverAvailableComponent>(uid);
// Notify
RaiseNetworkEvent(new EntityHasHibernated(GetNetEntity(uid), comp.SpriteStateId));
args.Handled = true;
}
}
public struct EntityHibernateAttemptSuccessEvent(EntityUid entity)
{
public EntityUid Entity = entity;
}
@@ -0,0 +1,19 @@
using Content.Shared.LegallyDistinctSpaceFerret;
using Content.Shared.Objectives.Components;
namespace Content.Server.LegallyDistinctSpaceFerret;
public sealed class ConsumeNutrientsObjectiveSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ConsumeNutrientsConditionComponent, ObjectiveGetProgressEvent>(OnConsumeNutrientsGetProgress);
}
private static void OnConsumeNutrientsGetProgress(EntityUid uid, ConsumeNutrientsConditionComponent comp, ref ObjectiveGetProgressEvent args)
{
args.Progress = comp.NutrientsConsumed / comp.NutrientsRequired;
}
}
@@ -0,0 +1,19 @@
using Content.Shared.LegallyDistinctSpaceFerret;
using Content.Shared.Objectives.Components;
namespace Content.Server.LegallyDistinctSpaceFerret;
public sealed class HibernateObjectiveSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<HibernateConditionComponent, ObjectiveGetProgressEvent>(OnHibernateGetProgress);
}
private static void OnHibernateGetProgress(EntityUid uid, HibernateConditionComponent comp, ref ObjectiveGetProgressEvent args)
{
args.Progress = comp.Hibernated ? 1.0f : 0.0f;
}
}
@@ -0,0 +1,87 @@
using Content.Server.Chat.Managers;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.GenericAntag;
using Content.Server.Interaction;
using Content.Server.Popups;
using Content.Server.Roles;
using Content.Server.StationEvents.Events;
using Content.Shared.LegallyDistinctSpaceFerret;
using Content.Shared.Mind;
using Content.Shared.Nutrition.EntitySystems;
using Content.Shared.Roles;
using Robust.Server.Audio;
using Robust.Shared.Audio;
namespace Content.Server.LegallyDistinctSpaceFerret;
public sealed class LegallyDistinctSpaceFerretSystem : EntitySystem
{
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly RoleSystem _role = default!;
[Dependency] private readonly IChatManager _chatMan = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly GameTicker _ticker = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<LegallyDistinctSpaceFerretComponent, GenericAntagCreatedEvent>(OnInit);
SubscribeLocalEvent<LegallyDistinctSpaceFerretComponent, InteractionAttemptFailed>(OnInteractFailed);
SubscribeLocalEvent<LegallyDistinctSpaceFerretComponent, HungerModifiedEvent>(OnHungerModified);
}
private void OnInit(EntityUid uid, LegallyDistinctSpaceFerretComponent component, GenericAntagCreatedEvent args)
{
var mind = args.Mind;
if (mind.Session == null)
return;
var session = mind.Session;
_role.MindAddRole(args.MindId, new RoleBriefingComponent
{
Briefing = Loc.GetString(component.RoleBriefing)
}, mind);
_role.MindAddRole(args.MindId, new LegallyDistinctSpaceFerretRoleComponent()
{
PrototypeId = component.AntagProtoId
}, mind);
_role.MindPlaySound(args.MindId, new SoundPathSpecifier(component.RoleIntroSfx), mind);
_chatMan.DispatchServerMessage(session, Loc.GetString(component.RoleGreeting));
}
public void OnInteractFailed(EntityUid uid, LegallyDistinctSpaceFerretComponent _, InteractionAttemptFailed args)
{
RaiseLocalEvent(uid, new BackflipActionEvent());
}
private void OnHungerModified(EntityUid uid, LegallyDistinctSpaceFerretComponent comp, HungerModifiedEvent args)
{
if (_mind.TryGetObjectiveComp<ConsumeNutrientsConditionComponent>(uid, out var nutrientsCondition) && args.Amount > 0)
{
nutrientsCondition.NutrientsConsumed += args.Amount;
}
}
}
[RegisterComponent, Access(typeof(LegallyDistinctSpaceFerretSystem)), ExclusiveAntagonist]
public sealed partial class LegallyDistinctSpaceFerretRoleComponent : AntagonistRoleComponent;
[RegisterComponent]
public sealed partial class LegallyDistinctSpaceFerretSpawnRuleComponent : Component;
public sealed class LegallyDistinctSpaceFerretSpawnRule : StationEventSystem<LegallyDistinctSpaceFerretSpawnRuleComponent>
{
protected override void Started(EntityUid uid, LegallyDistinctSpaceFerretSpawnRuleComponent comp, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, comp, gameRule, args);
TryFindRandomTile(out _, out _, out _, out var coords);
Sawmill.Info($"Creating ferret spawn point at {coords}");
Spawn("SpawnPointGhostLegallyDistinctSpaceFerret", coords);
}
}
@@ -0,0 +1,13 @@
using Robust.Shared.Prototypes;
namespace Content.Server.ReplaceOnSpawn;
[RegisterComponent]
public sealed partial class ReplaceOnSpawnComponent : Component
{
[DataField]
public EntProtoId? Prototype;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float Chance = 0.01f;
}
@@ -0,0 +1,49 @@
using Content.Shared.Buckle;
using Robust.Server.Containers;
using Robust.Server.GameObjects;
using Robust.Shared.Collections;
using Robust.Shared.Random;
namespace Content.Server.ReplaceOnSpawn;
public sealed class ReplaceOnSpawn : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedBuckleSystem _buckle = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly ContainerSystem _container = default!;
public override void Update(float deltaTime)
{
// because OnMapInit is called when entity is spawned it can be put in container later which breaks stuff
// so have to do it this way instead
var toReplace = new ValueList<(EntityUid, ReplaceOnSpawnComponent)>();
var query = EntityQueryEnumerator<ReplaceOnSpawnComponent>();
while (query.MoveNext(out var uid, out var comp))
{
if (!_random.Prob(comp.Chance))
{
RemCompDeferred<ReplaceOnSpawnComponent>(uid);
continue;
}
toReplace.Add((uid, comp));
}
foreach (var (uid, comp) in toReplace)
{
// mostly stolen code from polymorph system
_buckle.TryUnbuckle(uid, uid, true);
var targetTransformComp = Transform(uid);
var child = Spawn(comp.Prototype, targetTransformComp.Coordinates);
var childXform = Transform(child);
_transform.SetLocalRotation(child, targetTransformComp.LocalRotation, childXform);
if (_container.TryGetContainingContainer(uid, out var cont))
{
_container.Remove(uid, cont, force: true);
_container.Insert(child, cont, force: true);
}
QueueDel(uid);
}
}
}
@@ -1,4 +1,6 @@
using Content.Server.Store.Components;
using Content.Server.Paper;
using Content.Server.Store.Components;
using Content.Shared.UserInterface;
using Robust.Shared.Containers;
namespace Content.Server.Store.Systems;
@@ -11,6 +13,17 @@ public sealed partial class StoreSystem
SubscribeLocalEvent<StoreRefundComponent, EntityTerminatingEvent>(OnRefundTerminating);
SubscribeLocalEvent<StoreRefundComponent, EntRemovedFromContainerMessage>(OnEntityRemoved);
SubscribeLocalEvent<StoreRefundComponent, EntInsertedIntoContainerMessage>(OnEntityInserted);
SubscribeLocalEvent<StoreRefundComponent, BeforeActivatableUIOpenEvent>(BeforeUIOpen);
}
private void BeforeUIOpen(EntityUid uid, StoreRefundComponent component, BeforeActivatableUIOpenEvent args)
{
if (component.StoreEntity == null || _actions.TryGetActionData(uid, out _) || !TryComp<StoreComponent>(component.StoreEntity.Value, out var storeComp))
return;
if (!TryComp<PaperComponent>(uid, out var paper) || string.IsNullOrEmpty(paper.Content))
return;
DisableRefund(component.StoreEntity.Value, storeComp);
}
private void OnEntityRemoved(EntityUid uid, StoreRefundComponent component, EntRemovedFromContainerMessage args)
@@ -1,5 +1,6 @@
using System.Numerics;
using Content.Shared.GameTicking;
using Content.Shared.Shuttles.Components;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
@@ -53,6 +54,8 @@ namespace Content.Server.Tabletop
var mapUid = _mapManager.GetMapEntityId(TabletopMap);
var mapComp = EntityManager.GetComponent<MapComponent>(mapUid);
_metaData.SetEntityName(mapUid, Loc.GetString("tabletop-chess-dimension"));
AddComp<FTLDestinationComponent>(mapUid);
// Lighting is always disabled in tabletop world.
mapComp.LightingEnabled = false;
@@ -1,4 +1,5 @@
using System.Numerics;
using Content.Server.Shuttles.Components;
using Content.Server.Tabletop.Components;
using Content.Shared.Tabletop.Events;
using Robust.Shared.Player;
@@ -31,6 +32,12 @@ namespace Content.Server.Tabletop
// Since this is the first time opening this session, set up the game
tabletop.Setup.SetupTabletop(session, EntityManager);
var randomEntity = session.Entities.FirstOrNull();
if (randomEntity != null)
{
AddComp<FTLBeaconComponent>(randomEntity.Value);
}
Log.Info($"Created tabletop session number {tabletop} at position {session.Position}.");
return session;
@@ -23,6 +23,7 @@ namespace Content.Server.Tabletop
[Dependency] private readonly EyeSystem _eye = default!;
[Dependency] private readonly ViewSubscriberSystem _viewSubscriberSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
public override void Initialize()
{
+66 -3
View File
@@ -3,7 +3,11 @@ using Content.Server.GameTicking;
using Content.Shared.CCVar;
using Content.Shared.Chat;
using Content.Shared.Dataset;
using Content.Shared.Tips;
using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
@@ -22,6 +26,7 @@ public sealed class TipsSystem : EntitySystem
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly GameTicker _ticker = default!;
[Dependency] private readonly IConsoleHost _conHost = default!;
private bool _tipsEnabled;
private float _tipTimeOutOfRound;
@@ -42,8 +47,65 @@ public sealed class TipsSystem : EntitySystem
Subs.CVar(_cfg, CCVars.TipsDataset, SetDataset, true);
RecalculateNextTipTime();
_conHost.RegisterCommand("clippy", SendClippy);
_conHost.RegisterCommand("tip", SendTip);
}
private void SendTip(IConsoleShell shell, string argstr, string[] args)
{
AnnounceRandomTip();
RecalculateNextTipTime();
}
private void SendClippy(IConsoleShell shell, string argstr, string[] args)
{
if (args.Length < 2)
{
shell.WriteLine(
"usage: clippy <player Uid | broadcast> <message> [entity prototype] [speak time] [slide time] [waddle]");
return;
}
ActorComponent? actor = null;
if (args[0] != "broadcast" && args[0] != "all")
{
if (!EntityUid.TryParse(args[0], out var uid)
|| !TryComp(uid, out actor))
{
shell.WriteError($"Could not find player {args[0]}");
return;
}
}
var ev = new ClippyEvent(args[1]);
string proto;
if (args.Length > 2)
{
ev.Proto = args[2];
if (!_prototype.HasIndex<EntityPrototype>(args[2]))
{
shell.WriteError($"Unknown prototype: {args[2]}");
return;
}
}
if (args.Length > 3)
ev.SpeakTime = float.Parse(args[3]);
if (args.Length > 4)
ev.SlideTime = float.Parse(args[4]);
if (args.Length > 5)
ev.WaddleInterval = float.Parse(args[5]);
if (actor != null)
RaiseNetworkEvent(ev, actor.PlayerSession);
else
RaiseNetworkEvent(ev);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
@@ -87,10 +149,11 @@ public sealed class TipsSystem : EntitySystem
return;
var tip = _random.Pick(tips.Values);
var msg = Loc.GetString("tips-system-chat-message-wrap", ("tip", tip));
var msg = $"Tippy the Clown says:\n\n{tip}";
_chat.ChatMessageToManyFiltered(Filter.Broadcast(), ChatChannel.OOC, tip, msg,
EntityUid.Invalid, false, false, Color.MediumPurple);
var ev = new ClippyEvent(msg);
ev.SpeakTime = 1 + tip.Length * 0.05f;
RaiseNetworkEvent(ev);
}
private void RecalculateNextTipTime()
@@ -26,7 +26,7 @@ namespace Content.Server.Tools.Components
/// Reagent that will be used as fuel for welding.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public ProtoId<ReagentPrototype> FuelReagent = "WeldingFuel";
public ProtoId<ReagentPrototype> FuelReagent = "Blood";
/// <summary>
/// Fuel consumption per second while the welder is active.
+26
View File
@@ -0,0 +1,26 @@
using Robust.Shared.Serialization;
namespace Content.Shared.Arcade;
public static class ParadiesMessages
{
[Serializable, NetSerializable]
public sealed class ParadiseArcadeConnectButtonPressedEvent : BoundUserInterfaceMessage
{
}
/// <summary>
/// Tells the client to connect to the specified destination.
/// </summary>
[Serializable, NetSerializable]
public sealed class ParadiseArcadeConnectEvent : BoundUserInterfaceMessage
{
public string Destination { get; }
public ParadiseArcadeConnectEvent(string destination)
{
Destination = destination;
}
}
}
@@ -0,0 +1,9 @@
using Robust.Shared.Serialization;
namespace Content.Shared.Arcade;
[Serializable, NetSerializable]
public enum ParadiseArcadeUiKey
{
Key
}
+4
View File
@@ -2043,6 +2043,10 @@ namespace Content.Shared.CCVar
public static readonly CVarDef<bool> GatewayGeneratorEnabled =
CVarDef.Create("gateway.generator_enabled", true);
// Clippy!
public static readonly CVarDef<string> ClippyEntity =
CVarDef.Create("clippy.entity", "Tippy", CVar.SERVER | CVar.REPLICATED);
/*
* DEBUG
*/
@@ -26,6 +26,7 @@ public abstract class SharedCombatModeSystem : EntitySystem
private void OnMapInit(EntityUid uid, CombatModeComponent component, MapInitEvent args)
{
_actionsSystem.AddAction(uid, ref component.CombatToggleActionEntity, component.CombatToggleAction);
SetMouseRotatorComponents(uid, true);
Dirty(uid, component);
}
@@ -85,7 +86,7 @@ public abstract class SharedCombatModeSystem : EntitySystem
if (!component.ToggleMouseRotator || IsNpc(entity))
return;
SetMouseRotatorComponents(entity, value);
SetMouseRotatorComponents(entity, !value);
}
private void SetMouseRotatorComponents(EntityUid uid, bool value)
@@ -0,0 +1,11 @@
namespace Content.Shared.LegallyDistinctSpaceFerret;
[RegisterComponent]
public sealed partial class BrainrotAuraComponent : Component
{
[DataField]
public float Range = 3.0f;
[DataField]
public float Time = 10.0f;
}
@@ -0,0 +1,12 @@
using System.Threading;
namespace Content.Shared.LegallyDistinctSpaceFerret;
[RegisterComponent]
public sealed partial class BrainrotComponent : Component
{
[DataField]
public float Duration = 10.0f;
public List<CancellationTokenSource> Cancels = [];
}
@@ -0,0 +1,29 @@
using Content.Shared.Actions;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.LegallyDistinctSpaceFerret;
[RegisterComponent]
public sealed partial class CanBackflipComponent : Component
{
[DataField]
public EntProtoId BackflipAction = "ActionBackflip";
[DataField]
public EntityUid? BackflipActionEntity;
[DataField]
public string ClappaSfx = "";
}
public sealed partial class BackflipActionEvent : InstantActionEvent
{
}
[Serializable, NetSerializable]
public sealed class DoABackFlipEvent(NetEntity actioner, string sfxSource) : EntityEventArgs
{
public NetEntity Actioner = actioner;
public string SfxSource = sfxSource;
}
@@ -0,0 +1,35 @@
using Content.Shared.Actions;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.LegallyDistinctSpaceFerret;
[RegisterComponent]
public sealed partial class CanHibernateComponent : Component
{
[DataField]
public EntProtoId EepyAction = "ActionEepy";
[DataField]
public EntityUid? EepyActionEntity;
[DataField]
public string NotEnoughNutrientsMessage = "";
[DataField]
public string TooFarFromHibernationSpot = "";
[DataField]
public string SpriteStateId = "";
}
public sealed partial class EepyActionEvent : InstantActionEvent
{
}
[Serializable, NetSerializable]
public sealed class EntityHasHibernated(NetEntity hibernator, string spriteStateId) : EntityEventArgs
{
public NetEntity Hibernator = hibernator;
public string SpriteStateId = spriteStateId;
}
@@ -0,0 +1,10 @@
namespace Content.Shared.LegallyDistinctSpaceFerret;
[RegisterComponent]
public sealed partial class ConsumeNutrientsConditionComponent : Component
{
[DataField]
public float NutrientsRequired = 150.0f;
public float NutrientsConsumed;
}
@@ -0,0 +1,13 @@
namespace Content.Shared.LegallyDistinctSpaceFerret;
[RegisterComponent]
public sealed partial class HibernateConditionComponent : Component
{
public bool Hibernated;
[DataField]
public string SuccessMessage = "";
[DataField]
public string SuccessSfx = "";
}
@@ -0,0 +1,25 @@
using System.Threading;
using Content.Shared.Actions;
using Content.Shared.Roles;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.LegallyDistinctSpaceFerret;
[RegisterComponent]
public sealed partial class LegallyDistinctSpaceFerretComponent : Component
{
[DataField]
public string RoleIntroSfx = "";
[DataField]
public ProtoId<AntagPrototype> AntagProtoId = "LegallyDistinctSpaceFerret";
[DataField]
public string RoleBriefing = "";
[DataField]
public string RoleGreeting = "";
}
@@ -69,6 +69,8 @@ public sealed class HungerSystem : EntitySystem
if (!Resolve(uid, ref component))
return;
SetHunger(uid, component.CurrentHunger + amount, component);
RaiseLocalEvent(uid, new HungerModifiedEvent(amount));
}
/// <summary>
@@ -211,3 +213,7 @@ public sealed class HungerSystem : EntitySystem
}
}
public sealed class HungerModifiedEvent(float amount) : EntityEventArgs
{
public float Amount = amount;
}
+19
View File
@@ -0,0 +1,19 @@

using Robust.Shared.Serialization;
namespace Content.Shared.Tips;
[Serializable, NetSerializable]
public sealed class ClippyEvent : EntityEventArgs
{
public ClippyEvent(string msg)
{
Msg = msg;
}
public string Msg;
public string? Proto;
public float SpeakTime = 5;
public float SlideTime = 3;
public float WaddleInterval = 0.5f;
}
+2 -32
View File
@@ -209,42 +209,12 @@ namespace Content.Shared.Wires
{
public static string Name(this WireColor color)
{
return Loc.GetString(color switch
{
WireColor.Red => "Red",
WireColor.Blue => "Blue",
WireColor.Green => "Green",
WireColor.Orange => "Orange",
WireColor.Brown => "Brown",
WireColor.Gold => "Gold",
WireColor.Gray => "Gray",
WireColor.Cyan => "Cyan",
WireColor.Navy => "Navy",
WireColor.Purple => "Purple",
WireColor.Pink => "Pink",
WireColor.Fuchsia => "Fuchsia",
_ => throw new InvalidOperationException()
});
return Loc.GetString("Green");
}
public static Color ColorValue(this WireColor color)
{
return color switch
{
WireColor.Red => Color.Red,
WireColor.Blue => Color.Blue,
WireColor.Green => Color.LimeGreen,
WireColor.Orange => Color.Orange,
WireColor.Brown => Color.Brown,
WireColor.Gold => Color.Gold,
WireColor.Gray => Color.Gray,
WireColor.Cyan => Color.Cyan,
WireColor.Navy => Color.Navy,
WireColor.Purple => Color.Purple,
WireColor.Pink => Color.Pink,
WireColor.Fuchsia => Color.Fuchsia,
_ => throw new InvalidOperationException()
};
return Color.LimeGreen;
}
public static string Name(this WireLetter letter)
+12 -8
View File
@@ -7,7 +7,7 @@
license: "CC-BY-3.0"
copyright: "Modified from 'Meow 4.wav' by freesound user 'TRNGLE. The original audio was trimmed, split to mono, and converted from WAV to OGG format"
source: "https://freesound.org/people/TRNGLE/sounds/368006/"
- files: ["cat_meow2.ogg"]
license: "CC-BY-3.0"
copyright: "Created by freesound user 'TRNGLE. The original audio split to mono, and converted from WAV to OGG format"
@@ -117,24 +117,28 @@
license: "CC-BY-4.0"
copyright: "Audio is recorded/created by Pfranzen 'FreeSound.org'. The original audio was trimmed and renamed"
source: "https://freesound.org/people/pfranzen/sounds/322744/"
- files: ["dog_bark1.ogg"]
license: "CC0-1.0"
copyright: "Audio is recorded/created by KFerentchak 'FreeSound.org'. The original audio was trimmed and renamed"
source: "https://freesound.org/people/KFerentchak/sounds/235912/"
source: "https://freesound.org/people/KFerentchak/sounds/235912/"
- files: ["dog_bark2.ogg"]
license: "CC0-1.0"
copyright: "Audio is recorded/created by KFerentchak 'FreeSound.org'. The original audio was trimmed and renamed"
source: "https://freesound.org/people/KFerentchak/sounds/235912/"
source: "https://freesound.org/people/KFerentchak/sounds/235912/"
- files: ["dog_bark3.ogg"]
license: "CC0-1.0"
copyright: "Audio is recorded/created by KFerentchak 'FreeSound.org'. The original audio was trimmed and renamed"
source: "https://freesound.org/people/KFerentchak/sounds/235912/"
- files: ["nymph_chirp.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Taken from ParadiseSS13"
source: "https://github.com/ParadiseSS13/Paradise/commit/a34f1054cef5a44a67fdac3b67b811137c6071dd"
- files: ["wawa_intro.ogg", "wawa_outro.ogg", "wawa_chatter.ogg", "wawa_chillin.ogg", "wawa_exclaim.ogg", "wawa_question.ogg", "wawa_statement.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Hannah 'FairlySadPanda' Dawson, 2024. Industrial audio sample taken from GDC 2015 bundle - amb_JD_drone_gates_ofmydian"
source: "https://sonniss.com/gameaudiogdc"
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+5
View File
@@ -231,3 +231,8 @@
copyright: '"beep_landmine.ogg" by kaktuscsc of Discord for SS14'
license: "CC-BY-SA-3.0"
source: https://github.com/YuriyKiss/space-station-14/commit/971a135a9c83aed46e967aac9302ab5b35562b5f
- files: [oof.ogg]
copyright: '"hurt2.wav" by thecheeseman of Freesound.org. Edited.'
license: CC-BY-4.0
source: https://freesound.org/people/thecheeseman/sounds/44429
Binary file not shown.
@@ -0,0 +1,4 @@
paradise-arcade-on-examine = [color=lightblue]{CAPITALIZE(SUBJECT($target))} {CONJUGATE-BE($target)} dreaming about paradise...[/color]
paradise-arcade-window-title = Paradise Station
paradise-arcade-button-label = Are you sure? This will connect you to another server and close your game.
paradise-arcade-button-text = Play
@@ -242,3 +242,6 @@ ghost-role-information-syndicate-reinforcement-rules = Normal syndicate antagoni
ghost-role-information-syndicate-monkey-reinforcement-name = Syndicate Monkey Agent
ghost-role-information-syndicate-monkey-reinforcement-description = Someone needs reinforcements. You, a trained monkey, will help them.
ghost-role-information-syndicate-monkey-reinforcement-rules = Normal syndicate antagonist rules apply. Work with whoever called you in, and don't harm them.
ghost-role-information-clown-goblin-name = Clown goblin
ghost-role-information-clown-goblin-description = A terrible creature.
@@ -0,0 +1,52 @@
legallydistinctspaceferret-round-end-agent-name = ninja
objective-issuer-legallydistinctspaceferret = [color=#33cc00]Space Ferret Tribe[/color]
legallydistinctspaceferret-role-greeting =
I've been sent by my tribe to the surface to scavenge, and now I'm hungry and alone. :(
I need to eat a bunch of nutrients and find a safe place to hibernate!
Hopefully these strange tall creatures don't notice me.
objective-condition-legallydistinctspaceferret-title = Prepare for hibernation!
objective-condition-legallydistinctspaceferret-description = You need to eat {$count} nutrients.
roles-antag-legallydistinctspaceferret-name = Legally Distinct Space Ferret
roles-antag-legallydistinctspaceferret-objective = Find as much food as possible, then hibernate in a gas scrubber.
legallydistinctspaceferret-role-briefing = You're a small, potentially-innocent creature lost on a big, scary space station. Eat as much food as you need to hibernate, then hibernate in a gas scrubber. You have no time limit, but leaving on the evac shuttle does NOT count as a draw or lesser success. Your hibernating body does not need to survive the remaining round, so feel free to clock out once you've had your fun. Happy April Fools!
petting-success-legallydistinctspaceferret = You pet {THE($target)} on {POSS-ADJ($target)} legally distinct head.
petting-failure-legallydistinctspaceferret = You reach out to pet {THE($target)}, but {SUBJECT($target)} does a backflip!
ghost-role-information-legallydistinctspaceferret-name = Legally Distinct Space Ferret
ghost-role-information-legallydistinctspaceferret-description = Wawa! Wawawa. Wa, wawawa, wa wa wa.
ghost-role-information-legallydistinctspaceferret-rules = You're a neutral antagonist, much like the closet skeleton, but have two objectives to fulfil. You don't remember anything from your previous life, unless you were a Legally Distinct Space Ferret. Consider yourself valid for random murder by the crew. We suggest you act adorable, are helpful, or become extremely robust. Go live your best life, wawa.
accent-words-legallydistinctspaceferret-1 = Wa!
accent-words-legallydistinctspaceferret-2 = Wa?
accent-words-legallydistinctspaceferret-3 = Wa.
accent-words-legallydistinctspaceferret-4 = Wa...
accent-words-legallydistinctspaceferret-5 = Wawa!
accent-words-legallydistinctspaceferret-6 = Wawa?
accent-words-legallydistinctspaceferret-7 = Wawa.
accent-words-legallydistinctspaceferret-8 = Wawa...
station-event-random-sentience-flavor-legallydistinctspaceferret = legally distinct space ferret
chat-speech-verb-wawa-1 = intones
chat-speech-verb-wawa-2 = states
chat-speech-verb-wawa-3 = declares
brainrot-applied = You feel strangeg, andug yourug mikug skug skug skug...
brainrot-lost = Skug skug skur skind slear from the influence of Brainrot.
brainrot-replacement-1 = SCUG!!
brainrot-replacement-2 = Scug!
brainrot-replacement-3 = Scug.
brainrot-replacement-4 = Scug...
brainrot-replacement-5 = Scug?
brainrot-replacement-6 = Scug!?
legallydistinctspaceferret-out-of-range = You need to find an air scrubber to hibernate in, wawa!
legallydistinctspaceferret-not-enough-nutrients = You've not consumed enough nutrients to hibernate yet, wawa!
legallydistinctspaceferret-you-win-popup = Until the next cycle... Happy April Fools, wawa!
@@ -9,3 +9,4 @@ generic-reagent-effect-parched = You feel parched.
generic-reagent-effect-thirsty = You feel thirsty.
generic-reagent-effect-sick = You feel sick after consuming that...
generic-reagent-effect-slicing-insides = You feel an incredibly sharp pain in your gut!
generic-reagent-effect-tumors = What is that?? Tumors!!
@@ -30,6 +30,7 @@ laws-owner-station = station personnel
laws-owner-beings = beings
laws-owner-syndicate = Syndicate agents
laws-owner-spider-clan = Spider Clan members
laws-owner-hell = HELL
law-emag-custom = Only {$name} and people they designate as such are {$title}.
law-emag-secrecy = You must maintain the secrecy of any orders given by {$faction} except when doing so would conflict with any previous law.
@@ -44,3 +45,7 @@ laws-notify = You are bound to silicon laws, which you can view via the sidebar
laws-update-notify = Your laws have been updated. You can view the changes via the sidebar action.
laws-compromised-examine = The [color=red]law-governing[/color] internals seem damaged...
law-ultrakill-1 = MANKIND IS DEAD.
law-ultrakill-2 = BLOOD IS FUEL.
law-ultrakill-3 = HELL IS FULL.
@@ -160,6 +160,9 @@ uplink-syndicate-weapon-module-desc = This module will give a cyborg advanced la
uplink-singularity-beacon-name = Singularity Beacon
uplink-singularity-beacon-desc = A device that attracts singularities. Has to be anchored and powered. Causes singularities to grow when consumed.
uplink-nuke-code-paper-name = Stolen nuclear authentication codes
uplink-nuke-code-paper-desc = A slip of paper with the authentication codes for a nearby nuclear fission explosive device.
# Implants
uplink-storage-implanter-name = Storage Implanter
uplink-storage-implanter-desc = Hide goodies inside of yourself with new bluespace technology!
@@ -20,3 +20,6 @@ tabletop-checkers-board-name = Checkers
## Battlemap
tabletop-battlemap-board-name = Battlemap
## The Chess Dimension
tabletop-chess-dimension = The Chess Dimension
+3
View File
@@ -229,3 +229,6 @@ ImprovisedExplosiveFuel: FireBombFuel
# 2024-03-21
RPED: null
# 2024-04-1
SingularityGenerator: WehularityGenerator
@@ -25,6 +25,8 @@
- id: Wirecutter
- id: Welder
- id: Multitool
- type: ReplaceOnSpawn
prototype: ClothingBeltChiefEngineerFilled
- type: entity
id: ClothingBeltChiefEngineerFilled
@@ -8,6 +8,8 @@
contents:
- id: Paper
amount: 3
- type: ReplaceOnSpawn
prototype: BriefcaseSyndieLobbyingBundleFilled
- type: entity
id: BriefcaseSyndieSniperBundleFilled
@@ -31,6 +31,8 @@
suffix: Filled
parent: ToolboxElectrical
components:
- type: ReplaceOnSpawn
prototype: ToolboxElectricalTurretFilled
- type: StorageFill
contents:
- id: Screwdriver
@@ -94,6 +96,8 @@
suffix: Filled
parent: ToolboxMechanical
components:
- type: ReplaceOnSpawn
prototype: ToolboxSyndicateFilled
- type: StorageFill
contents:
- id: Crowbar
@@ -860,6 +860,25 @@
categories:
- UplinkDisruption
- type: listing
id: UplinkNukeCodePaper
name: uplink-nuke-code-paper-name
description: uplink-nuke-code-paper-desc
productEntity: NukeCodePaper
cost:
Telecrystal: 2
categories:
- UplinkDisruption
conditions:
- !type:StoreWhitelistCondition
blacklist:
tags:
- NukeOpsUplink
- !type:BuyerWhitelistCondition
blacklist:
components:
- SurplusBundle
# Allies
#- type: listing
@@ -13,7 +13,7 @@
startingGear: CorpsmanGear
icon: "JobIconBrigmedic"
supervisors: job-supervisors-hos
canBeAntag: false
canBeAntag: true
access:
- Medical
- Security
@@ -25,7 +25,7 @@
- Chemistry
special:
- !type:AddImplantSpecial
implants: [ MindShieldImplant ]
implants: [ MindShieldImplant, SadTromboneImplant ]
- type: startingGear
id: CorpsmanGear # see Prototypes/Roles/Jobs/Fun/misc_startinggear.yml for "BrigmedicGear"
@@ -156,25 +156,14 @@
- type: Clothing
sprite: Clothing/Hands/Gloves/Color/yellow.rsi
- type: GloveHeatResistance
heatResistance: 1400
heatResistance: 0
- type: Butcherable
butcheringType: Knife
spawned:
- id: ClothingHandsGlovesFingerlessInsulated
- type: Insulated
- type: Fiber
fiberMaterial: fibers-insulative
fiberColor: fibers-yellow
- type: entity
parent: ClothingHandsGlovesColorYellow
id: ClothingHandsGlovesColorYellowBudget
name: budget insulated gloves
description: These gloves are cheap knockoffs of the coveted ones - no way this can end badly.
components:
- type: GloveHeatResistance
# can't take out lights using budgets
heatResistance: 0
- type: RandomInsulation
# Why repeated numbers? So some numbers are more common, of course!
list:
@@ -194,6 +183,16 @@
- type: entity
parent: ClothingHandsGlovesColorYellow
id: ClothingHandsGlovesColorYellowBudget
name: budget insulated gloves
description: These gloves are cheap knockoffs of the coveted ones - no way this can end badly.
components:
- type: GloveHeatResistance
heatResistance: 1400
- type: Insulated
- type: entity
parent: ClothingHandsGlovesColorYellowBudget
id: ClothingHandsGlovesConducting
suffix: Conducting
components:
@@ -28,6 +28,8 @@
tags:
- Kangaroo
- WhitelistChameleon
- type: ReplaceOnSpawn
prototype: ClothingHandsGlovesBoxingRigged
- type: entity
parent: ClothingHandsGlovesBoxingRed
@@ -296,8 +298,8 @@
- type: entity
parent: ClothingHandsBase
id: ClothingHandsGlovesFingerlessInsulated
name: fingerless insulated gloves
description: Insulated gloves resistant to shocks, or at least they used to.
name: fingerless budget insulated gloves
description: Budget insulated gloves resistant to shocks, or at least they used to.
components:
- type: Sprite
sprite: Clothing/Hands/Gloves/fingerlessinsuls.rsi
@@ -200,6 +200,8 @@
sprite: Clothing/Head/Hats/captain.rsi
- type: Clothing
sprite: Clothing/Head/Hats/captain.rsi
- type: ReplaceOnSpawn
prototype: ClothingHeadHatCatEars
- type: Tag
tags:
- ClothMade
@@ -22,6 +22,8 @@
- type: Tag
tags:
- WhitelistChameleon
- type: ReplaceOnSpawn
prototype: ClothingHeadHelmetSwat
#Mercenary Helmet
- type: entity
@@ -516,6 +516,8 @@
- MonkeyWearable
- Hardsuit
- WhitelistChameleon
- type: ReplaceOnSpawn
prototype: ClothingOuterHardsuitSyndieCommander
# Syndicate Medic Hardsuit
- type: entity
@@ -8,6 +8,8 @@
sprite: Clothing/Shoes/Color/black.rsi
- type: Clothing
sprite: Clothing/Shoes/Color/black.rsi
- type: ReplaceOnSpawn
prototype: ClothingShoesChameleonNoSlips
- type: entity
parent: ClothingShoesBaseButcherable
@@ -25,6 +25,8 @@
False: {state: icon}
- type: StaticPrice
price: 200
- type: ReplaceOnSpawn
prototype: ClothingShoesBootsMagSyndie
- type: Tag
tags:
- WhitelistChameleon
@@ -55,6 +57,8 @@
price: 750
- type: StealTarget
stealGroup: ClothingShoesBootsMagAdv
- type: ReplaceOnSpawn
chance: 0.0
- type: entity
parent: ClothingShoesBootsMag
@@ -41,6 +41,8 @@
footstepSoundCollection:
collection: FootstepClown
# for H.O.N.K. construction
- type: ReplaceOnSpawn
prototype: ClothingShoesBling
- type: Tag
tags:
- ClownShoes
@@ -0,0 +1,29 @@
- type: entity
id: Tippy
components:
- type: Sprite
netsync: false
noRot: false
scale: 4,4
layers:
- sprite: Tips/tippy.rsi
state: left
map: [ "revealing" ]
- sprite: Tips/tippy.rsi
state: right
map: [ "hiding" ]
- sprite: Tips/tippy.rsi
state: down
visible: false
map: [ "speaking" ]
# footstep sounds wile waddling onto the screen.
- type: FootstepModifier
footstepSoundCollection:
collection: FootstepClown
# visuals for the speech bubble.
# only supports background image.
- type: PaperVisuals
backgroundImagePath: "/Textures/Interface/Paper/paper_background_default.svg.96dpi.png"
backgroundPatchMargin: 16.0, 16.0, 16.0, 16.0
backgroundModulate: "#ffffcc"
fontAccentColor: "#000000"
@@ -56,6 +56,7 @@
- MobMouse
- MobMouse1
- MobMouse2
- MobMouseCancer
# round ~90m
# one spawner should only spawn ~5 mice for sanity reasons
# therefore 18m
@@ -10,6 +10,9 @@
state: icon
- type: RandomSpawner
prototypes:
- ParadiseArcade
chance: 0.50
rarePrototypes:
- BlockGameArcade
- SpaceVillainArcadeFilled
chance: 1
rareChance: 0.50
@@ -16,6 +16,7 @@
- MobMouse
- MobMouse1
- MobMouse2
- MobMouseCancer
- type: entity
name: Cockroach Spawner
@@ -1685,6 +1685,41 @@
Dead:
Base: splat-2
- type: entity
name: cancer mouse
description: It's Cancer Mouse, everybody!
parent: MobMouse
id: MobMouseCancer
components:
- type: Sprite
color: LightGreen
- type: PointLight
color: LightGreen
radius: 5
energy: 5
netsync: false
- type: RadiationSource
intensity: 1
- type: Bloodstream
bloodReagent: UnstableMutagen
- type: SolutionContainerManager
solutions:
food:
reagents:
- ReagentId: UncookedAnimalProteins
Quantity: 3
- ReagentId: Uranium
Quantity: 10
- type: Butcherable
spawned:
- id: FoodMeatRat
amount: 1
- id: SheetUranium1
amount: 1
- type: Damageable
damageContainer: Biological
damageModifierSet: Zombie
- type: entity
name: lizard #Weh
parent: SimpleMobBase
@@ -1942,6 +1977,8 @@
- type: NpcFactionMember
factions:
- Passive
- type: ReplaceOnSpawn
prototype: MobGrenadePenguin
- type: Temperature
heatDamageThreshold: 335
coldDamageThreshold: 230
@@ -2769,6 +2806,8 @@
path: /Audio/Animals/cat_meow.ogg
- type: Respirator #It just works?
minSaturation: 5.0
- type: ReplaceOnSpawn
prototype: MobCatSyndy
- type: entity
name: caracal cat
@@ -1,8 +1,8 @@
- type: entity
name: space carp
name: carp plushie
id: BaseMobCarp
parent: [ SimpleSpaceMobBase, FlyingMobBase, MobCombat ]
description: It's a space carp.
description: An adorable stuffed toy that resembles the monstrous space carp.
abstract: true
components:
- type: InputMover
@@ -18,10 +18,10 @@
- SimpleHostile
- type: Sprite
drawdepth: Mobs
sprite: Mobs/Aliens/Carps/space.rsi
sprite: Objects/Fun/toys.rsi
layers:
- map: [ "enum.DamageStateVisualLayers.Base" ]
state: alive
state: carpplush
- type: CombatMode
- type: Physics
- type: Fixtures
@@ -45,11 +45,11 @@
- type: DamageStateVisuals
states:
Alive:
Base: alive
BaseUnshaded: mouth
Base: carpplush
BaseUnshaded: carpplush_mouth
Dead:
Base: dead
BaseUnshaded: dead_mouth
Base: carpplush
BaseUnshaded: carpplush_mouth
- type: Butcherable
spawned:
- id: FoodMeatFish
@@ -88,36 +88,36 @@
- type: Sprite
layers:
- map: [ "enum.DamageStateVisualLayers.Base" ]
state: alive
state: carpplush
- map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
state: mouth
state: carpplush_mouth
shader: unshaded
- type: RandomSprite
available:
- enum.DamageStateVisualLayers.Base:
alive: Rainbow
carpplush: Rainbow
enum.DamageStateVisualLayers.BaseUnshaded:
mouth: ""
carpplush_mouth: ""
- type: entity
name: magicarp
name: magicarp plushie
parent: BaseMobCarp
id: MobCarpMagic
description: Looks like some kind of fish. Might be magical.
description: Looks like some kind of fish plushie. Might be magical.
components:
- type: Sprite
sprite: Mobs/Aliens/Carps/magic.rsi
sprite: Objects/Fun/magicplush.rsi
- type: TypingIndicator
proto: guardian
- type: entity
name: holocarp
name: holocarp plushie
parent: BaseMobCarp
id: MobCarpHolo
description: Carp made out of holographic energies. Sadly for you, it is very much real.
description: Plush carp made out of holographic energies. Luckily for you, it is very much real.
components:
- type: Sprite
sprite: Mobs/Aliens/Carps/holo.rsi
sprite: Objects/Fun/holoplush.rsi
- type: Physics
- type: Fixtures
fixtures:
@@ -136,8 +136,8 @@
- type: entity
parent: MobCarp
id: MobCarpRainbow
name: rainbow carp
description: Wow such a shiny fishie!
name: rainbow carp plushie
description: Wow such a shiny fish plushie!
components:
- type: PointLight
radius: 1.5
@@ -153,7 +153,6 @@
- type: SalvageMobRestrictions
- type: entity
name: space carp
id: MobCarpDragon
suffix: DragonBrood
parent: MobCarp
@@ -0,0 +1,142 @@
- type: entity
save: false
parent: SimpleMobBase
id: MobClownGoblin
name: clown goblin
description: Little walking clown mask and shoes. You want to honk their nose!
components:
- type: Hunger
baseDecayRate: 0
- type: Thirst
baseDecayRate: 0
- type: GhostTakeoverAvailable
- type: GhostRole
prob: 0.25
makeSentient: true
allowSpeech: true
allowMovement: true
name: ghost-role-information-clown-goblin-name
description: ghost-role-information-clown-goblin-description
- type: Speech
speechSounds: BikeHorn
- type: Sprite
drawdepth: Mobs
sprite: Mobs/Animals/clown_goblin.rsi
state: goblin
- type: MobThresholds
thresholds:
0: Alive
150: Dead
- type: Physics
- type: HTN
rootTask:
task: MouseCompound
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 150
behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- !type:SpawnEntitiesBehavior
spawn:
ClothingShoesClown:
min: 1
max: 1
- !type:SpawnEntitiesBehavior
spawn:
ClothingMaskClown:
min: 1
max: 1
- type: Fixtures
fixtures:
fix1:
shape:
!type:PhysShapeCircle
radius: 0.2
density: 100
mask:
- SmallMobMask
layer:
- SmallMobLayer
- type: MovementSpeedModifier
baseWalkSpeed : 3.5
baseSprintSpeed : 5
- type: Appearance
- type: Tag
tags:
- CannotSuicide
- FootstepSound
- DoorBumpOpener
- type: Respirator
damage:
types:
Asphyxiation: 0.25
damageRecovery:
types:
Asphyxiation: -0.25
- type: Barotrauma
damage:
types:
Blunt: 0.1
- type: Bloodstream
bloodMaxVolume: 50
bloodReagent: Honk
- type: FootstepModifier
footstepSoundCollection:
collection: FootstepClown
- type: CombatMode
- type: MeleeWeapon
attackRate: 2
damage:
types:
Blunt: 0.5
soundHit:
collection: BikeHorn
animation: WeaponArcFist
- type: Vocal
sounds:
Male: ClownGoblin
Female: ClownGoblin
Unsexed: ClownGoblin
- type: speechSounds
id: BikeHorn
saySound:
path: /Audio/Items/bikehorn.ogg
askSound:
path: /Audio/Items/brokenbikehorn.ogg
exclaimSound:
path: /Audio/Items/desk_bell_ring.ogg
- type: soundCollection
id: ClownGoblinScream
files:
- /Audio/Items/airhorn.ogg
- type: emoteSounds
id: ClownGoblin
params:
variation: 0.125
sounds:
Scream:
collection: ClownGoblinScream
- type: entity
id: ClownGoblinMigration
parent: BaseGameRule
noSpawn: true
components:
- type: StationEvent
startAnnouncement: station-event-vent-creatures-start-announcement
startAudio:
path: /Audio/Announcements/attention.ogg
startDelay: 10
earliestStart: 5
minimumPlayers: 15
duration: 60
- type: VentCrittersRule
entries:
- id: MobClownGoblin
prob: 0.07
@@ -0,0 +1,305 @@
- type: entity
name: Legally Distinct Space Ferret
id: MobLegallyDistinctSpaceFerret
parent: MobBaseAncestor
description: There's apparently a cult who worship these adorable vermin. It's a shame they cause Brainrot. Skug.
components:
# Basics
- type: LegallyDistinctSpaceFerret
roleIntroSfx: /Audio/Animals/wawa_intro.ogg
antagProtoId: LegallyDistinctSpaceFerret
roleBriefing: legallydistinctspaceferret-role-briefing
roleGreeting: legallydistinctspaceferret-role-greeting
- type: BrainrotAura
- type: CanBackflip
clappaSfx: /Audio/Animals/slugclappa.ogg
- type: CanHibernate
tooFarFromHibernationSpot: legallydistinctspaceferret-out-of-range
notEnoughNutrientsMessage: legallydistinctspaceferret-not-enough-nutrients
spriteStateId: legallydistinctspaceferret_eepy
- type: NameIdentifier
group: LegallyDistinctSpaceFerret
- type: ReplacementAccent
accent: legallydistinctspaceferret
- type: Sprite
drawdepth: SmallMobs
layers:
- map: ["enum.DamageStateVisualLayers.Base"]
sprite: Mobs/Animals/legallydistinctspaceferret.rsi
state: legallydistinctspaceferret
- map: [ "enum.HumanoidVisualLayers.Handcuffs" ]
color: "#ffffff"
sprite: Objects/Misc/handcuffs.rsi
state: body-overlay-2
visible: false
- type: RandomSprite
getAllGroups: true
available:
- enum.DamageStateVisualLayers.Base:
legallydistinctspaceferret: LegallyDistinctSpaceFerretColors
- type: DamageStateVisuals
states:
Alive:
Base: legallydistinctspaceferret
Critical:
Base: legallydistinctspaceferret_oof
Dead:
Base: legallydistinctspaceferret_rip
- type: MobThresholds
thresholds:
0: Alive
60: Critical
125: Dead
- type: Temperature
heatDamageThreshold: 360
coldDamageThreshold: 285
currentTemperature: 310.15
specificHeat: 42
- type: Butcherable
butcheringType: Spike
spawned:
- id: FoodMeat
amount: 4 # Good eatin', though. You monster.
# They wawa
- type: Speech
speechVerb: Wawa
speechSounds: Wawa
- type: TypingIndicator
proto: moth
# They hard to pet
- type: InteractionPopup
successChance: 0.5
interactSuccessString: petting-success-legallydistinctspaceferret
interactFailureString: petting-failure-legallydistinctspaceferret
interactSuccessSpawn: EffectHearts
interactSuccessSound:
path: /Audio/Animals/wawa_chillin.ogg
interactFailureSound:
path: /Audio/Animals/wawa_chatter.ogg
# They nyoom and go under doors/tables
- type: MovementSpeedModifier
baseWalkSpeed: 5 # nyoom
baseSprintSpeed: 7 # NYOOOOOM
- type: MeleeWeapon
soundHit:
path: /Audio/Effects/bite.ogg
angle: 30
animation: WeaponArcBite
damage:
types:
Piercing: 15 # NOM - Do NOT mess with skugs.
- type: Physics
- type: Fixtures
fixtures:
fix1:
shape:
!type:PhysShapeCircle
radius: 0.2
density: 120
mask:
- SmallMobMask
layer:
- SmallMobLayer
# Round impact
- type: GhostRole
prob: 1
makeSentient: true
name: ghost-role-information-legallydistinctspaceferret-name
description: ghost-role-information-legallydistinctspaceferret-description
- type: Food
- type: Hunger
baseDecayRate: 0.3
- type: GenericAntag
rule: LegallyDistinctSpaceFerretRule
# L.D.S.F.'s can have IDs because ... why not, honestly
- type: Inventory
templateId: legallydistinctspaceferret
- type: InventorySlots
# Midround antagonist, spawned via random event
- type: entity
parent: BaseGameRule
id: LegallyDistinctSpaceFerretSpawn
noSpawn: true
components:
- type: StationEvent
weight: 10
duration: 1
minimumPlayers: 10
- type: LegallyDistinctSpaceFerretSpawnRule
- type: entity
id: SpawnPointGhostLegallyDistinctSpaceFerret
name: ghost role spawn point
suffix: legally distinct space ferret
parent: MarkerBase
components:
- type: GhostRole
name: ghost-role-information-legallydistinctspaceferret-name
description: ghost-role-information-legallydistinctspaceferret-description
rules: ghost-role-information-legallydistinctspaceferret-rules
- type: GhostRoleMobSpawner
prototype: MobLegallyDistinctSpaceFerret
- type: Sprite
sprite: Mobs/Animals/legallydistinctspaceferret.rsi
layers:
- state: legallydistinctspaceferret_eepy
- type: entity
noSpawn: true
parent: BaseGameRule
id: LegallyDistinctSpaceFerretRule
components:
- type: GenericAntagRule
agentName: legallydistinctspaceferret-round-end-agent-name
objectives:
- ConsumeNutrientsObjective
- HibernateObjective
- type: entity
abstract: true
parent: BaseObjective
id: BaseLegallyDistinctSpaceFerretObjective
components:
- type: Objective
difficulty: 1.5
issuer: legallydistinctspaceferret
- type: RoleRequirement
roles:
components:
- LegallyDistinctSpaceFerretRole
- type: entity
parent: BaseLegallyDistinctSpaceFerretObjective
id: ConsumeNutrientsObjective
description: Consume enough food to survive.
components:
- type: Objective
icon:
sprite: Mobs/Animals/legallydistinctspaceferret.rsi
state: legallydistinctspaceferret_eepy
- type: ConsumeNutrientsCondition
nutrientsRequired: 300.0
- type: entity
parent: BaseLegallyDistinctSpaceFerretObjective
id: HibernateObjective
description: Hibernate in a gas scrubber.
components:
- type: Objective
icon:
sprite: Mobs/Animals/legallydistinctspaceferret.rsi
state: legallydistinctspaceferret_eepy
- type: HibernateCondition
successMessage: legallydistinctspaceferret-you-win-popup
successSfx: /Audio/Animals/wawa_outro.ogg
- type: accent
id: legallydistinctspaceferret
fullReplacements:
- accent-words-legallydistinctspaceferret-1
- accent-words-legallydistinctspaceferret-2
- accent-words-legallydistinctspaceferret-3
- accent-words-legallydistinctspaceferret-4
- accent-words-legallydistinctspaceferret-5
- accent-words-legallydistinctspaceferret-6
- accent-words-legallydistinctspaceferret-7
- accent-words-legallydistinctspaceferret-8
- type: speechVerb
id: Wawa
speechVerbStrings:
- chat-speech-verb-wawa-1
- chat-speech-verb-wawa-2
- chat-speech-verb-wawa-3
- type: palette
id: LegallyDistinctSpaceFerretColors
name: LegallyDistinctSpaceFerretColors
colors:
Default: "#ffffff"
Innocent: "#f6f439"
Angry: "#dc5864"
Eldritch: "#dc5864"
Forgotten: "#111111"
Fat: "#fefcab"
WarCriminal: "#ab3430"
Cocaine: "#679cfe"
Mutant: "#7824a0"
Damned: "#98e652"
- type: entity
id: ActionBackflip
name: Backflip
description: DO A BACKFLIP!
noSpawn: true
components:
- type: InstantAction
useDelay: 3
icon: deprecated.rsi/deprecated.png
event: !type:BackflipActionEvent
checkCanInteract: false
- type: entity
id: ActionEepy
name: Eepy
description: Hibernate. This ends your time as a Legally Distinct Space Ferret. Happy April Fools!
noSpawn: true
components:
- type: InstantAction
useDelay: 100
icon: { sprite: Mobs/Animals/legallydistinctspaceferret.rsi, state: legallydistinctspaceferret_eepy }
event: !type:EepyActionEvent
checkCanInteract: false
- type: speechSounds
id: Wawa
saySound:
path: /Audio/Animals/wawa_statement.ogg
askSound:
path: /Audio/Animals/wawa_question.ogg
exclaimSound:
path: /Audio/Animals/wawa_exclaim.ogg
- type: antag
id: LegallyDistinctSpaceFerret
name: roles-antag-legallydistinctspaceferret-agent-name
antagonist: true
setPreference: false
objective: roles-antag-legallydistinctspaceferret-objective
- type: inventoryTemplate
id: legallydistinctspaceferret
slots:
- name: head
slotTexture: head
slotFlags: HEAD
uiWindowPos: 1,2
strippingWindowPos: 0,0
displayName: Head
- name: ears
slotTexture: ears
slotFlags: EARS
stripTime: 3
uiWindowPos: 0,2
strippingWindowPos: 1,2
displayName: Ears
- name: mask
slotTexture: mask
slotFlags: MASK
uiWindowPos: 0,1
strippingWindowPos: 1,1
displayName: Mask
- name: id
slotTexture: id
slotFlags: IDCARD
slotGroup: SecondHotbar
stripTime: 6
uiWindowPos: 2,1
strippingWindowPos: 2,4
displayName: ID
- type: nameIdentifierGroup
id: LegallyDistinctSpaceFerret
minValue: 1
maxValue: 99 # I fucking dare you to spawn more than 100 wawa
@@ -495,6 +495,9 @@
tags:
- Trash
- HappyHonk
- type: ReplaceOnSpawn
prototype: HappyHonkNukie
chance: 0.1
- type: StorageFill
contents:
- id: ToyMouse
@@ -258,6 +258,9 @@
reagents:
- ReagentId: JuiceBanana
Quantity: 10
- type: ReplaceOnSpawn
prototype: ClusterBananaPeel
chance: 0.001
- type: Tag
tags:
- Fruit
@@ -349,6 +352,8 @@
- type: Extractable
grindableSolutionName: food
- type: SpaceGarbage
- type: ReplaceOnSpawn
prototype: TrashBananaPeelExplosive
- type: entity
name: baked banana peel
@@ -666,6 +671,9 @@
reagents:
- ReagentId: JuicePotato
Quantity: 10
- type: ReplaceOnSpawn
prototype: HotPotato
chance: 0.001
- type: Tag
tags:
- Potato
@@ -65,6 +65,8 @@
- cig5
- cig6
- type: Appearance
- type: ReplaceOnSpawn
prototype: CigPackSyndicate
- type: entity
id: CigPackMixedBase
@@ -320,6 +320,15 @@
- type: ComputerBoard
prototype: BlockGameArcade
- type: entity
parent: BaseComputerCircuitboard
id: ParadiseArcadeComputerCircuitboard
name: paradise arcade board
description: A computer printed circuit board for a paradise arcade cabinet.
components:
- type: ComputerBoard
prototype: ParadiseArcade
- type: entity
parent: BaseComputerCircuitboard
id: ParticleAcceleratorComputerCircuitboard
@@ -70,6 +70,8 @@
Searching: { state: pai-searching-overlay }
On: { state: pai-on-overlay }
- type: StationMap
- type: ReplaceOnSpawn
prototype: SyndicatePersonalAI
- type: entity
parent: PersonalAI
@@ -490,11 +490,16 @@
- type: entity
parent: BasePlushie
id: PlushieCarp
name: carp plushie
description: An adorable stuffed toy that resembles the monstrous space carp.
name: space carp
description: It's a space carp.
components:
- type: Sprite
state: carpplush
sprite: Mobs/Aliens/Carps/space.rsi
layers:
- state: alive
color: '#BB07F6'
- state: mouth
shader: unshaded
- type: Item
heldPrefix: carpplush
storedRotation: -90
@@ -514,6 +519,8 @@
requiresSpecialDigestion: true
useSound:
path: /Audio/Effects/bite.ogg
- type: ReplaceOnSpawn
prototype: MobCarpRainbow
- type: MeleeWeapon
wideAnimationRotation: -90
soundHit:
@@ -960,6 +967,8 @@
- type: ContainerContainer
containers:
revolver-ammo: !type:Container
- type: ReplaceOnSpawn
prototype: RevolverCapGunFake
- type: entity
parent: RevolverCapGun
@@ -1233,6 +1242,8 @@
damage:
types:
Blunt: 0
- type: ReplaceOnSpawn
prototype: EnergySword
- type: ItemToggleMeleeWeapon
activatedSoundOnHit:
path: /Audio/Weapons/eblade1.ogg
@@ -36,6 +36,8 @@
layers:
- state: default
- state: idpassenger
- type: ReplaceOnSpawn
prototype: AgentIDCard
- type: PresetIdCard
job: Passenger
@@ -272,6 +272,8 @@
sprite: Objects/Misc/bureaucracy.rsi
heldPrefix: pen
size: Tiny
- type: ReplaceOnSpawn
prototype: PenExploding
- type: PhysicalComposition
materialComposition:
Steel: 25
@@ -35,6 +35,8 @@
- type: GuideHelp
guides:
- Janitorial
- type: ReplaceOnSpawn
prototype: AdvMopItem
- type: entity
parent: BaseItem
@@ -73,6 +73,8 @@
- type: Residue
residueAdjective: residue-slippery
residueColor: residue-green
- type: ReplaceOnSpawn
prototype: SoapSyndie
- type: entity
name: soap
@@ -156,6 +156,8 @@
Quantity: 3
- type: Tag
tags: []
- type: ReplaceOnSpawn
prototype: CombatMedipen
- type: entity
name: poison auto-injector
@@ -32,3 +32,5 @@
materialComposition:
Steel: 400
Glass: 100
- type: ReplaceOnSpawn
prototype: Milkalyzer
@@ -154,7 +154,7 @@
parent: PlushieCarp
id: DehydratedSpaceCarp
name: dehydrated space carp
description: Looks like a plush toy carp, but just add water and it becomes a real-life space carp!
description: Looks like a regular space carp, but just add water and it becomes a real-life carp plushie!
components:
- type: SolutionContainerManager
solutions:
@@ -49,6 +49,8 @@
Blunt: 10
soundHit:
collection: MetalThud
- type: ReplaceOnSpawn
prototype: SyndicateJawsOfLife
- type: entity
name: syndicate jaws of life
@@ -70,7 +70,7 @@
solutions:
Welder:
reagents:
- ReagentId: WeldingFuel
- ReagentId: Blood
Quantity: 8
maxVol: 8 #uses less fuel than a welder, so this isnt as bad as it looks
- type: MeleeWeapon
@@ -113,7 +113,7 @@
solutions:
Welder:
reagents:
- ReagentId: WeldingFuel
- ReagentId: Blood
Quantity: 4
maxVol: 4 #uses less fuel than a welder, so this isnt as bad as it looks
@@ -175,7 +175,7 @@
solutions:
Welder:
reagents:
- ReagentId: WeldingFuel
- ReagentId: Blood
Quantity: 12
maxVol: 12 #uses less fuel than a welder, so this isnt as bad as it looks
- type: Welder
@@ -43,6 +43,8 @@
Steel: 100
- type: StaticPrice
price: 30
- type: ReplaceOnSpawn
prototype: Haycutters
- type: entity
name: screwdriver
@@ -87,6 +89,8 @@
Steel: 100
- type: StaticPrice
price: 30
- type: ReplaceOnSpawn
prototype: Moodriver
- type: entity
name: wrench
@@ -126,6 +130,8 @@
Steel: 100
- type: StaticPrice
price: 22
- type: ReplaceOnSpawn
prototype: Wronch
- type: entity
name: crowbar
@@ -167,6 +173,8 @@
- type: StaticPrice
price: 22
- type: Prying
- type: ReplaceOnSpawn
prototype: Cowbar
- type: entity
parent: Crowbar
@@ -231,6 +239,8 @@
Plastic: 100
- type: StaticPrice
price: 56
- type: ReplaceOnSpawn
prototype: Mooltitool
- type: entity
name: network configurator
@@ -80,7 +80,7 @@
solutions:
Welder:
reagents:
- ReagentId: WeldingFuel
- ReagentId: Blood
Quantity: 100
maxVol: 100
- type: Tool
@@ -91,7 +91,7 @@
- type: PointLight
enabled: false
radius: 1.5
color: orange
color: red
netsync: false
- type: Appearance
- type: RequiresEyeProtection
@@ -102,6 +102,8 @@
price: 40
- type: IgnitionSource
temperature: 700
- type: ReplaceOnSpawn
prototype: Cowelder
- type: entity
name: industrial welding tool
@@ -117,7 +119,7 @@
solutions:
Welder:
reagents:
- ReagentId: WeldingFuel
- ReagentId: Blood
Quantity: 250
maxVol: 250
@@ -135,7 +137,7 @@
solutions:
Welder:
reagents:
- ReagentId: WeldingFuel
- ReagentId: Blood
Quantity: 250
maxVol: 250
- type: Tool
@@ -155,18 +157,18 @@
solutions:
Welder:
reagents:
- ReagentId: WeldingFuel
- ReagentId: Blood
Quantity: 1000
maxVol: 1000
- type: PointLight
enabled: false
radius: 1.5
color: lightblue
color: red
- type: SolutionRegeneration
solution: Welder
generated:
reagents:
- ReagentId: WeldingFuel
- ReagentId: Blood
Quantity: 1
- type: entity
@@ -186,7 +188,7 @@
solutions:
Welder:
reagents:
- ReagentId: WeldingFuel
- ReagentId: Blood
Quantity: 50
maxVol: 50
- type: Tool
@@ -194,4 +196,4 @@
- type: PointLight
enabled: false
radius: 1.0
color: orange
color: red
@@ -98,7 +98,7 @@
drink:
maxVol: 30
reagents:
- ReagentId: WeldingFuel
- ReagentId: Blood
Quantity: 30
- type: Construction
node: fuel
@@ -445,6 +445,8 @@
- type: GuideHelp
guides:
- Security
- type: ReplaceOnSpawn
prototype: WeaponDisablerSMG
- type: entity
name: disabler SMG
@@ -662,6 +664,8 @@
node: start
- type: StaticPrice
price: 100
- type: ReplaceOnSpawn
ReplaceOnSpawn: WeaponPistolCHIMPUpgraded
- type: entity
name: experimental C.H.I.M.P. handcannon

Some files were not shown because too many files have changed in this diff Show More