diff --git a/Content.Server/EntityEffects/EntityEffectSystem.cs b/Content.Server/EntityEffects/EntityEffectSystem.cs index eaa8798de9..699f7e6890 100644 --- a/Content.Server/EntityEffects/EntityEffectSystem.cs +++ b/Content.Server/EntityEffects/EntityEffectSystem.cs @@ -5,9 +5,9 @@ using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Components; using Content.Server.Body.Systems; +using Content.Server.Botany; using Content.Server.Botany.Components; using Content.Server.Botany.Systems; -using Content.Server.Botany; using Content.Server.Chat.Systems; using Content.Server.Emp; using Content.Server.Explosion.EntitySystems; @@ -28,17 +28,19 @@ using Content.Server.Zombies; using Content.Shared.Atmos; using Content.Shared.Audio; using Content.Shared.Coordinates.Helpers; +using Content.Shared.EntityEffects; using Content.Shared.EntityEffects.EffectConditions; +using Content.Shared.EntityEffects.Effects; using Content.Shared.EntityEffects.Effects.PlantMetabolism; using Content.Shared.EntityEffects.Effects.StatusEffects; -using Content.Shared.EntityEffects.Effects; -using Content.Shared.EntityEffects; using Content.Shared.Humanoid; using Content.Shared.Maps; using Content.Shared.Mind.Components; using Content.Shared.Nyanotrasen.Chemistry.Effects; using Content.Shared.Popups; using Content.Shared.Random; +using Content.Shared.Xenoarchaeology.Artifact; +using Content.Shared.Xenoarchaeology.Artifact.Components; using Content.Shared.Zombies; using Robust.Server.GameObjects; using Robust.Shared.Audio; @@ -47,9 +49,8 @@ using Robust.Shared.GameObjects; using Robust.Shared.Map; using Robust.Shared.Prototypes; using Robust.Shared.Random; - -using TemperatureCondition = Content.Shared.EntityEffects.EffectConditions.Temperature; // disambiguate the namespace using PolymorphEffect = Content.Shared.EntityEffects.Effects.Polymorph; +using TemperatureCondition = Content.Shared.EntityEffects.EffectConditions.Temperature; // disambiguate the namespace namespace Content.Server.EntityEffects; @@ -999,8 +1000,23 @@ public sealed class EntityEffectSystem : EntitySystem private void OnActivateArtifact(ref ExecuteEntityEffectEvent args) { - var artifact = args.Args.EntityManager.EntitySysManager.GetEntitySystem(); - artifact.TryActivateArtifact(args.Args.TargetEntity, logMissing: false); + // Get the XenoArtifact system + var xenoArtifactSystem = EntityManager.EntitySysManager.GetEntitySystem(); + + // Make sure the target entity has a XenoArtifactComponent + if (!TryComp(args.Args.TargetEntity, out var artifactComp)) + return; + + // Wrap the entity and component in the Entity<> type + var artifactEntity = new Entity(args.Args.TargetEntity, artifactComp); + + // Try to activate the artifact + xenoArtifactSystem.TryActivateXenoArtifact( + artifact: artifactEntity, + user: null, // no performer info in the effect + target: args.Args.TargetEntity, + coordinates: Transform(args.Args.TargetEntity).Coordinates + ); } // Nyanotrasen diff --git a/Content.Server/Instruments/InstrumentSystem.cs b/Content.Server/Instruments/InstrumentSystem.cs index a347d7ea41..ca7e0e05f1 100644 --- a/Content.Server/Instruments/InstrumentSystem.cs +++ b/Content.Server/Instruments/InstrumentSystem.cs @@ -231,7 +231,7 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem if (msg.Value) { // Prevent stuck notes when turning off a channel... Shrimple. - RaiseNetworkEvent(new InstrumentMidiEventEvent(msg.Uid, new []{RobustMidiEvent.AllNotesOff((byte)msg.Channel, 0)})); + RaiseNetworkEvent(new InstrumentMidiEventEvent(msg.Uid, new[] { RobustMidiEvent.AllNotesOff((byte)msg.Channel, 0) })); } Dirty(uid, instrument); @@ -277,7 +277,7 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem var instrumentQuery = EntityManager.GetEntityQuery(); if (!TryComp(uid, out InstrumentComponent? originInstrument) - || originInstrument.InstrumentPlayer is not {} originPlayer) + || originInstrument.InstrumentPlayer is not { } originPlayer) return Array.Empty<(NetEntity, string)>(); // It's probably faster to get all possible active instruments than all entities in range @@ -292,7 +292,7 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem continue; // We want to use the instrument player's name. - if (instrument.InstrumentPlayer is not {} playerUid) + if (instrument.InstrumentPlayer is not { } playerUid) continue; // Maybe a bit expensive but oh well GetBands is queued and has a timer anyway. @@ -320,7 +320,7 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem var netUid = GetNetEntity(uid); // Reset puppet instruments too. - RaiseNetworkEvent(new InstrumentMidiEventEvent(netUid, new[]{RobustMidiEvent.SystemReset(0)})); + RaiseNetworkEvent(new InstrumentMidiEventEvent(netUid, new[] { RobustMidiEvent.SystemReset(0) })); RaiseNetworkEvent(new InstrumentStopMidiEvent(netUid)); } @@ -371,12 +371,12 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem if (instrument.RespectMidiLimits) { - if (instrument.LaggedBatches == (int) (MaxMidiLaggedBatches * (1 / 3d) + 1)) + if (instrument.LaggedBatches == (int)(MaxMidiLaggedBatches * (1 / 3d) + 1)) { _popup.PopupEntity(Loc.GetString("instrument-component-finger-cramps-light-message"), uid, attached, PopupType.SmallCaution); } - else if (instrument.LaggedBatches == (int) (MaxMidiLaggedBatches * (2 / 3d) + 1)) + else if (instrument.LaggedBatches == (int)(MaxMidiLaggedBatches * (2 / 3d) + 1)) { _popup.PopupEntity(Loc.GetString("instrument-component-finger-cramps-serious-message"), uid, attached, PopupType.MediumCaution); @@ -430,7 +430,7 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem var query = AllEntityQuery(); while (query.MoveNext(out var uid, out _, out var instrument)) { - if (instrument.Master is {} master) + if (instrument.Master is { } master) { if (Deleted(master)) { @@ -456,7 +456,7 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem (instrument.BatchesDropped >= MaxMidiBatchesDropped || instrument.LaggedBatches >= MaxMidiLaggedBatches)) { - if (instrument.InstrumentPlayer is {Valid: true} mob) + if (instrument.InstrumentPlayer is { Valid: true } mob) { _stuns.TryParalyze(mob, TimeSpan.FromSeconds(1), true); diff --git a/Content.Server/Xenoarchaeology/Artifact/XenoArtifactSystem.cs b/Content.Server/Xenoarchaeology/Artifact/XenoArtifactSystem.cs index fbea515dc3..312090c9d0 100644 --- a/Content.Server/Xenoarchaeology/Artifact/XenoArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/Artifact/XenoArtifactSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.Cargo.Systems; +using Content.Shared.Cargo; using Content.Shared.Xenoarchaeology.Artifact; using Content.Shared.Xenoarchaeology.Artifact.Components; diff --git a/Content.Server/_DV/Xenoarchaeology/XenoArtifacts/Effects/Systems/GlimmerArtifactSystem.cs b/Content.Server/_DV/Xenoarchaeology/XenoArtifacts/Effects/Systems/GlimmerArtifactSystem.cs index a8a7032205..60b16c8c6f 100644 --- a/Content.Server/_DV/Xenoarchaeology/XenoArtifacts/Effects/Systems/GlimmerArtifactSystem.cs +++ b/Content.Server/_DV/Xenoarchaeology/XenoArtifacts/Effects/Systems/GlimmerArtifactSystem.cs @@ -1,5 +1,5 @@ using Content.Server._DV.Xenoarchaeology.XenoArtifacts.Effects.Components; -using Content.Server.Xenoarchaeology.XenoArtifacts.Events; +using Content.Shared.Xenoarchaeology.Artifact; using Content.Shared.Psionics.Glimmer; namespace Content.Server._DV.Xenoarchaeology.XenoArtifacts.Effects.Systems; @@ -12,10 +12,10 @@ public sealed class GlimmerArtifactSystem : EntitySystem { base.Initialize(); - SubscribeLocalEvent(OnActivated); + SubscribeLocalEvent(OnActivated); } - private void OnActivated(Entity ent, ref ArtifactActivatedEvent args) + private void OnActivated(Entity ent, ref XenoArtifactActivatedEvent args) { var range = ent.Comp.Range; var current = _glimmer.Glimmer; diff --git a/Content.Server/_DV/Xenoarchaeology/XenoArtifacts/Effects/Systems/PsionicProducingArtifactSystem.cs b/Content.Server/_DV/Xenoarchaeology/XenoArtifacts/Effects/Systems/PsionicProducingArtifactSystem.cs index d742dbb3dd..66ef934606 100644 --- a/Content.Server/_DV/Xenoarchaeology/XenoArtifacts/Effects/Systems/PsionicProducingArtifactSystem.cs +++ b/Content.Server/_DV/Xenoarchaeology/XenoArtifacts/Effects/Systems/PsionicProducingArtifactSystem.cs @@ -1,11 +1,12 @@ +using System.Linq; using Content.Server._DV.Xenoarchaeology.XenoArtifacts.Effects.Components; -using Content.Server.Xenoarchaeology.XenoArtifacts; -using Content.Server.Xenoarchaeology.XenoArtifacts.Events; using Content.Server.Psionics; +using Content.Shared.Xenoarchaeology.Artifact; +using Content.Shared.Xenoarchaeology.Artifact.Components; public sealed class PsionicProducingArtifactSystem : EntitySystem { - [Dependency] private readonly ArtifactSystem _artifact = default!; + [Dependency] private readonly SharedXenoArtifactSystem _artifact = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly PsionicsSystem _psionics = default!; @@ -15,24 +16,39 @@ public sealed class PsionicProducingArtifactSystem : EntitySystem { base.Initialize(); - SubscribeLocalEvent(OnActivated); + SubscribeLocalEvent(OnActivated); } - private void OnActivated(Entity ent, ref ArtifactActivatedEvent args) + private void OnActivated(Entity ent, ref XenoArtifactActivatedEvent args) { var (uid, comp) = ent; - if (!_artifact.TryGetNodeData(uid, NodeDataPsionicAmount, out int amount)) - amount = 0; - if (amount >= comp.Limit) + // Resolve the artifact entity from the node + if (!TryComp(uid, out var artifactComp)) + return; + + var artifactEntity = new Entity(uid, artifactComp); + + // Pick first active node + var node = _artifact.GetActiveNodes(artifactEntity).FirstOrDefault(); + if (node == null) + return; + + // Track psionic usage using ConsumedResearchValue + var currentAmount = _artifact.GetResearchValue(node); + + if (currentAmount >= comp.Limit) return; var coords = Transform(uid).Coordinates; + foreach (var target in _lookup.GetEntitiesInRange(coords, comp.Range)) { _psionics.TryMakePsionic(target); } - _artifact.SetNodeData(uid, NodeDataPsionicAmount, amount + 1); + // Update node usage + _artifact.SetConsumedResearchValue(node, currentAmount + 1); } + } diff --git a/Content.Server/_DV/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactMetapsionicTriggerSystem.cs b/Content.Server/_DV/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactMetapsionicTriggerSystem.cs index f9c8c01be3..2459ae548e 100644 --- a/Content.Server/_DV/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactMetapsionicTriggerSystem.cs +++ b/Content.Server/_DV/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactMetapsionicTriggerSystem.cs @@ -1,13 +1,14 @@ using Content.Server._DV.Xenoarchaeology.XenoArtifacts.Triggers.Components; using Content.Server.Nyanotrasen.StationEvents.Events; -using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems; +using Content.Server.Xenoarchaeology.Artifact; using Content.Shared.Abilities.Psionics; +using Content.Shared.Xenoarchaeology.Artifact.Components; namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems; public sealed class ArtifactMetapsionicTriggerSystem : EntitySystem { - [Dependency] private readonly ArtifactSystem _artifact = default!; + [Dependency] private readonly XenoArtifactSystem _artifact = default!; public override void Initialize() { @@ -20,7 +21,18 @@ public sealed class ArtifactMetapsionicTriggerSystem : EntitySystem private void OnPowerDetected(Entity ent, ref PsionicPowerDetectedEvent args) { - _artifact.TryActivateArtifact(ent); + if (!TryComp(ent, out var artifactComp)) + return; + + var artifactEntity = new Entity(ent, artifactComp); + var coords = Transform(ent).Coordinates; + + _artifact.TryActivateXenoArtifact( + artifactEntity, + user: null, + target: null, + coordinates: coords + ); } private void OnGlimmerEventEnded(GlimmerEventEndedEvent args) @@ -28,7 +40,18 @@ public sealed class ArtifactMetapsionicTriggerSystem : EntitySystem var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out _)) { - _artifact.TryActivateArtifact(uid); + if (!TryComp(uid, out var artifactComp)) + continue; + + var artifactEntity = new Entity(uid, artifactComp); + var coords = Transform(uid).Coordinates; + + _artifact.TryActivateXenoArtifact( + artifactEntity, + user: null, + target: null, + coordinates: coords + ); } } } diff --git a/Content.Server/_Impstation/Xenoarchaeology/XenoArtifacts/Effects/Systems/AnimateArtifactSystem.cs b/Content.Server/_Impstation/Xenoarchaeology/XenoArtifacts/Effects/Systems/AnimateArtifactSystem.cs index c1efb97fea..02d1cf4167 100644 --- a/Content.Server/_Impstation/Xenoarchaeology/XenoArtifacts/Effects/Systems/AnimateArtifactSystem.cs +++ b/Content.Server/_Impstation/Xenoarchaeology/XenoArtifacts/Effects/Systems/AnimateArtifactSystem.cs @@ -1,5 +1,5 @@ using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components; -using Content.Server.Xenoarchaeology.XenoArtifacts.Events; +using Content.Shared.Xenoarchaeology.Artifact; using Content.Server.Revenant.EntitySystems; using Content.Shared.Item; using System.Linq; @@ -19,10 +19,10 @@ public sealed class AnimateArtifactSystem : EntitySystem /// public override void Initialize() { - SubscribeLocalEvent(OnActivated); + SubscribeLocalEvent(OnActivated); } - private void OnActivated(EntityUid uid, AnimateArtifactComponent component, ArtifactActivatedEvent args) + private void OnActivated(EntityUid uid, AnimateArtifactComponent component, XenoArtifactActivatedEvent args) { // Get a list of all nearby objects in range diff --git a/Content.Shared.Database/LogType.cs b/Content.Shared.Database/LogType.cs index bcb9e6942e..fa2304dc87 100644 --- a/Content.Shared.Database/LogType.cs +++ b/Content.Shared.Database/LogType.cs @@ -470,5 +470,15 @@ public enum LogType /// /// Artifact node got activated. /// - ArtifactNode = 101 + ArtifactNode = 101, + + /// + /// Damaging grid collision has occurred. + /// + ShuttleImpact = 102, + + /// + /// Events relating to midi playback. + /// + Instrument = 103, } diff --git a/Content.Shared/Instruments/SharedInstrumentComponent.cs b/Content.Shared/Instruments/SharedInstrumentComponent.cs index da64bf8cd7..3cb583beb9 100644 --- a/Content.Shared/Instruments/SharedInstrumentComponent.cs +++ b/Content.Shared/Instruments/SharedInstrumentComponent.cs @@ -22,7 +22,7 @@ public abstract partial class SharedInstrumentComponent : Component public bool AllowPercussion { get; set; } [DataField("allowProgramChange"), ViewVariables(VVAccess.ReadWrite)] - public bool AllowProgramChange { get ; set; } + public bool AllowProgramChange { get; set; } [DataField("respectMidiLimits"), ViewVariables(VVAccess.ReadWrite)] public bool RespectMidiLimits { get; set; } = true; @@ -38,7 +38,13 @@ public abstract partial class SharedInstrumentComponent : Component /// Component that indicates that musical instrument was activated (ui opened). /// [RegisterComponent, NetworkedComponent] -public sealed partial class ActiveInstrumentComponent : Component; +[AutoGenerateComponentState(true)] +public sealed partial class ActiveInstrumentComponent : Component +{ + [DataField] + [AutoNetworkedField] + public MidiTrack?[] Tracks = []; +} [Serializable, NetSerializable] public sealed class InstrumentComponentState : ComponentState @@ -144,3 +150,72 @@ public enum InstrumentUiKey { Key, } + +/// +/// Sets the MIDI channels on an instrument. +/// +[Serializable, NetSerializable] +public sealed class InstrumentSetChannelsEvent : EntityEventArgs +{ + public NetEntity Uid { get; } + public MidiTrack?[] Tracks { get; set; } + + public InstrumentSetChannelsEvent(NetEntity uid, MidiTrack?[] tracks) + { + Uid = uid; + Tracks = tracks; + } +} + +/// +/// Represents a single midi track with the track name, instrument name and bank instrument name extracted. +/// +[Serializable, NetSerializable] +public sealed class MidiTrack +{ + /// + /// The first specified Track Name + /// + public string? TrackName; + /// + /// The first specified instrument name + /// + public string? InstrumentName; + + /// + /// The first program change resolved to the name. + /// + public string? ProgramName; + + public override string ToString() + { + return $"Track Name: {TrackName}; Instrument Name: {InstrumentName}; Program Name: {ProgramName}"; + } + + /// + /// Truncates the fields based on the limit inputted into this method. + /// + public void TruncateFields(int limit) + { + if (InstrumentName != null) + InstrumentName = Truncate(InstrumentName, limit); + + if (TrackName != null) + TrackName = Truncate(TrackName, limit); + + if (ProgramName != null) + ProgramName = Truncate(ProgramName, limit); + } + + private const string Postfix = "…"; + // TODO: Make a general method to use in RT? idk if we have that. + private string Truncate(string input, int limit) + { + if (string.IsNullOrEmpty(input) || limit <= 0 || input.Length <= limit) + return input; + + var truncatedLength = limit - Postfix.Length; + + return input.Substring(0, truncatedLength) + Postfix; + } +} diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml index d65732bc4b..2de5e77313 100644 --- a/Resources/Prototypes/Actions/types.yml +++ b/Resources/Prototypes/Actions/types.yml @@ -1,345 +1,440 @@ # base actions +# base prototype for all action entities - type: entity - id: BaseSuicideAction abstract: true + id: BaseAction + components: + - type: Action + +# an action that is done all in le head and cant be prevented by any means +- type: entity + abstract: true + parent: BaseAction + id: BaseMentalAction + components: + - type: Action + checkCanInteract: false + checkConsciousness: false + +- type: entity + abstract: true + parent: BaseMentalAction + id: BaseSuicideAction components: - type: ConfirmableAction popup: suicide-action-popup +- type: entity + abstract: true + parent: BaseAction + id: BaseImplantAction + components: + - type: InstantAction + event: !type:ActivateImplantEvent + +- type: entity + abstract: true + parent: BaseAction + id: BaseToggleAction + components: + - type: InstantAction + event: !type:ToggleActionEvent + # actions - type: entity + parent: BaseAction id: ActionScream name: Scream description: AAAAAAAAAAAAAAAAAAAAAAAAA components: - - type: InstantAction + - type: Action useDelay: 10 icon: Interface/Actions/scream.png - event: !type:ScreamActionEvent checkCanInteract: false + - type: InstantAction + event: !type:ScreamActionEvent - type: entity + parent: BaseMentalAction id: ActionTurnUndead name: Turn Undead description: Succumb to your infection and become a zombie. components: - - type: InstantAction - checkCanInteract: false - checkConsciousness: false + - type: Action icon: Interface/Actions/zombie-turn.png + - type: InstantAction event: !type:ZombifySelfActionEvent - type: entity + parent: BaseToggleAction id: ActionToggleLight name: Toggle Light description: Turn the light on and off. components: - - type: InstantAction + - type: Action useDelay: 1 icon: { sprite: Objects/Tools/flashlight.rsi, state: flashlight } iconOn: { sprite: Objects/Tools/flashlight.rsi, state: flashlight-on } - event: !type:ToggleActionEvent - type: entity + parent: BaseAction id: ActionOpenStorageImplant name: Toggle Storage Implant description: Opens or closes the storage implant embedded under your skin, note that it cannot store high value or storage based items # DeltaV components: - - type: InstantAction + - type: Action itemIconStyle: BigAction priority: -20 icon: sprite: Clothing/Back/Backpacks/backpack.rsi state: icon - event: !type:OpenStorageImplantEvent useDelay: 1 + - type: InstantAction + event: !type:OpenStorageImplantEvent - type: entity - parent: BaseSuicideAction + parent: [BaseSuicideAction, BaseImplantAction] id: ActionActivateMicroBomb name: Activate Microbomb description: Activates your internal microbomb, completely destroying you and your equipment components: - - type: InstantAction - checkCanInteract: false - checkConsciousness: false + - type: Action itemIconStyle: BigAction priority: -20 icon: sprite: Actions/Implants/implants.rsi state: explosive - event: !type:ActivateImplantEvent - type: entity - parent: BaseSuicideAction + parent: [BaseSuicideAction, BaseImplantAction] id: ActionActivateDeathAcidifier name: Activate Death-Acidifier description: Activates your death-acidifier, completely melting you and your equipment components: - - type: InstantAction - checkCanInteract: false - checkConsciousness: false + - type: Action itemIconStyle: BigAction priority: -20 icon: sprite: Objects/Magic/magicactions.rsi state: gib - event: !type:ActivateImplantEvent - type: entity + parent: BaseAction id: ActionActivateFreedomImplant name: Break Free description: Activating your freedom implant will free you from any hand restraints components: - - type: InstantAction - charges: 3 + - type: LimitedCharges + maxCharges: 3 + - type: Action checkCanInteract: false itemIconStyle: BigAction priority: -20 icon: sprite: Actions/Implants/implants.rsi state: freedom + - type: InstantAction event: !type:UseFreedomImplantEvent - type: entity + parent: BaseAction id: ActionOpenUplinkImplant name: Open Uplink description: Opens the syndicate uplink embedded under your skin components: - - type: InstantAction + - type: Action itemIconStyle: BigAction priority: -20 icon: sprite: Objects/Devices/communication.rsi state: old-radio + - type: InstantAction event: !type:OpenUplinkImplantEvent - type: entity + parent: BaseImplantAction id: ActionActivateEmpImplant name: Activate EMP description: Triggers a small EMP pulse around you components: - - type: InstantAction + - type: LimitedCharges + maxCharges: 3 + - type: Action checkCanInteract: false - charges: 3 useDelay: 5 itemIconStyle: BigAction priority: -20 icon: sprite: Objects/Weapons/Grenades/empgrenade.rsi state: icon - event: !type:ActivateImplantEvent - type: entity + parent: BaseAction id: ActionActivateScramImplant name: SCRAM! description: Randomly teleports you within a large distance. components: - - type: InstantAction + - type: LimitedCharges + maxCharges: 2 + - type: Action checkCanInteract: false - charges: 2 useDelay: 5 itemIconStyle: BigAction priority: -20 icon: sprite: Structures/Specific/anomaly.rsi state: anom4 + - type: InstantAction event: !type:UseScramImplantEvent - type: entity + parent: BaseAction id: ActionActivateDnaScramblerImplant name: Scramble DNA description: Randomly changes your name and appearance. components: - type: ConfirmableAction popup: dna-scrambler-action-popup - - type: InstantAction - charges: 1 + - type: LimitedCharges + maxCharges: 1 + - type: Action itemIconStyle: BigAction priority: -20 icon: sprite: Clothing/OuterClothing/Hardsuits/lingspacesuit.rsi state: icon + - type: InstantAction event: !type:UseDnaScramblerImplantEvent - type: entity + parent: BaseAction id: ActionToggleSuitPiece name: Toggle Suit Piece description: Remember to equip the important pieces of your suit before going into action. components: - - type: InstantAction + - type: Action itemIconStyle: BigItem useDelay: 1 # equip noise spam. + - type: InstantAction event: !type:ToggleClothingEvent - type: entity + parent: BaseAction id: ActionCombatModeToggle name: "[color=red]Combat Mode[/color]" description: Enter combat mode components: - - type: InstantAction - checkCanInteract: false - checkConsciousness: false + - type: Action icon: Interface/Actions/harmOff.png iconOn: Interface/Actions/harm.png - event: !type:ToggleCombatActionEvent priority: -100 + - type: InstantAction + event: !type:ToggleCombatActionEvent - type: entity - id: ActionCombatModeToggleOff parent: ActionCombatModeToggle - name: "[color=red]Combat Mode[/color]" - description: Enter combat mode + id: ActionCombatModeToggleOff components: - - type: InstantAction + - type: Action enabled: false autoPopulate: false - priority: -100 - type: entity + parent: BaseAction id: ActionChangeVoiceMask name: Set name description: Change the name others hear to something else. components: - - type: InstantAction + - type: Action icon: { sprite: Interface/Actions/voice-mask.rsi, state: icon } + - type: InstantAction event: !type:VoiceMaskSetNameEvent - type: entity + parent: BaseAction id: ActionVendingThrow name: Dispense Item description: Randomly dispense an item from your stock. components: - - type: InstantAction + - type: Action useDelay: 30 + - type: InstantAction event: !type:VendingMachineSelfDispenseEvent +# - type: entity + # parent: BaseAction + # id: ActionArtifactActivate + # name: Activate Artifact + # description: Immediately activates your current artifact node. + # components: + # - type: Action + # icon: + # sprite: Objects/Specific/Xenoarchaeology/xeno_artifacts.rsi + # state: ano01 + # useDelay: 60 + # - type: InstantAction + # event: !type:ArtifactSelfActivateEvent + - type: entity + parent: BaseToggleAction id: ActionToggleBlock name: Block description: Raise or lower your shield. components: - - type: InstantAction + - type: Action icon: { sprite: Objects/Weapons/Melee/shields.rsi, state: teleriot-icon } - iconOn: Objects/Weapons/Melee/shields.rsi/teleriot-on.png - event: !type:ToggleActionEvent + iconOn: { sprite: Objects/Weapons/Melee/shields.rsi, state: teleriot-on } - type: entity + parent: BaseMentalAction id: ActionClearNetworkLinkOverlays name: Clear network link overlays description: Clear network link overlays. components: - - type: InstantAction + - type: Action clientExclusive: true - checkCanInteract: false - checkConsciousness: false temporary: true icon: { sprite: Objects/Tools/multitool.rsi, state: icon } + - type: InstantAction event: !type:ClearAllOverlaysEvent - type: entity + parent: BaseAction id: ActionAnimalLayEgg name: Lay egg description: Uses hunger to lay an egg. components: - - type: InstantAction + - type: Action icon: { sprite: Objects/Consumable/Food/egg.rsi, state: icon } useDelay: 60 + - type: InstantAction event: !type:EggLayInstantActionEvent - type: entity + parent: BaseMentalAction id: ActionSleep name: Sleep description: Go to sleep. components: - - type: InstantAction - checkCanInteract: false - checkConsciousness: false + - type: Action icon: { sprite: Clothing/Head/Hats/pyjamasyndicatered.rsi, state: icon } + - type: InstantAction event: !type:SleepActionEvent - type: entity + parent: BaseMentalAction id: ActionWake name: Wake up description: Stop sleeping. components: - - type: InstantAction - icon: { sprite: Clothing/Head/Hats/pyjamasyndicatered.rsi, state: icon } - checkCanInteract: false - checkConsciousness: false - event: !type:WakeActionEvent + - type: Action startDelay: true useDelay: 2 + icon: { sprite: Clothing/Head/Hats/pyjamasyndicatered.rsi, state: icon } + - type: InstantAction + event: !type:WakeActionEvent - type: entity + parent: BaseImplantAction id: ActionActivateHonkImplant name: Honk description: Activates your honking implant, which will produce the signature sound of the clown. components: - - type: InstantAction + - type: Action icon: { sprite: Objects/Fun/bikehorn.rsi, state: icon } - event: !type:ActivateImplantEvent useDelay: 1 - type: entity + parent: BaseAction id: ActionFireStarter name: Ignite description: Ignites enemies in a radius around you. components: - - type: InstantAction + - type: Action priority: -1 useDelay: 30 icon: Interface/Actions/firestarter.png + - type: InstantAction event: !type:FireStarterActionEvent - type: entity + parent: BaseMentalAction id: ActionToggleEyes name: Open/Close eyes description: Close your eyes to protect your peepers, or open your eyes to enjoy the pretty lights. components: - - type: InstantAction + - type: Action icon: Interface/Actions/eyeopen.png iconOn: Interface/Actions/eyeclose.png - event: !type:ToggleEyesActionEvent useDelay: 1 # so u cant give yourself and observers eyestrain by rapidly spamming the action - checkCanInteract: false - checkConsciousness: false + - type: InstantAction + event: !type:ToggleEyesActionEvent - type: entity + parent: BaseToggleAction id: ActionToggleWagging name: Wagging Tail description: Start or stop wagging your tail. components: - - type: InstantAction - icon: { sprite: Mobs/Customization/reptilian_parts.rsi, state: tail_smooth_behind } - iconOn: { sprite: Mobs/Customization/reptilian_parts.rsi, state: tail_smooth_behind } - itemIconStyle: NoItem - useDelay: 1 # emote spam - event: !type:ToggleActionEvent + - type: Action + icon: { sprite: Mobs/Customization/reptilian_parts.rsi, state: tail_smooth_behind } + iconOn: { sprite: Mobs/Customization/reptilian_parts.rsi, state: tail_smooth_behind } + itemIconStyle: NoItem + useDelay: 1 # emote spam + checkCanInteract: false - type: entity + parent: BaseAction id: FakeMindShieldToggleAction name: '[color=green]Toggle Fake Mindshield[/color]' description: Turn the Fake Mindshield implant's transmission on/off components: - - type: InstantAction + - type: Action icon: { sprite: Interface/Actions/actions_fakemindshield.rsi, state: icon } iconOn: { sprite: Interface/Actions/actions_fakemindshield.rsi, state: icon-on } itemIconStyle: NoItem useDelay: 1 + - type: InstantAction event: !type:FakeMindShieldToggleEvent + - type: Tag + tags: + - FakeMindShieldImplant - type: entity + parent: BaseToggleAction id: ActionToggleParamedicSiren name: Toggle Paramedic Siren description: Toggles the paramedic siren on and off. components: - - type: InstantAction + - type: Action icon: sprite: Clothing/OuterClothing/Hardsuits/paramed.rsi state: icon-siren useDelay: 1 itemIconStyle: BigAction - event: !type:ToggleActionEvent + +- type: entity + parent: BaseToggleAction + id: ActionToggleRootable + name: Rootable + description: Begin or stop being rooted to the floor. + components: + - type: Action + icon: Interface/Actions/rooting.png + iconOn: Interface/Actions/rooting.png + itemIconStyle: NoItem + useDelay: 1 + +- type: entity + id: ActionChameleonController + name: Control clothing + description: Change your entire outfit fast! + components: + - type: Action + priority: -20 + icon: { sprite: Actions/Implants/implants.rsi, state: chameleon } + itemIconStyle: BigAction + - type: InstantAction + event: !type:ChameleonControllerOpenMenuEvent \ No newline at end of file