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

DetGadget Hat Revitalization #35438

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
46e23ee
DetGadget Hat
Cojoke-dot Jul 20, 2024
211523b
uh... half-assed item description
Cojoke-dot Jul 20, 2024
5320198
Reduce hat range to one tile, you have to stand on someone to steal t…
Cojoke-dot Jul 20, 2024
0dfa418
Fix Integration Errors
Cojoke-dot Jul 20, 2024
6f40d2d
Only the wearer can access voice commands
Cojoke-dot Jul 21, 2024
d907cf2
Merge branch 'fork/Cojoke-dot/DetGadget' into detgadget-hat-real
ArtisticRoomba Feb 23, 2025
f7f9606
init work - handscomp is unable to be pulled
ArtisticRoomba Feb 23, 2025
49edaf0
second bit of progress
ArtisticRoomba Feb 23, 2025
e3cd997
basic working implementation
ArtisticRoomba Feb 23, 2025
5b29b42
nuke storageslots and add adminlogging
ArtisticRoomba Feb 24, 2025
aaa419b
disallow trolling nukies or hiding objective items
ArtisticRoomba Feb 24, 2025
108c79b
Merge branch 'master' into detgadget-hat-real
ArtisticRoomba Feb 24, 2025
06c2e1d
remove unnecessary tags additions
ArtisticRoomba Feb 24, 2025
5f5dcf1
finish nuking unused tags
ArtisticRoomba Feb 24, 2025
93493be
death to yamllinter
ArtisticRoomba Feb 24, 2025
65f2662
int tests be damned
ArtisticRoomba Feb 24, 2025
584efda
milon is a furry
ArtisticRoomba Feb 24, 2025
4bab745
address review
ArtisticRoomba Feb 24, 2025
7ea219a
upd desc
ArtisticRoomba Feb 24, 2025
27d9f5c
address reviews part 2
ArtisticRoomba Feb 25, 2025
243f6e1
address more reviews
ArtisticRoomba Feb 25, 2025
d6b16fd
remove unused refs
ArtisticRoomba Feb 25, 2025
d21e8e5
fix order of dependencies
ArtisticRoomba Feb 25, 2025
0bdb6f1
add ShowVerb to SharedStorageSystem.cs
ArtisticRoomba Feb 25, 2025
1ac112a
orks is a nerd
ArtisticRoomba Feb 25, 2025
d51a702
add proper locale, fix adminlogging
ArtisticRoomba Feb 26, 2025
2583830
orks is a nerd 2
ArtisticRoomba Mar 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Content.Server/Explosion/EntitySystems/TriggerSystem.Voice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ private void OnListen(Entity<TriggerOnVoiceComponent> ent, ref ListenEvent args)
_adminLogger.Add(LogType.Trigger, LogImpact.High,
$"A voice-trigger on {ToPrettyString(ent):entity} was triggered by {ToPrettyString(args.Source):speaker} speaking the key-phrase {component.KeyPhrase}.");
Trigger(ent, args.Source);

var voice = new VoiceTriggeredEvent(args.Source, message);
RaiseLocalEvent(ent, ref voice);
}
}

Expand Down Expand Up @@ -137,3 +140,12 @@ private void OnVoiceExamine(EntityUid uid, TriggerOnVoiceComponent component, Ex
}
}
}


/// <summary>
/// Raised when a voice trigger is activated, containing the message that triggered it.
/// </summary>
/// <param name="Source"> The EntityUid of the entity sending the message</param>
/// <param name="Message"> The contents of the message</param>
[ByRefEvent]
public readonly record struct VoiceTriggeredEvent(EntityUid Source, string? Message);
19 changes: 19 additions & 0 deletions Content.Server/VoiceTrigger/StorageVoiceControlComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Content.Shared.Inventory;

namespace Content.Server.VoiceTrigger;

/// <summary>
/// Entities with this component, Containers, and TriggerOnVoiceComponent will insert any item or extract the spoken item after the TriggerOnVoiceComponent has been activated
/// </summary>
[RegisterComponent]
public sealed partial class StorageVoiceControlComponent : Component
{
/// <summary>
/// Used to determine which slots the component can be used in.
/// <remarks>
/// If not set, the component can be used anywhere, even while inside other containers.
/// </remarks>
/// </summary>
[DataField]
public SlotFlags? AllowedSlots;
}
98 changes: 98 additions & 0 deletions Content.Server/VoiceTrigger/StorageVoiceControlSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using Content.Server.Hands.Systems;
using Content.Server.Storage.EntitySystems;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.Hands.Components;
using Content.Shared.Inventory;
using Content.Shared.Popups;
using Content.Shared.Storage;
using Robust.Server.Containers;

namespace Content.Server.VoiceTrigger;

/// <summary>
/// Allows storages to be manipulated using voice commands.
/// </summary>
public sealed class StorageVoiceControlSystem : EntitySystem
{
[Dependency] private readonly ContainerSystem _container = default!;
[Dependency] private readonly HandsSystem _hands = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly StorageSystem _storage = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<StorageVoiceControlComponent, VoiceTriggeredEvent>(VoiceTriggered);
}

private void VoiceTriggered(Entity<StorageVoiceControlComponent> ent, ref VoiceTriggeredEvent args)
{
// Check if the component has any slot restrictions via AllowedSlots
// If it has slot restrictions, check if the item is in a slot that is allowed
if (ent.Comp.AllowedSlots != null && _inventory.TryGetContainingSlot((ent.Owner, null), out var itemSlot) &&
(itemSlot.SlotFlags & ent.Comp.AllowedSlots) == 0)
return;

// Don't do anything if there is no message
if (args.Message == null)
return;

// Get the storage component
if (!TryComp<StorageComponent>(ent, out var storage))
return;

// Get the hands component
if (!TryComp<HandsComponent>(args.Source, out var hands))
return;

// If the player has something in their hands, try to insert it into the storage
if (hands.ActiveHand != null && hands.ActiveHand.HeldEntity.HasValue)
{
// Disallow insertion and provide a reason why if the person decides to insert the item into itself
if (ent.Owner.Equals(hands.ActiveHand.HeldEntity.Value))
{
_popup.PopupEntity(Loc.GetString("comp-storagevoicecontrol-self-insert", ("entity", hands.ActiveHand.HeldEntity.Value)), ent, args.Source);
return;
}
if (_storage.CanInsert(ent, hands.ActiveHand.HeldEntity.Value, out var failedReason))
{
// We adminlog before insertion, otherwise the logger will attempt to pull info on an entity that no longer is present and throw an exception
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(args.Source)} inserted {ToPrettyString(hands.ActiveHand.HeldEntity.Value)} into {ToPrettyString(ent)} via voice control");
_storage.Insert(ent, hands.ActiveHand.HeldEntity.Value, out _);
return;
}
{
// Tell the player the reason why the item couldn't be inserted
if (failedReason == null)
return;
_popup.PopupEntity(Loc.GetString(failedReason), ent, args.Source);
_adminLogger.Add(LogType.Action,
LogImpact.Low,
$"{ToPrettyString(args.Source)} failed to insert {ToPrettyString(hands.ActiveHand.HeldEntity.Value)} into {ToPrettyString(ent)} via voice control");
}
return;
}

// If otherwise, we're retrieving an item, so check all the items currently in the attached storage
foreach (var item in storage.Container.ContainedEntities)
{
// Get the item's name
var itemName = MetaData(item).EntityName;
// The message doesn't match the item name the requestor requested, skip and move on to the next item
if (!args.Message.Contains(itemName, StringComparison.InvariantCultureIgnoreCase))
continue;

// We found the item we want, so draw it from storage and place it into the player's hands
if (storage.Container.ContainedEntities.Count != 0)
{
_container.RemoveEntity(ent, item);
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(args.Source)} retrieved {ToPrettyString(item)} from {ToPrettyString(ent)} via voice control");
_hands.TryPickup(args.Source, item, handsComp: hands);
break;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ private void OnBoundUIClosed(EntityUid uid, StorageComponent storageComp, BoundU

private void AddUiVerb(EntityUid uid, StorageComponent component, GetVerbsEvent<ActivationVerb> args)
{
if (!CanInteract(args.User, (uid, component), args.CanAccess && args.CanInteract))
if (component.ShowVerb == false || !CanInteract(args.User, (uid, component), args.CanAccess && args.CanInteract))
return;

// Does this player currently have the storage UI open?
Expand Down
7 changes: 7 additions & 0 deletions Content.Shared/Storage/StorageComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,13 @@ public enum StorageUiKey : byte
{
Key,
}

/// <summary>
/// Allow or disallow showing the "open/close storage" verb.
/// This is desired on items that we don't want to be accessed by the player directly.
/// </summary>
[DataField]
public bool ShowVerb = true;
}

[Serializable, NetSerializable]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
comp-storagevoicecontrol-self-insert = You can't insert { THE($entity) } into itself!
2 changes: 1 addition & 1 deletion Resources/Prototypes/Catalog/Fills/Lockers/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
contents:
- id: ClothingEyesGlassesSecurity
prob: 0.3
- id: ClothingHeadHatFedoraBrown
- id: ClothingHeadHatDetGadget
- id: ClothingNeckTieDet
- id: ClothingOuterVestDetective
- id: ClothingOuterCoatDetective
Expand Down
31 changes: 31 additions & 0 deletions Resources/Prototypes/Entities/Clothing/Head/specific.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,34 @@
interfaces:
enum.ChameleonUiKey.Key:
type: ChameleonBoundUserInterface

- type: entity
parent: ClothingHeadHatFedoraBrown
id: ClothingHeadHatDetGadget
name: go go hat
description: A novel hat with a built in toolkit. Automatically stores and retrieves items at the say of a phrase!
components:
- type: Tag
tags: [] # ignore "WhitelistChameleon" tag
- type: TriggerOnVoice
keyPhrase: "go go gadget"
listenRange: 0
- type: ActiveListener
range: 0
- type: StorageVoiceControl
allowedSlots:
- HEAD
- type: Storage
showVerb: false
grid:
- 0,0,6,3
maxItemSize: Small
blacklist:
tags:
- HighRiskItem # no hiding objectives or trolling nukies
- FakeNukeDisk # no disk checking
- QuantumSpinInverter # avoid the morbillionth QSI bug
- type: ContainerContainer
containers:
storagebase: !type:Container
ents: [ ]
Loading