Skip to content

Commit 4bcf3c3

Browse files
FildranceScarKy0pa.pecherskijmetalgearsloth
authored
Station AI ability to electricute doors (space-wizards#32012)
* Boom! Emergency access! * Emergency access sound * locale * Updated sounds * bleh * Door electrify base * feat: popups on attempt to activate AI action when wires cut * refactor: use SharedApcPowerReceiverComponent to check if AI can interact with door * refactor: added icon and sound for door overcharge * meta.json should use tabs not spaces * refactor: extracted sounds for airlock overcharge to static field in system * refactor: cleanup, ScarKy0 mentions for resources * refactor: removed unused textures * feat: now notification is displayed when AI attempting to interact with door which have wire cut * StationAiWhitelistComponent is properly gating BUI OnMessageAttempt, SharedPowerReceiverSystem.IsPowered is now used to check if device powered * refactor: use PlayLocal to play electrify sound only for AI player * refactor: SetBoltsDown now uses TrySetBoltDown, checks for power. * bolts now check for power using SharedPowerReceiverSystem * electrify localization and louder electrify sounds * extracted ShowDeviceNotRespondingPopup, reverted airlocks not opening/closing when ai wire was cut * refactor: cleanup * New sprites and fixes * Copyright * even more sprite changes * refactore: cleanup, rename overcharge => electrify --------- Co-authored-by: ScarKy0 <[email protected]> Co-authored-by: pa.pecherskij <[email protected]> Co-authored-by: metalgearsloth <[email protected]>
1 parent 0d26bb0 commit 4bcf3c3

30 files changed

+371
-109
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,75 @@
11
using Content.Shared.Doors.Components;
2+
using Content.Shared.Electrocution;
23
using Content.Shared.Silicons.StationAi;
34
using Robust.Shared.Utility;
45

56
namespace Content.Client.Silicons.StationAi;
67

78
public sealed partial class StationAiSystem
89
{
10+
private readonly ResPath _aiActionsRsi = new ResPath("/Textures/Interface/Actions/actions_ai.rsi");
11+
912
private void InitializeAirlock()
1013
{
1114
SubscribeLocalEvent<DoorBoltComponent, GetStationAiRadialEvent>(OnDoorBoltGetRadial);
15+
SubscribeLocalEvent<AirlockComponent, GetStationAiRadialEvent>(OnEmergencyAccessGetRadial);
16+
SubscribeLocalEvent<ElectrifiedComponent, GetStationAiRadialEvent>(OnDoorElectrifiedGetRadial);
1217
}
1318

1419
private void OnDoorBoltGetRadial(Entity<DoorBoltComponent> ent, ref GetStationAiRadialEvent args)
1520
{
16-
args.Actions.Add(new StationAiRadial()
17-
{
18-
Sprite = ent.Comp.BoltsDown ?
19-
new SpriteSpecifier.Rsi(
20-
new ResPath("/Textures/Structures/Doors/Airlocks/Standard/basic.rsi"), "open") :
21-
new SpriteSpecifier.Rsi(
22-
new ResPath("/Textures/Structures/Doors/Airlocks/Standard/basic.rsi"), "closed"),
23-
Tooltip = ent.Comp.BoltsDown ? Loc.GetString("bolt-open") : Loc.GetString("bolt-close"),
24-
Event = new StationAiBoltEvent()
21+
args.Actions.Add(
22+
new StationAiRadial
23+
{
24+
Sprite = ent.Comp.BoltsDown
25+
? new SpriteSpecifier.Rsi(_aiActionsRsi, "unbolt_door")
26+
: new SpriteSpecifier.Rsi(_aiActionsRsi, "bolt_door"),
27+
Tooltip = ent.Comp.BoltsDown
28+
? Loc.GetString("bolt-open")
29+
: Loc.GetString("bolt-close"),
30+
Event = new StationAiBoltEvent
31+
{
32+
Bolted = !ent.Comp.BoltsDown,
33+
}
34+
}
35+
);
36+
}
37+
38+
private void OnEmergencyAccessGetRadial(Entity<AirlockComponent> ent, ref GetStationAiRadialEvent args)
39+
{
40+
args.Actions.Add(
41+
new StationAiRadial
42+
{
43+
Sprite = ent.Comp.EmergencyAccess
44+
? new SpriteSpecifier.Rsi(_aiActionsRsi, "emergency_off")
45+
: new SpriteSpecifier.Rsi(_aiActionsRsi, "emergency_on"),
46+
Tooltip = ent.Comp.EmergencyAccess
47+
? Loc.GetString("emergency-access-off")
48+
: Loc.GetString("emergency-access-on"),
49+
Event = new StationAiEmergencyAccessEvent
50+
{
51+
EmergencyAccess = !ent.Comp.EmergencyAccess,
52+
}
53+
}
54+
);
55+
}
56+
57+
private void OnDoorElectrifiedGetRadial(Entity<ElectrifiedComponent> ent, ref GetStationAiRadialEvent args)
58+
{
59+
args.Actions.Add(
60+
new StationAiRadial
2561
{
26-
Bolted = !ent.Comp.BoltsDown,
62+
Sprite = ent.Comp.Enabled
63+
? new SpriteSpecifier.Rsi(_aiActionsRsi, "door_overcharge_off")
64+
: new SpriteSpecifier.Rsi(_aiActionsRsi, "door_overcharge_on"),
65+
Tooltip = ent.Comp.Enabled
66+
? Loc.GetString("electrify-door-off")
67+
: Loc.GetString("electrify-door-on"),
68+
Event = new StationAiElectrifiedEvent
69+
{
70+
Electrified = !ent.Comp.Enabled,
71+
}
2772
}
28-
});
73+
);
2974
}
3075
}

Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -90,22 +90,22 @@ private void AddTricksVerbs(GetVerbsEvent<Verb> args)
9090
args.Verbs.Add(bolt);
9191
}
9292

93-
if (TryComp<AirlockComponent>(args.Target, out var airlock))
93+
if (TryComp<AirlockComponent>(args.Target, out var airlockComp))
9494
{
9595
Verb emergencyAccess = new()
9696
{
97-
Text = airlock.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On",
97+
Text = airlockComp.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On",
9898
Category = VerbCategory.Tricks,
9999
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/emergency_access.png")),
100100
Act = () =>
101101
{
102-
_airlockSystem.ToggleEmergencyAccess(args.Target, airlock);
102+
_airlockSystem.SetEmergencyAccess((args.Target, airlockComp), !airlockComp.EmergencyAccess);
103103
},
104104
Impact = LogImpact.Medium,
105-
Message = Loc.GetString(airlock.EmergencyAccess
105+
Message = Loc.GetString(airlockComp.EmergencyAccess
106106
? "admin-trick-emergency-access-off-description"
107107
: "admin-trick-emergency-access-on-description"),
108-
Priority = (int) (airlock.EmergencyAccess ? TricksVerbPriorities.EmergencyAccessOff : TricksVerbPriorities.EmergencyAccessOn),
108+
Priority = (int) (airlockComp.EmergencyAccess ? TricksVerbPriorities.EmergencyAccessOff : TricksVerbPriorities.EmergencyAccessOn),
109109
};
110110
args.Verbs.Add(emergencyAccess);
111111
}

Content.Server/Construction/Completions/AttemptElectrocute.cs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Content.Server.Electrocution;
2+
using Content.Shared.Electrocution;
23
using Content.Shared.Construction;
34

45
namespace Content.Server.Construction.Completions;

Content.Server/Doors/WireActions/DoorBoltWireAction.cs

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using Content.Server.Wires;
33
using Content.Shared.Doors;
44
using Content.Shared.Doors.Components;
5-
using Content.Shared.Doors.Systems;
65
using Content.Shared.Wires;
76

87
namespace Content.Server.Doors;

Content.Server/Electrocution/ElectrocutionSystem.cs

+11
Original file line numberDiff line numberDiff line change
@@ -488,4 +488,15 @@ private void PlayElectrocutionSound(EntityUid targetUid, EntityUid sourceUid, El
488488
}
489489
_audio.PlayPvs(electrified.ShockNoises, targetUid, AudioParams.Default.WithVolume(electrified.ShockVolume));
490490
}
491+
492+
public void SetElectrifiedWireCut(Entity<ElectrifiedComponent> ent, bool value)
493+
{
494+
if (ent.Comp.IsWireCut == value)
495+
{
496+
return;
497+
}
498+
499+
ent.Comp.IsWireCut = value;
500+
Dirty(ent);
501+
}
491502
}

Content.Server/Power/PowerWireAction.cs

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Content.Server.Electrocution;
2+
using Content.Shared.Electrocution;
23
using Content.Server.Power.Components;
34
using Content.Server.Wires;
45
using Content.Shared.Power;
@@ -104,6 +105,7 @@ private void SetElectrified(EntityUid used, bool setting, ElectrifiedComponent?
104105
&& !EntityManager.TryGetComponent(used, out electrified))
105106
return;
106107

108+
_electrocutionSystem.SetElectrifiedWireCut((used, electrified), setting);
107109
electrified.Enabled = setting;
108110
}
109111

Content.Server/Remotes/DoorRemoteSystem.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ private void OnBeforeInteract(Entity<DoorRemoteComponent> entity, ref BeforeRang
7474
case OperatingMode.ToggleEmergencyAccess:
7575
if (airlockComp != null)
7676
{
77-
_airlock.ToggleEmergencyAccess(args.Target.Value, airlockComp);
77+
_airlock.SetEmergencyAccess((args.Target.Value, airlockComp), !airlockComp.EmergencyAccess);
7878
_adminLogger.Add(LogType.Action, LogImpact.Medium,
7979
$"{ToPrettyString(args.User):player} used {ToPrettyString(args.Used)} on {ToPrettyString(args.Target.Value)} to set emergency access {(airlockComp.EmergencyAccess ? "on" : "off")}");
8080
}

Content.Shared/Doors/Components/AirlockComponent.cs

+13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Content.Shared.DeviceLinking;
22
using Content.Shared.Doors.Systems;
3+
using Robust.Shared.Audio;
34
using Robust.Shared.GameStates;
45
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
56

@@ -23,6 +24,18 @@ public sealed partial class AirlockComponent : Component
2324
[ViewVariables(VVAccess.ReadWrite)]
2425
[DataField, AutoNetworkedField]
2526
public bool EmergencyAccess = false;
27+
28+
/// <summary>
29+
/// Sound to play when the airlock emergency access is turned on.
30+
/// </summary>
31+
[DataField]
32+
public SoundSpecifier EmergencyOnSound = new SoundPathSpecifier("/Audio/Machines/airlock_emergencyon.ogg");
33+
34+
/// <summary>
35+
/// Sound to play when the airlock emergency access is turned off.
36+
/// </summary>
37+
[DataField]
38+
public SoundSpecifier EmergencyOffSound = new SoundPathSpecifier("/Audio/Machines/airlock_emergencyoff.ogg");
2639

2740
/// <summary>
2841
/// Pry modifier for a powered airlock.

Content.Shared/Doors/Systems/SharedAirlockSystem.cs

+19-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Content.Shared.Doors.Components;
2+
using Robust.Shared.Audio.Systems;
23
using Content.Shared.Popups;
34
using Content.Shared.Prying.Components;
45
using Content.Shared.Wires;
@@ -10,7 +11,9 @@ public abstract class SharedAirlockSystem : EntitySystem
1011
{
1112
[Dependency] private readonly IGameTiming _timing = default!;
1213
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
14+
[Dependency] protected readonly SharedAudioSystem Audio = default!;
1315
[Dependency] protected readonly SharedDoorSystem DoorSystem = default!;
16+
[Dependency] protected readonly SharedPopupSystem Popup = default!;
1417
[Dependency] private readonly SharedWiresSystem _wiresSystem = default!;
1518

1619
public override void Initialize()
@@ -131,11 +134,23 @@ public void UpdateEmergencyLightStatus(EntityUid uid, AirlockComponent component
131134
Appearance.SetData(uid, DoorVisuals.EmergencyLights, component.EmergencyAccess);
132135
}
133136

134-
public void ToggleEmergencyAccess(EntityUid uid, AirlockComponent component)
137+
public void SetEmergencyAccess(Entity<AirlockComponent> ent, bool value, EntityUid? user = null, bool predicted = false)
135138
{
136-
component.EmergencyAccess = !component.EmergencyAccess;
137-
Dirty(uid, component); // This only runs on the server apparently so we need this.
138-
UpdateEmergencyLightStatus(uid, component);
139+
if(!ent.Comp.Powered)
140+
return;
141+
142+
if (ent.Comp.EmergencyAccess == value)
143+
return;
144+
145+
ent.Comp.EmergencyAccess = value;
146+
Dirty(ent, ent.Comp); // This only runs on the server apparently so we need this.
147+
UpdateEmergencyLightStatus(ent, ent.Comp);
148+
149+
var sound = ent.Comp.EmergencyAccess ? ent.Comp.EmergencyOnSound : ent.Comp.EmergencyOffSound;
150+
if (predicted)
151+
Audio.PlayPredicted(sound, ent, user: user);
152+
else
153+
Audio.PlayPvs(sound, ent);
139154
}
140155

141156
public void SetAutoCloseDelayModifier(AirlockComponent component, float value)

Content.Shared/Doors/Systems/SharedDoorSystem.Bolts.cs

+14-1
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,20 @@ public void SetBoltLightsEnabled(Entity<DoorBoltComponent> ent, bool value)
7777

7878
public void SetBoltsDown(Entity<DoorBoltComponent> ent, bool value, EntityUid? user = null, bool predicted = false)
7979
{
80+
TrySetBoltDown(ent, value, user, predicted);
81+
}
82+
83+
public bool TrySetBoltDown(
84+
Entity<DoorBoltComponent> ent,
85+
bool value,
86+
EntityUid? user = null,
87+
bool predicted = false
88+
)
89+
{
90+
if (!_powerReceiver.IsPowered(ent.Owner))
91+
return false;
8092
if (ent.Comp.BoltsDown == value)
81-
return;
93+
return false;
8294

8395
ent.Comp.BoltsDown = value;
8496
Dirty(ent, ent.Comp);
@@ -89,6 +101,7 @@ public void SetBoltsDown(Entity<DoorBoltComponent> ent, bool value, EntityUid? u
89101
Audio.PlayPredicted(sound, ent, user: user);
90102
else
91103
Audio.PlayPvs(sound, ent);
104+
return true;
92105
}
93106

94107
private void OnStateChanged(Entity<DoorBoltComponent> entity, ref DoorStateChangedEvent args)

Content.Shared/Doors/Systems/SharedDoorSystem.cs

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Content.Shared.Interaction;
1010
using Content.Shared.Physics;
1111
using Content.Shared.Popups;
12+
using Content.Shared.Power.EntitySystems;
1213
using Content.Shared.Prying.Components;
1314
using Content.Shared.Prying.Systems;
1415
using Content.Shared.Stunnable;
@@ -42,6 +43,7 @@ public abstract partial class SharedDoorSystem : EntitySystem
4243
[Dependency] private readonly PryingSystem _pryingSystem = default!;
4344
[Dependency] protected readonly SharedPopupSystem Popup = default!;
4445
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
46+
[Dependency] private readonly SharedPowerReceiverSystem _powerReceiver = default!;
4547

4648

4749
[ValidatePrototypeId<TagPrototype>]

0 commit comments

Comments
 (0)