Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 10 additions & 10 deletions Content.Server/_ES/Masks/Objectives/ESKillTroupeObjectiveSystem.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Content.Server._ES.Masks.Objectives.Components;
using Content.Server._ES.Masks.Objectives.Relays.Components;
using Content.Shared._ES.KillTracking.Components;
using Content.Shared._ES.Objectives;

Expand All @@ -10,26 +11,25 @@ namespace Content.Server._ES.Masks.Objectives;
/// <seealso cref="ESKillTroupeObjectiveComponent"/>
public sealed class ESKillTroupeObjectiveSystem : ESBaseObjectiveSystem<ESKillTroupeObjectiveComponent>
{
public override Type[] RelayComponents => [typeof(ESKilledRelayComponent)];

/// <inheritdoc/>
public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<ESPlayerKilledEvent>(OnKillReported);
SubscribeLocalEvent<ESKillTroupeObjectiveComponent, ESKilledPlayerEvent>(OnKill);
}

private void OnKillReported(ref ESPlayerKilledEvent args)
private void OnKill(Entity<ESKillTroupeObjectiveComponent> ent, ref ESKilledPlayerEvent args)
{
if (!args.ValidKill || !MindSys.TryGetMind(args.Killer.Value, out var mind))
if (!args.ValidKill)
return;

foreach (var objective in ObjectivesSys.GetObjectives<ESKillTroupeObjectiveComponent>(mind.Value.Owner))
{
if (!MaskSys.TryGetTroupe(args.Killed, out var troupe))
return;
if (!MaskSys.TryGetTroupe(args.Killed, out var troupe))
return;

if ((troupe == objective.Comp.Troupe) ^ objective.Comp.Invert)
ObjectivesSys.AdjustObjectiveCounter(objective.Owner);
}
if ((troupe == ent.Comp.Troupe) ^ ent.Comp.Invert)
ObjectivesSys.AdjustObjectiveCounter(ent.Owner);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Content.Shared._ES.Objectives.Components;

namespace Content.Server._ES.Masks.Vigilante.Components;

/// <summary>
/// Objective that works with <see cref="ESCounterObjectiveComponent"/> to add progress each time a "killer" is killed.
/// </summary>
[RegisterComponent]
[Access(typeof(ESKillKillerObjectiveSystem))]
public sealed partial class ESKillKillerObjectiveComponent : Component;
37 changes: 37 additions & 0 deletions Content.Server/_ES/Masks/Vigilante/ESKillKillerObjectiveSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Content.Server._ES.Masks.Objectives.Relays.Components;
using Content.Server._ES.Masks.Vigilante.Components;
using Content.Shared._ES.KillTracking;
using Content.Shared._ES.KillTracking.Components;
using Content.Shared._ES.Objectives;

namespace Content.Server._ES.Masks.Vigilante;

public sealed class ESKillKillerObjectiveSystem : ESBaseObjectiveSystem<ESKillKillerObjectiveComponent>
{
[Dependency] private readonly ESKillTrackingSystem _killTracking = default!;

public override Type[] RelayComponents => [typeof(ESKilledRelayComponent)];

/// <inheritdoc/>
public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<ESKillKillerObjectiveComponent, ESKilledPlayerEvent>(OnKill);
}

private void OnKill(Entity<ESKillKillerObjectiveComponent> ent, ref ESKilledPlayerEvent args)
{
// Suicides don't count and i'll enumerate why because it's funny:
// If you can suicide to get the kill, then the best strategy is to murder someone at complete random
// If you randomly get a killer. Great! If not, you can just suicide at any point during the round,
// and it will count as a valid completion.
//
// It's fun to think about, though.
if (args.Suicide)
return;

if (_killTracking.GetPlayerKillCount(args.Killed) > 0)
ObjectivesSys.AdjustObjectiveCounter(ent.Owner);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public readonly struct ESPlayerKilledEvent(EntityUid killed, EntityUid? killer)
}

/// <summary>
/// Event raised on an entity when they kill and entity with <see cref="ESKillTrackerComponent"/>.
/// Event raised on an entity when they kill an entity with <see cref="ESKillTrackerComponent"/>.
/// </summary>
[ByRefEvent]
public readonly struct ESKilledPlayerEvent(EntityUid killed, EntityUid killer)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Content.Shared._ES.KillTracking.Components;

/// <summary>
/// Holds info about the entities with <see cref="ESKillTrackerComponent"/> killed by this entity.
/// </summary>
[RegisterComponent]
[Access(typeof(ESKillTrackingSystem))]
public sealed partial class ESKillerTrackerComponent : Component
{
/// <summary>
/// Number of players this entity has killed.
/// </summary>
[DataField]
public int KilledPlayerCount;
}
22 changes: 19 additions & 3 deletions Content.Shared/_ES/KillTracking/ESKillTrackingSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Content.Shared.Damage.Systems;
using Content.Shared.Destructible;
using Content.Shared.FixedPoint;
using Content.Shared.Humanoid;
using Content.Shared.Interaction.Events;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
Expand Down Expand Up @@ -95,10 +96,17 @@ private void RaiseKillEvent(Entity<ESKillTrackerComponent> ent)
var ev = new ESPlayerKilledEvent(ent, killer);
RaiseLocalEvent(ent, ref ev, true);

if (killer.HasValue)
if (!killer.HasValue)
return;

var killerEv = new ESKilledPlayerEvent(ent, killer.Value);
RaiseLocalEvent(killer.Value, ref killerEv);

// Only increment the player kill tracker if it was like a real player
if (HasComp<HumanoidAppearanceComponent>(ent))
{
var killerEv = new ESKilledPlayerEvent(ent, killer.Value);
RaiseLocalEvent(killer.Value, ref killerEv);
var comp = EnsureComp<ESKillerTrackerComponent>(killer.Value);
++comp.KilledPlayerCount;
}
}

Expand Down Expand Up @@ -172,4 +180,12 @@ public List<ESDamageSource> GetOrderedSources(Entity<ESKillTrackerComponent?> en
.ThenByDescending(s => s.AccumulatedDamage) // Within those groups, go from most damage to least damage.
.ToList();
}

public int GetPlayerKillCount(Entity<ESKillerTrackerComponent?> ent)
{
if (!Resolve(ent, ref ent.Comp, false))
return 0;

return ent.Comp.KilledPlayerCount;
}
}
3 changes: 3 additions & 0 deletions Resources/Locale/en-US/_ES/masks/masks.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ es-mask-vandal-desc = As a Vandal, sabotage random machines around the station f
es-mask-veteran-name = Veteran
es-mask-veteran-desc = As a Veteran, help the station by using your trusty sidearm to take care of anybody who isn't aligned with the crew.

es-mask-vigilante-name = Vigilante
es-mask-vigilante-desc = As a Vigilante, seek out those who have killed others and bring them to justice by killing them yourself.

es-mask-vip-name = VIP
es-mask-vip-desc = As a VIP, use your fancy VIP card to help confirm your innocence in times of peril.

Expand Down
22 changes: 22 additions & 0 deletions Resources/Prototypes/_ES/Catalog/Fills/Crates/caches.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,28 @@
weight: 2
- id: ESWeaponPistol9mmSilenced

# Vigilante
- type: entity
parent: ESCrateCache
id: ESCrateCacheCrewVigilante
suffix: ES, Vigilante Cache
components:
- type: EntityTableContainerFill
containers:
entity_storage:
tableId: ESCrewCacheVigilante

- type: entityTable
id: ESCrewCacheVigilante
table:
group:
- all:
- id: ESWeaponRevolver357
- group:
- id: ESWeaponPistol9mm
weight: 2
- id: ESWeaponPistol9mmSilenced

# Survivalist
- type: entity
parent: ESCrateCache
Expand Down
1 change: 1 addition & 0 deletions Resources/Prototypes/_ES/MaskSets/gunners.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
ESArmsDealer: 0.3
ESMercenary: 1
ESVeteran: 1
ESVigilante: 1
42 changes: 28 additions & 14 deletions Resources/Prototypes/_ES/Masks/crew.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,20 +123,6 @@
all:
- id: ESObjectiveSurvive

- type: esMask
id: ESVeteran
name: es-mask-veteran-name
troupe: ESCrew
description: es-mask-veteran-desc
color: ruber
weight: 1
objectives:
id: ESObjectiveKillNonCrew
mindComponents:
- type: ESMaskCacheSpawner
cacheProto:
id: ESCrateCacheCrewVeteran

- type: esMask
parent: ESBaseCommandRestricted
id: ESVandal
Expand All @@ -157,6 +143,34 @@
weight: 2
amount: 1, 2

- type: esMask
id: ESVeteran
name: es-mask-veteran-name
troupe: ESCrew
description: es-mask-veteran-desc
color: ruber
weight: 1
objectives:
id: ESObjectiveKillNonCrew
mindComponents:
- type: ESMaskCacheSpawner
cacheProto:
id: ESCrateCacheCrewVeteran

- type: esMask
id: ESVigilante
name: es-mask-vigilante-name
troupe: ESCrew
description: es-mask-vigilante-desc
color: orchid
weight: 1
objectives:
id: ESObjectiveVigilanteKillKiller
mindComponents:
- type: ESMaskCacheSpawner
cacheProto:
id: ESCrateCacheCrewVigilante

- type: esMask
id: ESVIP
name: es-mask-vip-name
Expand Down
12 changes: 12 additions & 0 deletions Resources/Prototypes/_ES/Objectives/Crew/vigilante.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
- type: entity
parent: ESBaseMaskObjective
id: ESObjectiveVigilanteKillKiller
name: Kill a killer
description: Find someone who has taken the life of another and exact justice.
components:
- type: ESObjective
icon:
sprite: _ES/Objects/Weapons/Guns/357.rsi
state: icon
- type: ESKillKillerObjective
- type: ESCounterObjective
Loading