diff --git a/Content.Server/Geras/GerasComponent.cs b/Content.Server/Geras/GerasComponent.cs
new file mode 100644
index 0000000000..eaf792502f
--- /dev/null
+++ b/Content.Server/Geras/GerasComponent.cs
@@ -0,0 +1,18 @@
+using Content.Shared.Actions;
+using Content.Shared.Polymorph;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Geras;
+
+///
+/// This component assigns the entity with a polymorph action.
+///
+[RegisterComponent]
+public sealed partial class GerasComponent : Component
+{
+ [DataField] public ProtoId GerasPolymorphId = "SlimeMorphGeras";
+
+ [DataField] public ProtoId GerasAction = "ActionMorphGeras";
+
+ [DataField] public EntityUid? GerasActionEntity;
+}
diff --git a/Content.Server/Geras/GerasSystem.cs b/Content.Server/Geras/GerasSystem.cs
new file mode 100644
index 0000000000..a5377a021e
--- /dev/null
+++ b/Content.Server/Geras/GerasSystem.cs
@@ -0,0 +1,40 @@
+using Content.Server.Actions;
+using Content.Server.Polymorph.Systems;
+using Content.Server.Popups;
+using Content.Shared.Actions;
+using Content.Shared.Geras;
+using Robust.Shared.Player;
+
+namespace Content.Server.Geras;
+
+///
+public sealed class GerasSystem : SharedGerasSystem
+{
+ [Dependency] private readonly ActionsSystem _actionsSystem = default!;
+ [Dependency] private readonly PolymorphSystem _polymorphSystem = default!;
+ [Dependency] private readonly PopupSystem _popupSystem = default!;
+
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnMorphIntoGeras);
+ SubscribeLocalEvent(OnMapInit);
+ }
+
+ private void OnMapInit(EntityUid uid, GerasComponent component, MapInitEvent args)
+ {
+ // try to add geras action
+ _actionsSystem.AddAction(uid, ref component.GerasActionEntity, component.GerasAction);
+ }
+
+ private void OnMorphIntoGeras(EntityUid uid, GerasComponent component, MorphIntoGeras args)
+ {
+ var ent = _polymorphSystem.PolymorphEntity(uid, component.GerasPolymorphId);
+
+ if (!ent.HasValue)
+ return;
+
+ _popupSystem.PopupEntity(Loc.GetString("geras-popup-morph-message-others", ("entity", ent.Value)), ent.Value, Filter.PvsExcept(ent.Value), true);
+ _popupSystem.PopupEntity(Loc.GetString("geras-popup-morph-message-user"), ent.Value, ent.Value);
+ }
+}
diff --git a/Content.Server/Storage/EntitySystems/StorageSystem.cs b/Content.Server/Storage/EntitySystems/StorageSystem.cs
index 27694ee61c..5d41e0a521 100644
--- a/Content.Server/Storage/EntitySystems/StorageSystem.cs
+++ b/Content.Server/Storage/EntitySystems/StorageSystem.cs
@@ -76,13 +76,13 @@ public sealed partial class StorageSystem : SharedStorageSystem
};
if (uiOpen)
{
- verb.Text = Loc.GetString("verb-common-close-ui");
+ verb.Text = Loc.GetString("comp-storage-verb-close-storage");
verb.Icon = new SpriteSpecifier.Texture(
new("/Textures/Interface/VerbIcons/close.svg.192dpi.png"));
}
else
{
- verb.Text = Loc.GetString("verb-common-open-ui");
+ verb.Text = Loc.GetString("comp-storage-verb-open-storage");
verb.Icon = new SpriteSpecifier.Texture(
new("/Textures/Interface/VerbIcons/open.svg.192dpi.png"));
}
diff --git a/Content.Shared/Geras/SharedGerasSystem.cs b/Content.Shared/Geras/SharedGerasSystem.cs
new file mode 100644
index 0000000000..f5dea466a2
--- /dev/null
+++ b/Content.Shared/Geras/SharedGerasSystem.cs
@@ -0,0 +1,16 @@
+using Content.Shared.Actions;
+
+namespace Content.Shared.Geras;
+
+///
+/// A Geras is the small morph of a slime. This system handles exactly that.
+///
+public abstract class SharedGerasSystem : EntitySystem
+{
+
+}
+
+public sealed partial class MorphIntoGeras : InstantActionEvent
+{
+
+}
diff --git a/Resources/Locale/en-US/components/storage-component.ftl b/Resources/Locale/en-US/components/storage-component.ftl
index 29c858891a..e742c83f6a 100644
--- a/Resources/Locale/en-US/components/storage-component.ftl
+++ b/Resources/Locale/en-US/components/storage-component.ftl
@@ -8,3 +8,5 @@ comp-storage-cant-drop = You can't let go of { THE($entity) }!
comp-storage-window-title = Storage Item
comp-storage-window-weight = { $weight }/{ $maxWeight }, Max Size: {$size}
comp-storage-window-slots = Slots: { $itemCount }/{ $maxCount }, Max Size: {$size}
+comp-storage-verb-open-storage = Open Storage
+comp-storage-verb-close-storage = Close Storage
diff --git a/Resources/Locale/en-US/geras/geras.ftl b/Resources/Locale/en-US/geras/geras.ftl
new file mode 100644
index 0000000000..3cd3f101ff
--- /dev/null
+++ b/Resources/Locale/en-US/geras/geras.ftl
@@ -0,0 +1,2 @@
+geras-popup-morph-message-user = You shift and morph into a small version of you!
+geras-popup-morph-message-others = {CAPITALIZE(THE($entity))} shifts and morphs into a blob of slime!
diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml
index b91b26e357..aeffd5b8c5 100644
--- a/Resources/Prototypes/Actions/types.yml
+++ b/Resources/Prototypes/Actions/types.yml
@@ -92,7 +92,6 @@
state: gib
event: !type:ActivateImplantEvent
-
- type: entity
id: ActionActivateFreedomImplant
name: Break Free
@@ -171,6 +170,22 @@
state: icon
event: !type:UseDnaScramblerImplantEvent
+- type: entity
+ id: ActionMorphGeras
+ name: Morph into Geras
+ description: Morphs you into a Geras - a miniature version of you which allows you to move fast, at the cost of your inventory.
+ noSpawn: true
+ components:
+ - type: InstantAction
+ charges: 1
+ itemIconStyle: BigAction
+ useDelay: 10 # prevent spam
+ priority: -20
+ icon:
+ sprite: Mobs/Aliens/slimes.rsi
+ state: blue_adult_slime
+ event: !type:MorphIntoGeras
+
- type: entity
id: ActionToggleSuitPiece
name: Toggle Suit Piece
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml b/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml
index 10e9218d6e..95c30a174f 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml
@@ -1,16 +1,10 @@
- type: entity
name: basic slime
- id: MobAdultSlimes
+ id: BaseMobAdultSlimes
parent: [ SimpleMobBase, MobCombat ]
abstract: true
description: It looks so much like jelly. I wonder what it tastes like?
components:
- - type: NpcFactionMember
- factions:
- - SimpleNeutral
- - type: HTN
- rootTask:
- task: SimpleHostileCompound
- type: Sprite
drawdepth: Mobs
sprite: Mobs/Aliens/slimes.rsi
@@ -111,6 +105,19 @@
successChance: 0.5
interactSuccessString: petting-success-slimes
interactFailureString: petting-failure-generic
+ - type: Speech
+ speechVerb: Slime
+ speechSounds: Slime
+ - type: TypingIndicator
+ proto: slime
+
+- type: entity
+ name: basic slime
+ id: MobAdultSlimes
+ parent: BaseMobAdultSlimes
+ abstract: true
+ description: It looks so much like jelly. I wonder what it tastes like?
+ components:
- type: ReplacementAccent
accent: slimes
- type: GhostTakeoverAvailable
@@ -118,11 +125,37 @@
makeSentient: true
name: ghost-role-information-slimes-name
description: ghost-role-information-slimes-description
- - type: Speech
- speechVerb: Slime
- speechSounds: Slime
- - type: TypingIndicator
- proto: slime
+ - type: NpcFactionMember
+ factions:
+ - SimpleNeutral
+ - type: HTN
+ rootTask:
+ task: SimpleHostileCompound
+
+- type: entity
+ name: geras
+ description: A geras of a slime - the name is ironic, isn't it?
+ id: MobSlimesGeras
+ parent: BaseMobAdultSlimes
+ noSpawn: true
+ components:
+ # they portable...
+ - type: MultiHandedItem
+ - type: Item
+ size: Huge
+ - type: Sprite
+ color: "#FFFFFF55"
+ - type: MeleeWeapon
+ attackRate: 2
+ damage:
+ types:
+ Blunt: 4
+ - type: DamageStateVisuals
+ states:
+ Alive:
+ Base: blue_adult_slime
+ Dead:
+ Base: blue_adult_slime_dead
- type: entity
name: blue slime
diff --git a/Resources/Prototypes/Entities/Mobs/Species/slime.yml b/Resources/Prototypes/Entities/Mobs/Species/slime.yml
index 3eabb7dc07..5599825a0c 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/slime.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/slime.yml
@@ -12,6 +12,30 @@
- type: Body
prototype: Slime
requiredLegs: 2
+ # they like eat it idk lol
+ - type: Storage
+ grid:
+ - 0,0,1,2
+ maxItemSize: Large
+ storageInsertSound:
+ path: /Audio/Voice/Slime/slime_squish.ogg
+ - type: ContainerContainer
+ containers:
+ storagebase: !type:Container
+ ents: []
+ - type: UserInterface
+ interfaces:
+ - key: enum.StorageUiKey.Key
+ type: StorageBoundUserInterface
+ - key: enum.VoiceMaskUIKey.Key
+ type: VoiceMaskBoundUserInterface
+ - key: enum.HumanoidMarkingModifierKey.Key
+ type: HumanoidMarkingModifierBoundUserInterface
+ - key: enum.StrippingUiKey.Key
+ type: StrippableBoundUserInterface
+ # to prevent bag open/honk spam
+ - type: UseDelay
+ delay: 0.5
- type: HumanoidAppearance
species: SlimePerson
- type: Speech
@@ -27,6 +51,16 @@
- type: Damageable
damageContainer: Biological
damageModifierSet: Slime
+ - type: Geras
+ - type: PassiveDamage # Around 8 damage a minute healed
+ allowedStates:
+ - Alive
+ damageCap: 65
+ damage:
+ types:
+ Heat: -0.14
+ groups:
+ Brute: -0.14
- type: DamageVisuals
damageOverlayGroups:
Brute:
diff --git a/Resources/Prototypes/Polymorphs/polymorph.yml b/Resources/Prototypes/Polymorphs/polymorph.yml
index b4249f8a3e..ce89f41d37 100644
--- a/Resources/Prototypes/Polymorphs/polymorph.yml
+++ b/Resources/Prototypes/Polymorphs/polymorph.yml
@@ -75,6 +75,17 @@
inventory: Transfer
revertOnDeath: true
+- type: polymorph
+ id: SlimeMorphGeras
+ configuration:
+ entity: MobSlimesGeras
+ transferName: false
+ transferHumanoidAppearance: false
+ inventory: Drop
+ transferDamage: true
+ revertOnDeath: true
+ revertOnCrit: true
+
# this is a test for transferring some visual appearance stuff
- type: polymorph
id: TestHumanMorph
diff --git a/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml b/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml
index fc72c60dbf..0374d4cb95 100644
--- a/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml
+++ b/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml
@@ -10,7 +10,21 @@
They exhale nitrous oxide and are unaffected by it.
Their body can process 6 reagents at the same time instead of just 2.
- Their Slime "blood" can not be regenerated from Iron. Slime Blood is technically a source of
+ Slimepeople can morph into a [bold]"geras"[/bold] (an archaic slimefolk term), which is a smaller slime form that can [bold]pass through grilles[/bold],
+ but forces them to drop their inventory and held items. It's handy for a quick getaway. A geras is small enough to pick up (with two hands)
+ and fits in a duffelbag.
+
+
+
+
+
+ Slimepeople have an [bold]internal 2x2 storage inventory[/bold] inside of their slime membrane. Anyone can see what's inside and take it out of you without asking,
+ so be careful. They [bold]don't drop their internal storage when they morph into a geras, however![/bold]
+
+ Slimepeople have slight accelerated regeneration compared to other humanoids. They're also capable of hardening their fists, and as such have stronger punches,
+ although they punch a little slower.
+
+ Their slime "blood" can not be regenerated from Iron. Slime Blood is technically a source of
moderately filling food for other species, although drinking the blood of your coworkers is usually frowned upon.
They suffocate 80% slower, but take pressure damage 9% faster. This makes them by far the species most capable to survive in hard vacuum. For a while.