From 03745efc7f64dee81329bece19d89fa69a9b50db Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Thu, 8 Aug 2024 16:17:50 +0300 Subject: [PATCH] Thief beacons (try 2) (#29997) content --- .../Components/StealAreaComponent.cs | 23 +++++ .../Components/StealConditionComponent.cs | 7 ++ .../Systems/StealConditionSystem.cs | 51 +++++++--- .../Thief/Components/ThiefBeaconComponent.cs | 17 ++++ .../Thief/Systems/ThiefBeaconSystem.cs | 95 ++++++++++++++++++ Resources/Locale/en-US/thief/beacon.ftl | 8 ++ .../Entities/Objects/Tools/thief_beacon.yml | 38 +++++++ .../Prototypes/Objectives/objectiveGroups.yml | 5 +- Resources/Prototypes/Objectives/thief.yml | 9 +- Resources/Prototypes/Roles/Antags/Thief.yml | 3 +- .../thief_beacon.rsi/extraction_point.png | Bin 0 -> 954 bytes .../extraction_point_light.png | Bin 0 -> 281 bytes .../thief_beacon.rsi/folded_extraction.png | Bin 0 -> 681 bytes .../Objects/Tools/thief_beacon.rsi/meta.json | 32 ++++++ 14 files changed, 264 insertions(+), 24 deletions(-) create mode 100644 Content.Server/Objectives/Components/StealAreaComponent.cs create mode 100644 Content.Server/Thief/Components/ThiefBeaconComponent.cs create mode 100644 Content.Server/Thief/Systems/ThiefBeaconSystem.cs create mode 100644 Resources/Locale/en-US/thief/beacon.ftl create mode 100644 Resources/Prototypes/Entities/Objects/Tools/thief_beacon.yml create mode 100644 Resources/Textures/Objects/Tools/thief_beacon.rsi/extraction_point.png create mode 100644 Resources/Textures/Objects/Tools/thief_beacon.rsi/extraction_point_light.png create mode 100644 Resources/Textures/Objects/Tools/thief_beacon.rsi/folded_extraction.png create mode 100644 Resources/Textures/Objects/Tools/thief_beacon.rsi/meta.json diff --git a/Content.Server/Objectives/Components/StealAreaComponent.cs b/Content.Server/Objectives/Components/StealAreaComponent.cs new file mode 100644 index 0000000000..26e752f2f2 --- /dev/null +++ b/Content.Server/Objectives/Components/StealAreaComponent.cs @@ -0,0 +1,23 @@ +using Content.Server.Objectives.Systems; +using Content.Server.Thief.Systems; + +namespace Content.Server.Objectives.Components; + +/// +/// An abstract component that allows other systems to count adjacent objects as "stolen" when controlling other systems +/// +[RegisterComponent, Access(typeof(StealConditionSystem), typeof(ThiefBeaconSystem))] +public sealed partial class StealAreaComponent : Component +{ + [DataField] + public bool Enabled = true; + + [DataField] + public float Range = 1f; + + /// + /// all the minds that will be credited with stealing from this area. + /// + [DataField] + public HashSet Owners = new(); +} diff --git a/Content.Server/Objectives/Components/StealConditionComponent.cs b/Content.Server/Objectives/Components/StealConditionComponent.cs index f8d68063f8..cdade8cc8d 100644 --- a/Content.Server/Objectives/Components/StealConditionComponent.cs +++ b/Content.Server/Objectives/Components/StealConditionComponent.cs @@ -22,11 +22,18 @@ public sealed partial class StealConditionComponent : Component [DataField] public bool VerifyMapExistence = true; + /// + /// If true, counts objects that are close to steal areas. + /// + [DataField] + public bool CheckStealAreas = false; + /// /// If the target may be alive but has died, it will not be counted /// [DataField] public bool CheckAlive = false; + /// /// The minimum number of items you need to steal to fulfill a objective /// diff --git a/Content.Server/Objectives/Systems/StealConditionSystem.cs b/Content.Server/Objectives/Systems/StealConditionSystem.cs index 42a296ab92..2c9244cf7d 100644 --- a/Content.Server/Objectives/Systems/StealConditionSystem.cs +++ b/Content.Server/Objectives/Systems/StealConditionSystem.cs @@ -21,16 +21,15 @@ public sealed class StealConditionSystem : EntitySystem [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly SharedObjectivesSystem _objectives = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; private EntityQuery _containerQuery; - private EntityQuery _metaQuery; public override void Initialize() { base.Initialize(); _containerQuery = GetEntityQuery(); - _metaQuery = GetEntityQuery(); SubscribeLocalEvent(OnAssigned); SubscribeLocalEvent(OnAfterAssign); @@ -96,25 +95,33 @@ public sealed class StealConditionSystem : EntitySystem if (!_containerQuery.TryGetComponent(mind.OwnedEntity, out var currentManager)) return 0; - var stack = new Stack(); + var containerStack = new Stack(); var count = 0; + //check stealAreas + if (condition.CheckStealAreas) + { + var areasQuery = AllEntityQuery(); + while (areasQuery.MoveNext(out var uid, out var area)) + { + if (!area.Owners.Contains(mind.Owner)) + continue; + + var nearestEnt = _lookup.GetEntitiesInRange(uid, area.Range); + foreach (var ent in nearestEnt) + { + CheckEntity(ent, condition, ref containerStack, ref count); + } + } + } + //check pulling object if (TryComp(mind.OwnedEntity, out var pull)) //TO DO: to make the code prettier? don't like the repetition { var pulledEntity = pull.Pulling; if (pulledEntity != null) { - // check if this is the item - count += CheckStealTarget(pulledEntity.Value, condition); - - //we don't check the inventories of sentient entity - if (!HasComp(pulledEntity)) - { - // if it is a container check its contents - if (_containerQuery.TryGetComponent(pulledEntity, out var containerManager)) - stack.Push(containerManager); - } + CheckEntity(pulledEntity.Value, condition, ref containerStack, ref count); } } @@ -131,16 +138,30 @@ public sealed class StealConditionSystem : EntitySystem // if it is a container check its contents if (_containerQuery.TryGetComponent(entity, out var containerManager)) - stack.Push(containerManager); + containerStack.Push(containerManager); } } - } while (stack.TryPop(out currentManager)); + } while (containerStack.TryPop(out currentManager)); var result = count / (float) condition.CollectionSize; result = Math.Clamp(result, 0, 1); return result; } + private void CheckEntity(EntityUid entity, StealConditionComponent condition, ref Stack containerStack, ref int counter) + { + // check if this is the item + counter += CheckStealTarget(entity, condition); + + //we don't check the inventories of sentient entity + if (!TryComp(entity, out var pullMind)) + { + // if it is a container check its contents + if (_containerQuery.TryGetComponent(entity, out var containerManager)) + containerStack.Push(containerManager); + } + } + private int CheckStealTarget(EntityUid entity, StealConditionComponent condition) { // check if this is the target diff --git a/Content.Server/Thief/Components/ThiefBeaconComponent.cs b/Content.Server/Thief/Components/ThiefBeaconComponent.cs new file mode 100644 index 0000000000..65db79f861 --- /dev/null +++ b/Content.Server/Thief/Components/ThiefBeaconComponent.cs @@ -0,0 +1,17 @@ +using Content.Server.Thief.Systems; +using Robust.Shared.Audio; + +namespace Content.Server.Thief.Components; + +/// +/// working together with StealAreaComponent, allows the thief to count objects near the beacon as stolen when setting up. +/// +[RegisterComponent, Access(typeof(ThiefBeaconSystem))] +public sealed partial class ThiefBeaconComponent : Component +{ + [DataField] + public SoundSpecifier LinkSound = new SoundPathSpecifier("/Audio/Machines/high_tech_confirm.ogg"); + + [DataField] + public SoundSpecifier UnlinkSound = new SoundPathSpecifier("/Audio/Machines/beep.ogg"); +} diff --git a/Content.Server/Thief/Systems/ThiefBeaconSystem.cs b/Content.Server/Thief/Systems/ThiefBeaconSystem.cs new file mode 100644 index 0000000000..e004212124 --- /dev/null +++ b/Content.Server/Thief/Systems/ThiefBeaconSystem.cs @@ -0,0 +1,95 @@ +using Content.Server.Mind; +using Content.Server.Objectives.Components; +using Content.Server.Roles; +using Content.Server.Thief.Components; +using Content.Shared.Examine; +using Content.Shared.Foldable; +using Content.Shared.Popups; +using Content.Shared.Verbs; +using Robust.Shared.Audio.Systems; + +namespace Content.Server.Thief.Systems; + +/// +/// +/// +public sealed class ThiefBeaconSystem : EntitySystem +{ + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly MindSystem _mind = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent>(OnGetInteractionVerbs); + SubscribeLocalEvent(OnFolded); + SubscribeLocalEvent(OnExamined); + } + + private void OnGetInteractionVerbs(Entity beacon, ref GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract || args.Hands is null) + return; + + if (TryComp(beacon, out var foldable) && foldable.IsFolded) + return; + + var mind = _mind.GetMind(args.User); + if (!HasComp(mind)) + return; + + var user = args.User; + args.Verbs.Add(new() + { + Act = () => + { + SetCoordinate(beacon, mind.Value); + }, + Message = Loc.GetString("thief-fulton-verb-message"), + Text = Loc.GetString("thief-fulton-verb-text"), + }); + } + + private void OnFolded(Entity beacon, ref FoldedEvent args) + { + if (args.IsFolded) + ClearCoordinate(beacon); + } + + private void OnExamined(Entity beacon, ref ExaminedEvent args) + { + if (!TryComp(beacon, out var area)) + return; + + args.PushText(Loc.GetString(area.Owners.Count == 0 + ? "thief-fulton-examined-unset" + : "thief-fulton-examined-set")); + } + + private void SetCoordinate(Entity beacon, EntityUid mind) + { + if (!TryComp(beacon, out var area)) + return; + + _audio.PlayPvs(beacon.Comp.LinkSound, beacon); + _popup.PopupEntity(Loc.GetString("thief-fulton-set"), beacon); + area.Owners.Clear(); //We only reconfigure the beacon for ourselves, we don't need multiple thieves to steal from the same beacon. + area.Owners.Add(mind); + } + + private void ClearCoordinate(Entity beacon) + { + if (!TryComp(beacon, out var area)) + return; + + if (area.Owners.Count == 0) + return; + + _audio.PlayPvs(beacon.Comp.UnlinkSound, beacon); + _popup.PopupEntity(Loc.GetString("thief-fulton-clear"), beacon); + area.Owners.Clear(); + } +} diff --git a/Resources/Locale/en-US/thief/beacon.ftl b/Resources/Locale/en-US/thief/beacon.ftl new file mode 100644 index 0000000000..9fbbcaf419 --- /dev/null +++ b/Resources/Locale/en-US/thief/beacon.ftl @@ -0,0 +1,8 @@ +thief-fulton-set = Delivery coordinates are set. +thief-fulton-clear = Delivery coordinates cleared. + +thief-fulton-examined-set = Coordinates entered. Bluespace teleportation of the nearest objects will be performed when the evacuation shuttle departs. +thief-fulton-examined-unset = Beacon coordinates are not set. + +thief-fulton-verb-text = Set coordinates +thief-fulton-verb-message = Set the coordinates of your thief's hideout, where all nearby items will be sent at the end of the round. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Tools/thief_beacon.yml b/Resources/Prototypes/Entities/Objects/Tools/thief_beacon.yml new file mode 100644 index 0000000000..c35e66127d --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Tools/thief_beacon.yml @@ -0,0 +1,38 @@ +- type: entity + id: ThiefBeacon + name: thieving beacon + description: A device that will teleport everything around it to the thief's vault at the end of the shift. + components: + - type: ThiefBeacon + - type: StealArea + - type: Item + size: Normal + - type: Physics + bodyType: Dynamic + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.25,-0.4,0.25,0.1" + density: 20 + mask: + - Impassable + - type: Foldable + folded: true + - type: Clickable + - type: InteractionOutline + - type: Appearance + - type: GenericVisualizer + visuals: + enum.FoldedVisuals.State: + foldedLayer: + True: { state: folded_extraction } + False: { state: extraction_point } + - type: Sprite + sprite: Objects/Tools/thief_beacon.rsi + drawdepth: SmallObjects + noRot: true + layers: + - state: extraction_point + map: [ "foldedLayer" ] \ No newline at end of file diff --git a/Resources/Prototypes/Objectives/objectiveGroups.yml b/Resources/Prototypes/Objectives/objectiveGroups.yml index bb74c92da3..e62aa9fdf6 100644 --- a/Resources/Prototypes/Objectives/objectiveGroups.yml +++ b/Resources/Prototypes/Objectives/objectiveGroups.yml @@ -52,8 +52,8 @@ - type: weightedRandom id: ThiefBigObjectiveGroups weights: - ThiefObjectiveGroupStructure: 0 #Temporarily disabled until obvious ways to steal structures are added - ThiefObjectiveGroupAnimal: 2 + ThiefObjectiveGroupStructure: 1 + ThiefObjectiveGroupAnimal: 1 - type: weightedRandom id: ThiefObjectiveGroupCollection @@ -91,7 +91,6 @@ weights: NuclearBombStealObjective: 0.5 FaxMachineCaptainStealObjective: 1 - VehicleSecwayStealObjective: 1 ChemDispenserStealObjective: 1 XenoArtifactStealObjective: 1 FreezerHeaterStealObjective: 1 diff --git a/Resources/Prototypes/Objectives/thief.yml b/Resources/Prototypes/Objectives/thief.yml index c29641081b..672f9b2ba7 100644 --- a/Resources/Prototypes/Objectives/thief.yml +++ b/Resources/Prototypes/Objectives/thief.yml @@ -18,30 +18,29 @@ - type: StealCondition verifyMapExistence: false descriptionText: objective-condition-thief-description + checkStealAreas: true - type: entity abstract: true - parent: [BaseThiefObjective, BaseStealObjective] + parent: [BaseThiefObjective, BaseThiefStealObjective] id: BaseThiefStealCollectionObjective components: - type: StealCondition verifyMapExistence: true - descriptionText: objective-condition-thief-description - type: entity abstract: true - parent: [BaseThiefObjective, BaseStealObjective] + parent: [BaseThiefObjective, BaseThiefStealObjective] id: BaseThiefStealStructureObjective components: - type: StealCondition verifyMapExistence: true - descriptionText: objective-condition-thief-description - type: Objective difficulty: 2 # it's hard to hide - type: entity abstract: true - parent: [BaseThiefObjective, BaseStealObjective] + parent: [BaseThiefObjective, BaseThiefStealObjective] id: BaseThiefStealAnimalObjective components: - type: StealCondition diff --git a/Resources/Prototypes/Roles/Antags/Thief.yml b/Resources/Prototypes/Roles/Antags/Thief.yml index d85d366f6b..f0d0c12470 100644 --- a/Resources/Prototypes/Roles/Antags/Thief.yml +++ b/Resources/Prototypes/Roles/Antags/Thief.yml @@ -10,4 +10,5 @@ storage: back: - ToolboxThief - - ClothingHandsChameleonThief \ No newline at end of file + - ClothingHandsChameleonThief + - ThiefBeacon \ No newline at end of file diff --git a/Resources/Textures/Objects/Tools/thief_beacon.rsi/extraction_point.png b/Resources/Textures/Objects/Tools/thief_beacon.rsi/extraction_point.png new file mode 100644 index 0000000000000000000000000000000000000000..b986a6ae28aedc92556d947c05ecb2963c5a90a0 GIT binary patch literal 954 zcmV;r14aCaP)Px&bV)=(RA_(jj?V(^xsVg^C6$x3&rBbCHDwP9L zzeP{I^voB@2cXbHi#QZTf*>R##o~YoO>n_#8kosCo5dSvd)V=UiP>!2buR2*8a>a< zn>YV?GjG=OAjbQSM3lyg_r6U4W4a^&7uW~(>tEh*M@m3XJ`M<7Qh)>4y6g=iF&-5G zyj2U}j4lRX0h_v5KzGofQ4lx}+|u%lZXY;TlmrrZZa07>-L|CbDc-T&Q4(h$yTrSP$ z3P9@mzz~Fx_rQFm;sRKXgON)4@=aKd!|H6`6#D7#16f{BTVJ}IT7*=!Ef&1jv&5ZVKVVIZaKlZIgcAcQ!eAJzk* z2w0BeySQGjbHXraJbA(^%X;S+&jbHPLja&sE(i864|xWTbPwFVbBB&?lNO>+E>^2Y zF%ynJX>QI1P)hl(?$|ctw?9L)lK8v+<70o!N3*kTHk$>YyQ3)0O}ju}c)pFmD7dt+ z;IB?fNm>X#xSQnUs*6~MldCQr+eS(Wz+$yZrCg>`E@QUaTv}K_DK(r2-p0nfNvCFG z7XT7iQ(cT!lC%(P%$wLXC#1~>os-PeC96_dH_|08hXi%G^#r`i4O zZvfIlAf=>OECSFj6zDV>zW&#rWKg1@8LYwNdG6P0fdqoD;>HZ_qt5})%^lkYAeYOL z%jL-D^Q47fW+elF+U?SQ{)nu-&Zc@5Xu5|$51h_yfwRR+UPr{HXIp&NMA<7u8^-y8I6n~Q2f)h@oc-k@-HaD)Nz-NP z>Y6|1Sn>lqr35d&>S7mQr<6GU{6KCU#CnpX>C(+4u#Y=G@Xt^61G;g3pocg=5a$Pm coZ~&mf5q`3zCm8LX#fBK07*qoM6N<$f?J5hnE(I) literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/thief_beacon.rsi/extraction_point_light.png b/Resources/Textures/Objects/Tools/thief_beacon.rsi/extraction_point_light.png new file mode 100644 index 0000000000000000000000000000000000000000..f2e9f984d239556377c9957670d3fe82c8441a9b GIT binary patch literal 281 zcmV+!0p|XRP)Px#(@8`@R9J=WmN5#0KoCXWih|n2B9>`#Gus>@MGleH8+fCfKnq3C1rs+-h&GEG z69~w>dU?#uewYD4xjoAj9v%wA$e5WA1-Zf}BqU%!qq$EC->CqPkd%~|j*^m&#~Q(r zgc@kklfZKlC<0=V@Jd2VFmK#VU>NAA^@*B}f!Pqa27AP9o+9}3xt!gjH4|BH!$p7YxK;NZC2t%8b* fp2$HV2tVKn30Fa0oMIG>00000NkvXXu0mjfaW-&x literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/thief_beacon.rsi/folded_extraction.png b/Resources/Textures/Objects/Tools/thief_beacon.rsi/folded_extraction.png new file mode 100644 index 0000000000000000000000000000000000000000..43ead68bb252215e76ecb1793dad137c86d9637a GIT binary patch literal 681 zcmV;a0#^NrP)Px%V@X6oR9J=Wmd{TUK^(L?RfECla_?Bc%jjxl|&b%aPCJ=r|5b#Ue_nuqC3$uwLlkYE8S@ zWFebnA)BS$Y+?vOz0g5>Ueu}jaOM#xrGj{A&mP(m;nkF&G21;AuHj;l4PvPBz$ zSOPqL^7PbrMiv0@^2PJux?bquRt_7k*YWpSEvhp!)C(P`z}q*k1OBd5OxUr16EOB* zf}tscy;p}jHiSS*NjjYdz?qxFt0^<*ELzQG=sIBn03!WZo`dt&_|Neh%SrWEc6pZX P00000NkvXXu0mjf!sa%| literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/thief_beacon.rsi/meta.json b/Resources/Textures/Objects/Tools/thief_beacon.rsi/meta.json new file mode 100644 index 0000000000..ba7e003575 --- /dev/null +++ b/Resources/Textures/Objects/Tools/thief_beacon.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/austation/austation/commit/e2a4fefd01e702f48d3d4cc8d6a2686d54d104fa and edited by TheShuEd", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "folded_extraction" + }, + { + "name": "extraction_point", + "delays": [ + [ + 0.5, + 0.5 + ] + ] + }, + { + "name": "extraction_point_light", + "delays": [ + [ + 0.5, + 0.5 + ] + ] + } + ] +} \ No newline at end of file -- 2.52.0