Intellicards now have a doAfter. (#33198)

* init

* cleanup

* Oops! Forgot something

* addressing changes

* guh

* guh 2.0

* some cleanup

* all bless the intellicard

* Yippee

* small locale thing

* changes + small bugfix

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
This commit is contained in:
ScarKy0
2024-11-09 20:29:29 +01:00
committed by GitHub
parent 40044203e6
commit 287a9a07de
7 changed files with 153 additions and 7 deletions

View File

@@ -1,10 +1,11 @@
using System.Linq;
using Content.Server.Chat.Managers;
using Content.Server.Chat.Systems;
using Content.Shared.Chat;
using Content.Shared.Mind;
using Content.Shared.Roles;
using Content.Shared.Silicons.StationAi;
using Content.Shared.StationAi;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Audio;
using Robust.Shared.Map.Components;
using Robust.Shared.Player;
@@ -14,6 +15,8 @@ public sealed class StationAiSystem : SharedStationAiSystem
{
[Dependency] private readonly IChatManager _chats = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly SharedRoleSystem _roles = default!;
private readonly HashSet<Entity<StationAiCoreComponent>> _ais = new();
@@ -43,6 +46,19 @@ public sealed class StationAiSystem : SharedStationAiSystem
return true;
}
public override void AnnounceIntellicardUsage(EntityUid uid, SoundSpecifier? cue = null)
{
if (!TryComp<ActorComponent>(uid, out var actor))
return;
var msg = Loc.GetString("ai-consciousness-download-warning");
var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", msg));
_chats.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, actor.PlayerSession.Channel, colorOverride: Color.Red);
if (cue != null && _mind.TryGetMind(uid, out var mindId, out _))
_roles.MindPlaySound(mindId, cue);
}
private void AnnounceSnip(EntityUid entity)
{
var xform = Transform(entity);

View File

@@ -0,0 +1,39 @@
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Intellicard;
/// <summary>
/// Allows this entity to download the station AI onto an AiHolderComponent.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class IntellicardComponent : Component
{
/// <summary>
/// The duration it takes to download the AI from an AiHolder.
/// </summary>
[DataField, AutoNetworkedField]
public int DownloadTime = 15;
/// <summary>
/// The duration it takes to upload the AI to an AiHolder.
/// </summary>
[DataField, AutoNetworkedField]
public int UploadTime = 3;
/// <summary>
/// The sound that plays for the AI
/// when they are being downloaded
/// </summary>
[DataField, AutoNetworkedField]
public SoundSpecifier? WarningSound = new SoundPathSpecifier("/Audio/Misc/notice2.ogg");
/// <summary>
/// The delay before allowing the warning to play again in seconds.
/// </summary>
[DataField, AutoNetworkedField]
public TimeSpan WarningDelay = TimeSpan.FromSeconds(8);
[ViewVariables]
public TimeSpan NextWarningAllowed = TimeSpan.Zero;
}

View File

@@ -54,7 +54,7 @@ public abstract partial class SharedStationAiSystem
}
/// <summary>
/// Tries to get the entity held in the AI core.
/// Tries to get the entity held in the AI core using StationAiCore.
/// </summary>
private bool TryGetHeld(Entity<StationAiCoreComponent?> entity, out EntityUid held)
{
@@ -71,6 +71,24 @@ public abstract partial class SharedStationAiSystem
return true;
}
/// <summary>
/// Tries to get the entity held in the AI using StationAiHolder.
/// </summary>
private bool TryGetHeldFromHolder(Entity<StationAiHolderComponent?> entity, out EntityUid held)
{
held = EntityUid.Invalid;
if (!Resolve(entity.Owner, ref entity.Comp))
return false;
if (!_containers.TryGetContainer(entity.Owner, StationAiHolderComponent.Container, out var container) ||
container.ContainedEntities.Count == 0)
return false;
held = container.ContainedEntities[0];
return true;
}
private bool TryGetCore(EntityUid ent, out Entity<StationAiCoreComponent?> core)
{
if (!_containers.TryGetContainingContainer(ent, out var container) ||

View File

@@ -4,7 +4,9 @@ using Content.Shared.Administration.Managers;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Database;
using Content.Shared.Doors.Systems;
using Content.Shared.DoAfter;
using Content.Shared.Electrocution;
using Content.Shared.Intellicard;
using Content.Shared.Interaction;
using Content.Shared.Item.ItemToggle;
using Content.Shared.Mind;
@@ -15,6 +17,7 @@ using Content.Shared.Power;
using Content.Shared.Power.EntitySystems;
using Content.Shared.StationAi;
using Content.Shared.Verbs;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Map.Components;
@@ -40,6 +43,7 @@ public abstract partial class SharedStationAiSystem : EntitySystem
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedContainerSystem _containers = default!;
[Dependency] private readonly SharedDoorSystem _doors = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedElectrocutionSystem _electrify = default!;
[Dependency] private readonly SharedEyeSystem _eye = default!;
[Dependency] protected readonly SharedMapSystem Maps = default!;
@@ -87,6 +91,7 @@ public abstract partial class SharedStationAiSystem : EntitySystem
SubscribeLocalEvent<StationAiHolderComponent, MapInitEvent>(OnHolderMapInit);
SubscribeLocalEvent<StationAiHolderComponent, EntInsertedIntoContainerMessage>(OnHolderConInsert);
SubscribeLocalEvent<StationAiHolderComponent, EntRemovedFromContainerMessage>(OnHolderConRemove);
SubscribeLocalEvent<StationAiHolderComponent, IntellicardDoAfterEvent>(OnIntellicardDoAfter);
SubscribeLocalEvent<StationAiCoreComponent, EntInsertedIntoContainerMessage>(OnAiInsert);
SubscribeLocalEvent<StationAiCoreComponent, EntRemovedFromContainerMessage>(OnAiRemove);
@@ -197,15 +202,22 @@ public abstract partial class SharedStationAiSystem : EntitySystem
args.InRange = _vision.IsAccessible((targetXform.GridUid.Value, broadphase, grid), targetTile);
}
private void OnHolderInteract(Entity<StationAiHolderComponent> ent, ref AfterInteractEvent args)
private void OnIntellicardDoAfter(Entity<StationAiHolderComponent> ent, ref IntellicardDoAfterEvent args)
{
if (!TryComp(args.Target, out StationAiHolderComponent? targetHolder))
if (args.Cancelled)
return;
if (args.Handled)
return;
if (!TryComp(args.Args.Target, out StationAiHolderComponent? targetHolder))
return;
// Try to insert our thing into them
if (_slots.CanEject(ent.Owner, args.User, ent.Comp.Slot))
{
if (!_slots.TryInsert(args.Target.Value, targetHolder.Slot, ent.Comp.Slot.Item!.Value, args.User, excludeUserAudio: true))
if (!_slots.TryInsert(args.Args.Target.Value, targetHolder.Slot, ent.Comp.Slot.Item!.Value, args.User, excludeUserAudio: true))
{
return;
}
@@ -215,7 +227,7 @@ public abstract partial class SharedStationAiSystem : EntitySystem
}
// Otherwise try to take from them
if (_slots.CanEject(args.Target.Value, args.User, targetHolder.Slot))
if (_slots.CanEject(args.Args.Target.Value, args.User, targetHolder.Slot))
{
if (!_slots.TryInsert(ent.Owner, ent.Comp.Slot, targetHolder.Slot.Item!.Value, args.User, excludeUserAudio: true))
{
@@ -226,6 +238,55 @@ public abstract partial class SharedStationAiSystem : EntitySystem
}
}
private void OnHolderInteract(Entity<StationAiHolderComponent> ent, ref AfterInteractEvent args)
{
if (args.Handled || !args.CanReach || args.Target == null)
return;
if (!TryComp(args.Target, out StationAiHolderComponent? targetHolder))
return;
//Don't want to download/upload between several intellicards. You can just pick it up at that point.
if (HasComp<IntellicardComponent>(args.Target))
return;
if (!TryComp(args.Used, out IntellicardComponent? intelliComp))
return;
var cardHasAi = _slots.CanEject(ent.Owner, args.User, ent.Comp.Slot);
var coreHasAi = _slots.CanEject(args.Target.Value, args.User, targetHolder.Slot);
if (cardHasAi && coreHasAi)
{
_popup.PopupClient(Loc.GetString("intellicard-core-occupied"), args.User, args.User, PopupType.Medium);
args.Handled = true;
return;
}
if (!cardHasAi && !coreHasAi)
{
_popup.PopupClient(Loc.GetString("intellicard-core-empty"), args.User, args.User, PopupType.Medium);
args.Handled = true;
return;
}
if (TryGetHeldFromHolder((args.Target.Value, targetHolder), out var held) && _timing.CurTime > intelliComp.NextWarningAllowed)
{
intelliComp.NextWarningAllowed = _timing.CurTime + intelliComp.WarningDelay;
AnnounceIntellicardUsage(held, intelliComp.WarningSound);
}
var doAfterArgs = new DoAfterArgs(EntityManager, args.User, cardHasAi ? intelliComp.UploadTime : intelliComp.DownloadTime, new IntellicardDoAfterEvent(), args.Target, ent.Owner)
{
BreakOnDamage = true,
BreakOnMove = true,
NeedHand = true,
BreakOnDropItem = true
};
_doAfter.TryStartDoAfter(doAfterArgs);
args.Handled = true;
}
private void OnHolderInit(Entity<StationAiHolderComponent> ent, ref ComponentInit args)
{
_slots.AddItemSlot(ent.Owner, StationAiHolderComponent.Container, ent.Comp.Slot);
@@ -378,6 +439,8 @@ public abstract partial class SharedStationAiSystem : EntitySystem
_appearance.SetData(entity.Owner, StationAiVisualState.Key, StationAiState.Occupied);
}
public virtual void AnnounceIntellicardUsage(EntityUid uid, SoundSpecifier? cue = null) { }
public virtual bool SetVisionEnabled(Entity<StationAiVisionComponent> entity, bool enabled, bool announce = false)
{
if (entity.Comp.Enabled == enabled)
@@ -419,6 +482,10 @@ public sealed partial class JumpToCoreEvent : InstantActionEvent
}
[Serializable, NetSerializable]
public sealed partial class IntellicardDoAfterEvent : SimpleDoAfterEvent;
[Serializable, NetSerializable]
public enum StationAiVisualState : byte
{

View File

@@ -0,0 +1,3 @@
# General
intellicard-core-occupied = The AI core is already occupied by another digital consciousness.
intellicard-core-empty = The AI core has no digital consciousness to download.

View File

@@ -20,3 +20,5 @@ electrify-door-off = Disable overcharge
toggle-light = Toggle light
ai-device-not-responding = Device is not responding
ai-consciousness-download-warning = Your consciousness is being downloaded.

View File

@@ -301,6 +301,7 @@
unshaded:
Empty: { state: empty }
Occupied: { state: full }
- type: Intellicard
- type: entity
id: PlayerStationAiEmpty