Skip to content

Commit

Permalink
Thief beacons (try 2) (space-wizards#29997)
Browse files Browse the repository at this point in the history
content
  • Loading branch information
TheShuEd authored and themias committed Aug 9, 2024
1 parent 4067922 commit 6e941b9
Show file tree
Hide file tree
Showing 14 changed files with 264 additions and 24 deletions.
23 changes: 23 additions & 0 deletions Content.Server/Objectives/Components/StealAreaComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Content.Server.Objectives.Systems;
using Content.Server.Thief.Systems;

namespace Content.Server.Objectives.Components;

/// <summary>
/// An abstract component that allows other systems to count adjacent objects as "stolen" when controlling other systems
/// </summary>
[RegisterComponent, Access(typeof(StealConditionSystem), typeof(ThiefBeaconSystem))]
public sealed partial class StealAreaComponent : Component
{
[DataField]
public bool Enabled = true;

[DataField]
public float Range = 1f;

/// <summary>
/// all the minds that will be credited with stealing from this area.
/// </summary>
[DataField]
public HashSet<EntityUid> Owners = new();
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,18 @@ public sealed partial class StealConditionComponent : Component
[DataField]
public bool VerifyMapExistence = true;

/// <summary>
/// If true, counts objects that are close to steal areas.
/// </summary>
[DataField]
public bool CheckStealAreas = false;

/// <summary>
/// If the target may be alive but has died, it will not be counted
/// </summary>
[DataField]
public bool CheckAlive = false;

/// <summary>
/// The minimum number of items you need to steal to fulfill a objective
/// </summary>
Expand Down
51 changes: 36 additions & 15 deletions Content.Server/Objectives/Systems/StealConditionSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ContainerManagerComponent> _containerQuery;
private EntityQuery<MetaDataComponent> _metaQuery;

public override void Initialize()
{
base.Initialize();

_containerQuery = GetEntityQuery<ContainerManagerComponent>();
_metaQuery = GetEntityQuery<MetaDataComponent>();

SubscribeLocalEvent<StealConditionComponent, ObjectiveAssignedEvent>(OnAssigned);
SubscribeLocalEvent<StealConditionComponent, ObjectiveAfterAssignEvent>(OnAfterAssign);
Expand Down Expand Up @@ -96,25 +95,33 @@ private float GetProgress(MindComponent mind, StealConditionComponent condition)
if (!_containerQuery.TryGetComponent(mind.OwnedEntity, out var currentManager))
return 0;

var stack = new Stack<ContainerManagerComponent>();
var containerStack = new Stack<ContainerManagerComponent>();
var count = 0;

//check stealAreas
if (condition.CheckStealAreas)
{
var areasQuery = AllEntityQuery<StealAreaComponent>();
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<PullerComponent>(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<MindContainerComponent>(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);
}
}

Expand All @@ -131,16 +138,30 @@ private float GetProgress(MindComponent mind, StealConditionComponent condition)

// 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<ContainerManagerComponent> 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<MindContainerComponent>(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
Expand Down
17 changes: 17 additions & 0 deletions Content.Server/Thief/Components/ThiefBeaconComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Content.Server.Thief.Systems;
using Robust.Shared.Audio;

namespace Content.Server.Thief.Components;

/// <summary>
/// working together with StealAreaComponent, allows the thief to count objects near the beacon as stolen when setting up.
/// </summary>
[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");
}
95 changes: 95 additions & 0 deletions Content.Server/Thief/Systems/ThiefBeaconSystem.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// <see cref="ThiefBeaconComponent"/>
/// </summary>
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<ThiefBeaconComponent, GetVerbsEvent<InteractionVerb>>(OnGetInteractionVerbs);
SubscribeLocalEvent<ThiefBeaconComponent, FoldedEvent>(OnFolded);
SubscribeLocalEvent<ThiefBeaconComponent, ExaminedEvent>(OnExamined);
}

private void OnGetInteractionVerbs(Entity<ThiefBeaconComponent> beacon, ref GetVerbsEvent<InteractionVerb> args)
{
if (!args.CanAccess || !args.CanInteract || args.Hands is null)
return;

if (TryComp<FoldableComponent>(beacon, out var foldable) && foldable.IsFolded)
return;

var mind = _mind.GetMind(args.User);
if (!HasComp<ThiefRoleComponent>(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<ThiefBeaconComponent> beacon, ref FoldedEvent args)
{
if (args.IsFolded)
ClearCoordinate(beacon);
}

private void OnExamined(Entity<ThiefBeaconComponent> beacon, ref ExaminedEvent args)
{
if (!TryComp<StealAreaComponent>(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<ThiefBeaconComponent> beacon, EntityUid mind)
{
if (!TryComp<StealAreaComponent>(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<ThiefBeaconComponent> beacon)
{
if (!TryComp<StealAreaComponent>(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();
}
}
8 changes: 8 additions & 0 deletions Resources/Locale/en-US/thief/beacon.ftl
Original file line number Diff line number Diff line change
@@ -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.
38 changes: 38 additions & 0 deletions Resources/Prototypes/Entities/Objects/Tools/thief_beacon.yml
Original file line number Diff line number Diff line change
@@ -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" ]
5 changes: 2 additions & 3 deletions Resources/Prototypes/Objectives/objectiveGroups.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -91,7 +91,6 @@
weights:
NuclearBombStealObjective: 0.5
FaxMachineCaptainStealObjective: 1
VehicleSecwayStealObjective: 1
ChemDispenserStealObjective: 1
XenoArtifactStealObjective: 1
FreezerHeaterStealObjective: 1
Expand Down
9 changes: 4 additions & 5 deletions Resources/Prototypes/Objectives/thief.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion Resources/Prototypes/Roles/Antags/Thief.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
storage:
back:
- ToolboxThief
- ClothingHandsChameleonThief
- ClothingHandsChameleonThief
- ThiefBeacon
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions Resources/Textures/Objects/Tools/thief_beacon.rsi/meta.json
Original file line number Diff line number Diff line change
@@ -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
]
]
}
]
}

0 comments on commit 6e941b9

Please sign in to comment.