diff --git a/Content.Server/Polymorph/Systems/PolymorphSystem.cs b/Content.Server/Polymorph/Systems/PolymorphSystem.cs
index daff200982..c9a71c5358 100644
--- a/Content.Server/Polymorph/Systems/PolymorphSystem.cs
+++ b/Content.Server/Polymorph/Systems/PolymorphSystem.cs
@@ -199,6 +199,9 @@ public sealed partial class PolymorphSystem : EntitySystem
var targetTransformComp = Transform(uid);
+ if (configuration.PolymorphSound != null)
+ _audio.PlayPvs(configuration.PolymorphSound, targetTransformComp.Coordinates);
+
var child = Spawn(configuration.Entity, _transform.GetMapCoordinates(uid, targetTransformComp), rotation: _transform.GetWorldRotation(uid));
MakeSentientCommand.MakeSentient(child, EntityManager);
@@ -288,6 +291,9 @@ public sealed partial class PolymorphSystem : EntitySystem
var uidXform = Transform(uid);
var parentXform = Transform(parent);
+ if (component.Configuration.ExitPolymorphSound != null)
+ _audio.PlayPvs(component.Configuration.ExitPolymorphSound, uidXform.Coordinates);
+
_transform.SetParent(parent, parentXform, uidXform.ParentUid);
_transform.SetCoordinates(parent, parentXform, uidXform.Coordinates, uidXform.LocalRotation);
diff --git a/Content.Shared/Jaunt/JauntComponent.cs b/Content.Shared/Jaunt/JauntComponent.cs
new file mode 100644
index 0000000000..6d37ab4b32
--- /dev/null
+++ b/Content.Shared/Jaunt/JauntComponent.cs
@@ -0,0 +1,26 @@
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Jaunt;
+
+///
+/// Used to control various aspects of a Jaunt.
+/// Can be used in place of giving a jaunt-action directly.
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class JauntComponent : Component
+{
+ ///
+ /// Which Jaunt Action the component should grant.
+ ///
+ [DataField]
+ public EntProtoId JauntAction = "ActionPolymorphJaunt";
+
+ ///
+ /// The jaunt action itself.
+ ///
+ public EntityUid? Action;
+
+ // TODO: Enter & Exit Times and Whitelist when Actions are reworked and can support it
+ // TODO: Cooldown pausing when Actions can support it
+}
diff --git a/Content.Shared/Jaunt/JauntSystem.cs b/Content.Shared/Jaunt/JauntSystem.cs
new file mode 100644
index 0000000000..d9263d000e
--- /dev/null
+++ b/Content.Shared/Jaunt/JauntSystem.cs
@@ -0,0 +1,26 @@
+using Content.Shared.Actions;
+
+namespace Content.Shared.Jaunt;
+public sealed class JauntSystem : EntitySystem
+{
+ [Dependency] private readonly SharedActionsSystem _actions = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnInit);
+ SubscribeLocalEvent(OnShutdown);
+ }
+
+ private void OnInit(Entity ent, ref MapInitEvent args)
+ {
+ _actions.AddAction(ent.Owner, ref ent.Comp.Action, ent.Comp.JauntAction);
+ }
+
+ private void OnShutdown(Entity ent, ref ComponentShutdown args)
+ {
+ _actions.RemoveAction(ent.Owner, ent.Comp.Action);
+ }
+
+}
+
diff --git a/Content.Shared/Polymorph/PolymorphPrototype.cs b/Content.Shared/Polymorph/PolymorphPrototype.cs
index 6d010711d2..c057669408 100644
--- a/Content.Shared/Polymorph/PolymorphPrototype.cs
+++ b/Content.Shared/Polymorph/PolymorphPrototype.cs
@@ -1,3 +1,4 @@
+using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array;
@@ -115,6 +116,18 @@ public sealed partial record PolymorphConfiguration
[DataField(serverOnly: true)]
[ViewVariables(VVAccess.ReadWrite)]
public TimeSpan Cooldown = TimeSpan.Zero;
+
+ ///
+ /// If not null, this sound will be played when being polymorphed into something.
+ ///
+ [DataField]
+ public SoundSpecifier? PolymorphSound;
+
+ ///
+ /// If not null, this sound will be played when being reverted from a polymorph.
+ ///
+ [DataField]
+ public SoundSpecifier? ExitPolymorphSound;
}
public enum PolymorphInventoryChange : byte
diff --git a/Resources/Audio/Magic/attributions.yml b/Resources/Audio/Magic/attributions.yml
index cedda32286..bfbe4d6ec2 100644
--- a/Resources/Audio/Magic/attributions.yml
+++ b/Resources/Audio/Magic/attributions.yml
@@ -17,6 +17,8 @@
- forcewall.ogg
- knock.ogg
- blink.ogg
- copyright: '"ForceWall.ogg", "Knock.ogg", and "blink.ogg" by Citadel Station 13'
+ - ethereal_enter.ogg
+ - ethereal_exit.ogg
+ copyright: '"forcewall.ogg", "knock.ogg", "blink.ogg", "ethereal_enter.ogg", and "ethereal_exit.ogg" by Citadel Station 13'
license: CC-BY-SA-3.0
source: https://github.com/Citadel-Station-13/Citadel-Station-13/commit/35a1723e98a60f375df590ca572cc90f1bb80bd5
diff --git a/Resources/Audio/Magic/ethereal_enter.ogg b/Resources/Audio/Magic/ethereal_enter.ogg
new file mode 100644
index 0000000000..a0c7222c16
Binary files /dev/null and b/Resources/Audio/Magic/ethereal_enter.ogg differ
diff --git a/Resources/Audio/Magic/ethereal_exit.ogg b/Resources/Audio/Magic/ethereal_exit.ogg
new file mode 100644
index 0000000000..bd60ca8c69
Binary files /dev/null and b/Resources/Audio/Magic/ethereal_exit.ogg differ
diff --git a/Resources/Locale/en-US/store/spellbook-catalog.ftl b/Resources/Locale/en-US/store/spellbook-catalog.ftl
index 457f02916f..1d970f6e3a 100644
--- a/Resources/Locale/en-US/store/spellbook-catalog.ftl
+++ b/Resources/Locale/en-US/store/spellbook-catalog.ftl
@@ -17,6 +17,9 @@ spellbook-polymorph-rod-desc = Change into an Immovable Rod with limited movemen
spellbook-charge-name = Charge
spellbook-charge-desc = Adds a charge back to your wand!
+spellbook-ethereal-jaunt-name = Ethereal Jaunt
+spellbook-ethereal-jaunt-description = Slip into the ethereal plane to slip away from your enemies!
+
# Equipment
spellbook-wand-polymorph-door-name = Wand of Entrance
@@ -33,3 +36,6 @@ spellbook-event-summon-ghosts-description = Who ya gonna call?
# Upgrades
spellbook-upgrade-fireball-name = Upgrade Fireball
spellbook-upgrade-fireball-description = Upgrades Fireball to a maximum of level 3!
+
+spellbook-upgrade-jaunt-name = Upgrade Ethereal Jaunt
+spellbook-upgrade-jaunt-description = Upgrades Jaunt to a maximum of level 3!
diff --git a/Resources/Prototypes/Actions/polymorph.yml b/Resources/Prototypes/Actions/polymorph.yml
index 81feba4eac..291400ab38 100644
--- a/Resources/Prototypes/Actions/polymorph.yml
+++ b/Resources/Prototypes/Actions/polymorph.yml
@@ -40,3 +40,53 @@
icon:
sprite: Objects/Fun/immovable_rod.rsi
state: icon
+
+- type: entity
+ id: ActionPolymorphJaunt
+ name: Ethereal Jaunt
+ description: Melt into the Ethereal Plane for a quick getaway!
+ components:
+ - type: Magic
+ - type: InstantAction
+ useDelay: 30
+ event: !type:PolymorphActionEvent
+ protoId: Jaunt
+ itemIconStyle: NoItem
+ icon:
+ sprite: Objects/Magic/magicactions.rsi
+ state: jaunt
+ # TODO: Effect ECS (from cardboard box)
+ - type: ActionUpgrade
+ effectedLevels:
+ 2: ActionPolymorphJauntII
+ 3: ActionPolymorphJauntIII
+
+- type: entity
+ id: ActionPolymorphJauntII
+ parent: ActionPolymorphJaunt
+ name: Ethereal Jaunt II
+ description: Melt into the Ethereal Plane for an even quicker getaway!
+ components:
+ - type: InstantAction
+ useDelay: 25
+ event: !type:PolymorphActionEvent
+ protoId: Jaunt
+ itemIconStyle: NoItem
+ icon:
+ sprite: Objects/Magic/magicactions.rsi
+ state: jaunt
+
+- type: entity
+ id: ActionPolymorphJauntIII
+ parent: ActionPolymorphJaunt
+ name: Ethereal Jaunt III
+ description: Are you even tangible anymore?
+ components:
+ - type: InstantAction
+ useDelay: 20
+ event: !type:PolymorphActionEvent
+ protoId: Jaunt
+ itemIconStyle: NoItem
+ icon:
+ sprite: Objects/Magic/magicactions.rsi
+ state: jaunt
diff --git a/Resources/Prototypes/Catalog/spellbook_catalog.yml b/Resources/Prototypes/Catalog/spellbook_catalog.yml
index 38b95c3273..805c157f1e 100644
--- a/Resources/Prototypes/Catalog/spellbook_catalog.yml
+++ b/Resources/Prototypes/Catalog/spellbook_catalog.yml
@@ -77,6 +77,20 @@
- !type:ListingLimitedStockCondition
stock: 1
+- type: listing
+ id: SpellbookJaunt
+ name: spellbook-ethereal-jaunt-name
+ description: spellbook-ethereal-jaunt-description
+ productAction: ActionPolymorphJaunt
+ productUpgradeId: SpellbookJauntUpgrade
+ cost:
+ WizCoin: 2
+ categories:
+ - SpellbookUtility
+ conditions:
+ - !type:ListingLimitedStockCondition
+ stock: 1
+
# Equipment
- type: listing
id: SpellbookWandDoor
@@ -138,3 +152,22 @@
# manual for now
- !type:ListingLimitedStockCondition
stock: 2
+
+- type: listing
+ id: SpellbookJauntUpgrade
+ productUpgradeId: SpellbookJauntUpgrade
+ name: spellbook-upgrade-jaunt-name
+ description: spellbook-upgrade-jaunt-description
+ icon:
+ sprite: Objects/Magic/magicactions.rsi
+ state: jaunt
+ cost:
+ WizCoin: 2
+ categories:
+ - SpellbookUtility
+ conditions:
+ - !type:BuyBeforeCondition
+ whitelist:
+ - SpellbookJaunt
+ - !type:ListingLimitedStockCondition
+ stock: 2
diff --git a/Resources/Prototypes/Entities/Mobs/Player/jaunt_mobs.yml b/Resources/Prototypes/Entities/Mobs/Player/jaunt_mobs.yml
new file mode 100644
index 0000000000..3002264a75
--- /dev/null
+++ b/Resources/Prototypes/Entities/Mobs/Player/jaunt_mobs.yml
@@ -0,0 +1,40 @@
+- type: entity
+ name: jaunt
+ parent: [Incorporeal, BaseMob]
+ id: BaseMobJaunt
+ description: Faint traces of a humanoid figure linger here
+ suffix: Ethereal
+ components:
+ - type: ContentEye
+ maxZoom: 1.44,1.44
+ - type: Eye
+ drawFov: false
+ - type: Input
+ context: "ghost"
+ - type: InputMover
+ - type: MovementSpeedModifier
+ baseSprintSpeed: 12
+ baseWalkSpeed: 8
+ - type: Visibility
+ layer: 2
+ - type: Spectral
+
+# Should be slow, for balance
+- type: entity
+ name: jaunt
+ parent: BaseMobJaunt
+ id: EtherealJaunt
+ suffix: Wizard
+ components:
+ - type: Sprite
+ sprite: Mobs/Ghosts/ghost_human.rsi
+ color: "#60f7eb"
+ layers:
+ - state: animated
+ shader: unshaded
+ noRot: true
+ overrideContainerOcclusion: true
+ drawdepth: Ghosts
+ - type: MovementSpeedModifier
+ baseSprintSpeed: 6
+ baseWalkSpeed: 4
diff --git a/Resources/Prototypes/Polymorphs/polymorph.yml b/Resources/Prototypes/Polymorphs/polymorph.yml
index 96739a50d3..fe28287cb0 100644
--- a/Resources/Prototypes/Polymorphs/polymorph.yml
+++ b/Resources/Prototypes/Polymorphs/polymorph.yml
@@ -186,3 +186,19 @@
forced: true
revertOnCrit: false
revertOnDeath: false
+
+# Temporary Jaunt
+# Don't make permanent jaunts until action system can be reworked to allow do afters and cooldown pausing
+- type: polymorph
+ id: Jaunt
+ configuration:
+ entity: EtherealJaunt
+ transferName: true
+ inventory: None
+ forced: true
+ revertOnDeath: true
+ revertOnCrit: true
+ allowRepeatedMorphs: false
+ polymorphSound: /Audio/Magic/ethereal_enter.ogg
+ exitPolymorphSound: /Audio/Magic/ethereal_exit.ogg
+ duration: 3
diff --git a/Resources/Textures/Objects/Magic/magicactions.rsi/jaunt.png b/Resources/Textures/Objects/Magic/magicactions.rsi/jaunt.png
new file mode 100644
index 0000000000..f66002b469
Binary files /dev/null and b/Resources/Textures/Objects/Magic/magicactions.rsi/jaunt.png differ
diff --git a/Resources/Textures/Objects/Magic/magicactions.rsi/meta.json b/Resources/Textures/Objects/Magic/magicactions.rsi/meta.json
index 9bf76bbe77..a8da3d8bc3 100644
--- a/Resources/Textures/Objects/Magic/magicactions.rsi/meta.json
+++ b/Resources/Textures/Objects/Magic/magicactions.rsi/meta.json
@@ -25,8 +25,11 @@
{
"name": "magicmissile"
},
+ {
+ "name": "jaunt"
+ },
{
"name": "gib"
}
]
-}
\ No newline at end of file
+}