Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Station AI ability to electricute doors #32012

Open
wants to merge 27 commits into
base: master
Choose a base branch
from

Conversation

Fildrance
Copy link
Contributor

@Fildrance Fildrance commented Sep 9, 2024

About the PR

AI now have ability to electrify airlocks.
AI now have ability to set door to EmergencyAccess (yellow-lights-door).
AI now have better feedback on actions with airlocks: new icons for radial menu, sound effects

Why / Balance

AI can now help low-pop crew by setting some non-critical doors to emergency-access, enabling people to access medical self-care without breaking law (and doors).
AI can have quite harmful laws but it doesn't have any way to implement them. Electrifying doors is first step how AI can dominate human race and show who is master of the station (in not entirely gamebreaking way).

Technical details

ElectrifiedComponent was moved to shared to indicate is it On/Off for AI actions radial menu. It is marked dirty on IsEnabled change, logic was not transferred to shared.
SharedAirlockSystem.ToggleEmergencyAccess was changed to SetEmergencyAccess so AI commands can be more predictable.

Media

device_not_responding.1.mp4
bolt_showcase.mp4
overcharge_showcase.mp4
ai_wire_showcase.mp4

Requirements

Breaking changes

none

Changelog

🆑 Fildrance, ScarKy0

  • add: AI now can electrify doors and set them to emergency access. Setting door to emergency access will now play sound effect for everyone around, while electrifying door will play sound effect only for AI
  • fix: AI will now be notified when trying to interact with door without power or when respective wires were messed up with

@github-actions github-actions bot added the Changes: Sprites Should be reviewed or fixed by people who are knowledgeable with spriting or visual design. label Sep 9, 2024
Copy link
Contributor

github-actions bot commented Sep 9, 2024

RSI Diff Bot; head commit c1f9f60 merging into 2a6f15d
This PR makes changes to 1 or more RSIs. Here is a summary of all changes:

Resources/Textures/Interface/Actions/actions_ai.rsi

State Old New Status
bolt_door Added
door_overcharge_off Added
door_overcharge_on Added
emergency_off Added
emergency_on Added
unbolt_door Added

Edit: diff updated after c1f9f60

@ScarKy0
Copy link
Contributor

ScarKy0 commented Sep 9, 2024

Hype


namespace Content.Shared.Silicons.StationAi;

public abstract partial class SharedStationAiSystem
{
private static readonly SoundPathSpecifier AirlockOverchargeDisabled = new("/Audio/Machines/airlock_overcharge_on.ogg");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldnt you put those in the component or would that break things?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure where to put this. Maybe maint will propose good ideas. AirlockComponent is not used in this code path, ElectrifyComponent - well, fine but its still wierd... its only hear-able to AI.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's only hear-able to AI, maybe put specifiers into AI Core or Held? It would allow change audio paths in prototypes...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@metalgearsloth what do you think about moving this to HeldComponent example? sounds a bit sus

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be wherever stuff is electrified, also don't call it "overcharge" because it's just confusing what it's for.

"name": "unelectrify_door"
},
{
"name": "door_overcharge_on"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New ones are CC0-1.0 by ScarKy0, don't really know how to add this info to license and copyright! :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inserted new files and mention side-by-side... folder fits too well...

@Fildrance Fildrance changed the title Feature/ai door electricute for real Station AI ability to electricute doors Sep 10, 2024
@Fildrance Fildrance marked this pull request as ready for review September 10, 2024 19:49
@github-actions github-actions bot added the Status: Needs Review This PR requires new reviews before it can be merged. label Sep 10, 2024
@JIPDawg
Copy link
Contributor

JIPDawg commented Sep 10, 2024

Headphone warning for the Airhorn when electrifying the door. Ouch. My only complaints are the sound made when electrifying the door, why a airhorn? I also still don't like the sound for Emergency access either. Just my 2 cents.

@ScarKy0 ScarKy0 mentioned this pull request Sep 10, 2024
2 tasks
@ScarKy0
Copy link
Contributor

ScarKy0 commented Sep 10, 2024

Headphone warning for the Airhorn when electrifying the door. Ouch. My only complaints are the sound made when electrifying the door, why a airhorn? I also still don't like the sound for Emergency access either. Just my 2 cents.

Its mostly due to the quality of the clips, i believe

Comment on lines 41 to 52
[Dependency] private readonly SharedElectrocutionSystem _electrify = default!;
[Dependency] private readonly SharedAirlockSystem _airlocks = default!;
[Dependency] private readonly SharedEyeSystem _eye = default!;
[Dependency] protected readonly SharedMapSystem Maps = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly SharedMoverController _mover = default!;
[Dependency] private readonly SharedTransformSystem _xforms = default!;
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly StationAiVisionSystem _vision = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] protected readonly SharedPowerReceiverSystem PowerReceiver = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alphabetical and follow format of the existing stuff please I beg.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fine, but it was not me who started it (39 line by original file)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not 100% sure what u wanted but i sorted it all by field names.

Comment on lines 148 to 160
var verb = new AlternativeVerb
{
Text = isOpen ? Loc.GetString("ai-close") : Loc.GetString("ai-open"),
Act = () =>
{
// no need to show menu if device is not powered.
SharedApcPowerReceiverComponent? component = null;
if (PowerReceiver.ResolveApc(ent.Owner, ref component) && !component.Powered)
{
_popup.PopupClient(Loc.GetString("ai-device-not-responding"), user, PopupType.MediumCaution);
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not hardcode in devices here, it's supposed to be generic. Use an event or anything else.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I swear PowerReceiver.IsPowered was throwing exception... but now i tested it and it works fine for all cases. Oh well...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines 65 to 82
private void OnElectrified(EntityUid ent, ElectrifiedComponent component, StationAiElectrifiedEvent args)
{
if (!TryComp<ElectrifiedComponent>(ent, out var electrified)
|| !TryComp<StationAiWhitelistComponent>(ent, out var whiteList))
{
return;
}

SharedApcPowerReceiverComponent? apcPowerReceiverComponent = null;
if (
!whiteList.Enabled
|| electrified.IsWireCut
|| (
PowerReceiver.ResolveApc(ent, ref apcPowerReceiverComponent)
&& !apcPowerReceiverComponent.Powered
)
)
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whitelist comp gets handled in the BUI attempt event, having to check this manually every single time is bug prone and shouldn't be done.

Just add the whitelist enabled check to it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'll send popup from there, ye. It checks out pretty well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines 90 to 91
: AirlockOverchargeEnabled;
_audio.PlayEntity(soundToPlay, args.User, ent);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the predicted version this isn't predicted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines 52 to 58

if (!whiteList.Enabled || !component.Powered)
{
_popup.PopupClient(Loc.GetString("ai-device-not-responding"), args.User, PopupType.MediumCaution);
return;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AirlockComponent.Powered is obsolete please don't use it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

used PowerReceiver.IsPowered instead. we might need to mark it obsolete and remove related code btw... its really misleading...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it true for bolts component?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed, and used PowerReceiver system

Comment on lines 33 to 39

if (!whiteList.Enabled || component.BoltWireCut || !component.Powered)
{
_popup.PopupClient(Loc.GetString("ai-device-not-responding"), args.User, PopupType.MediumCaution);
return;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The latter 3 checks should be handled via a setbolts overload not here because other callers will forget to do this.

Enabled as mentioned should be handled in the BUI message attempt.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to add TrySetBolt to send popup in case it fails

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@metalgearsloth metalgearsloth added Status: Awaiting Changes This PR needs its reviews addressed or changes to be made in order to be merged. and removed Status: Needs Review This PR requires new reviews before it can be merged. labels Sep 11, 2024
@Fildrance
Copy link
Contributor Author

Updated media with cool (and more up to date) video from ScarKy0

@github-actions github-actions bot added Status: Needs Review This PR requires new reviews before it can be merged. and removed Status: Awaiting Changes This PR needs its reviews addressed or changes to be made in order to be merged. labels Sep 12, 2024
Copy link
Contributor

@ScarKy0 ScarKy0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine to me

Comment on lines 143 to 144
|| !HasComp<StationAiHeldComponent>(args.User)
|| !HasComp<StationAiWhitelistComponent>(args.Target))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this whitelist check is unneeded?

Copy link
Contributor Author

@Fildrance Fildrance Sep 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is, i belive, currently overlapping with OnHeldInteraction, but i'm not 100% sure it covers every possible scenario

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seemed good when i tested it - so i removed condition check duplication!

Comment on lines 111 to 116
StationAiWhitelistComponent? whitelistComponent = null;
if (TryComp(ev.Actor, out StationAiHeldComponent? aiComp) &&
(!ValidateAi((ev.Actor, aiComp)) ||
!HasComp<StationAiWhitelistComponent>(ev.Target)))
!TryComp(ev.Target, out whitelistComponent)))
{
ev.Cancel();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just inline the component no reason to leave it separate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean - use one block? and always call ShowDeviceNotRespondingPopup? this doesn't sound right - popup is kinda bound to whitelistComponent is { Enabled: false } scenario - there is no reason to show it if ai is not valid or we have no StationAiHeldComponent comp

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot inline declaration because then declaration (which is required in the next lines) will be optional (based on previous conditions eval) and code won't compile :(

Copy link
Contributor Author

@Fildrance Fildrance Sep 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And i don't want popup spam on every click! :/ so i want popup in separate condition... otherwise it will spam popup on every click, anywhere (walls included).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It absolutely will compile, the only reason it won't is if you don't get the component out of it, just adjust the if statement for it.

Comment on lines 58 to 64
private void OnElectrified(EntityUid ent, ElectrifiedComponent component, StationAiElectrifiedEvent args)
{
if (!TryComp<ElectrifiedComponent>(ent, out var electrified))
{
return;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This component is doubled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!yea

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines 491 to 494

public void SetElectrifiedWireCut(Entity<ElectrifiedComponent> ent, bool value)
{
ent.Comp.IsWireCut = value;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should guard these values behind equals checks to avoid dirtying if the value hasn't changed because dirtying is expensive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines 27 to 38

/// <summary>
/// Sound to play when the airlock emergency access is turned on.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier EmergencyOnSound = new SoundPathSpecifier("/Audio/Machines/airlock_emergencyon.ogg");

/// <summary>
/// Sound to play when the airlock emergency access is turned off.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier EmergencyOffSound = new SoundPathSpecifier("/Audio/Machines/airlock_emergencyoff.ogg");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VVRW is redundant with datafield.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines +139 to 145

var sound = ent.Comp.EmergencyAccess ? ent.Comp.EmergencyOnSound : ent.Comp.EmergencyOffSound;
if (predicted)
Audio.PlayPredicted(sound, ent, user: user);
else
Audio.PlayPvs(sound, ent);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do any of the callers even need this? This method is new...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AdminVerbSystem uses non-predicted version. is that wrong?

Comment on lines 26 to 37
/// <summary>
/// Sets electrified value of component and marks dirty if required.
/// </summary>
public void SetElectrified(Entity<ElectrifiedComponent> ent, bool value)
{
var oldValue = ent.Comp.Enabled;
ent.Comp.Enabled = value;
if (value != oldValue)
{
Dirty(ent, ent.Comp);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You did it here but also this is written in a weird way, just check if the values are the same before assigning (not sure if the JIT even accounts for this?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.


namespace Content.Shared.Silicons.StationAi;

public abstract partial class SharedStationAiSystem
{
private static readonly SoundPathSpecifier AirlockOverchargeDisabled = new("/Audio/Machines/airlock_overcharge_on.ogg");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be wherever stuff is electrified, also don't call it "overcharge" because it's just confusing what it's for.

Comment on lines 111 to 116
StationAiWhitelistComponent? whitelistComponent = null;
if (TryComp(ev.Actor, out StationAiHeldComponent? aiComp) &&
(!ValidateAi((ev.Actor, aiComp)) ||
!HasComp<StationAiWhitelistComponent>(ev.Target)))
!TryComp(ev.Target, out whitelistComponent)))
{
ev.Cancel();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It absolutely will compile, the only reason it won't is if you don't get the component out of it, just adjust the if statement for it.

Comment on lines 31 to 53
[Dependency] private readonly ISharedAdminManager _admin = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly ItemSlotsSystem _slots = default!;
[Dependency] private readonly ItemToggleSystem _toggles = default!;
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
[Dependency] private readonly MetaDataSystem _metadata = default!;
[Dependency] private readonly SharedAirlockSystem _airlocks = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
[Dependency] private readonly SharedContainerSystem _containers = default!;
[Dependency] private readonly SharedDoorSystem _doors = default!;
[Dependency] private readonly SharedElectrocutionSystem _electrify = default!;
[Dependency] private readonly SharedEyeSystem _eye = default!;
[Dependency] protected readonly SharedMapSystem Maps = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly MetaDataSystem _metadata = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly SharedMoverController _mover = default!;
[Dependency] private readonly SharedTransformSystem _xforms = default!;
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly ItemSlotsSystem _slots = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly ItemToggleSystem _toggles = default!;
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly StationAiVisionSystem _vision = default!;
[Dependency] private readonly SharedTransformSystem _xforms = default!;
[Dependency] protected readonly SharedMapSystem Maps = default!;
[Dependency] private readonly SharedPowerReceiverSystem PowerReceiver = default!;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a dog's breakfast please just make it alphabetical like it used to be.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thats a wierd way to sort it. ok, done.

@metalgearsloth metalgearsloth added Status: Awaiting Changes This PR needs its reviews addressed or changes to be made in order to be merged. and removed Status: Needs Review This PR requires new reviews before it can be merged. labels Sep 21, 2024
@github-actions github-actions bot added Status: Needs Review This PR requires new reviews before it can be merged. and removed Status: Awaiting Changes This PR needs its reviews addressed or changes to be made in order to be merged. labels Sep 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changes: Sprites Should be reviewed or fixed by people who are knowledgeable with spriting or visual design. Status: Needs Review This PR requires new reviews before it can be merged. Undergoing Maintainer Discussion This PR is currently going through the 72-hour discussion window as per maintainer policy
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants