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
This commit is contained in:
Hannah Giovanna Dawson 2024-03-25 07:03:49 +00:00 committed by NullWanderer
parent e74f92556e
commit e189a8f71f
No known key found for this signature in database
GPG Key ID: 65CF92BD1D26F4AC
33 changed files with 1020 additions and 8 deletions

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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 = [];
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,10 @@
namespace Content.Shared.LegallyDistinctSpaceFerret;
[RegisterComponent]
public sealed partial class ConsumeNutrientsConditionComponent : Component
{
[DataField]
public float NutrientsRequired = 150.0f;
public float NutrientsConsumed;
}

View File

@ -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 = "";
}

View File

@ -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 = "";
}

View File

@ -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;
}

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.

View File

@ -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!

View File

@ -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: 10.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

View File

@ -0,0 +1,24 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from Yogstation at https://github.com/yogstation13/Yogstation/blob/b5a72f35980b15404d3c507d2ad0af06010f6056/icons/mob/pets.dmi, some modifications by Hannah 'FairlySadPanda' Dawson.",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "legallydistinctspaceferret",
"directions": 4
},
{
"name": "legallydistinctspaceferret_eepy"
},
{
"name": "legallydistinctspaceferret_rip"
},
{
"name": "legallydistinctspaceferret_oof"
}
]
}