Thief beacons (try 2) (#29997)

content
This commit is contained in:
Ed
2024-08-08 16:17:50 +03:00
committed by GitHub
parent 6d6c836095
commit 03745efc7f
14 changed files with 264 additions and 24 deletions

View File

@@ -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();
}

View File

@@ -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>

View File

@@ -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);
@@ -96,25 +95,33 @@ public sealed class StealConditionSystem : EntitySystem
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);
}
}
@@ -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<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

View File

@@ -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");
}

View File

@@ -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();
}
}

View File

@@ -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.

View File

@@ -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" ]

View File

@@ -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

View File

@@ -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

View File

@@ -11,3 +11,4 @@
back:
- ToolboxThief
- ClothingHandsChameleonThief
- ThiefBeacon

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 681 B

View File

@@ -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
]
]
}
]
}