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
6 changes: 3 additions & 3 deletions Content.Server/GameTicking/Rules/ThiefRuleSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ private string MakeBriefing(EntityUid ent)
{
var isHuman = HasComp<HumanoidProfileComponent>(ent);
var briefing = isHuman
? Loc.GetString("thief-role-greeting-human")
: Loc.GetString("thief-role-greeting-animal");
? Loc.GetString("scorethief-role-greeting-human") // Funky change
: Loc.GetString("scorethief-role-greeting-animal"); // Funky change

if (isHuman)
briefing += "\n \n" + Loc.GetString("thief-role-greeting-equipment") + "\n";
briefing += "\n \n" + Loc.GetString("scorethief-role-greeting-equipment") + "\n"; // Funky change

return briefing;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Content.Server._Funkystation.Objectives.Systems;

namespace Content.Server._Funkystation.Objectives.Components;

/// <summary>
/// Requires that you steal enough to fill a speso quota
/// </summary>
[RegisterComponent, Access(typeof(ScoreThiefConditionSystem))]
public sealed partial class ScoreThiefConditionComponent : Component
{
[DataField(required: true)]
public int AmountSpesos;

[DataField(required: true)]
public int AmountSpesosVariance;

[DataField]
public int AmountSpesosVarianceInterval = 1000;

[DataField]
public bool CheckStealAreas = true;

public int TargetScore = 0;
public int CurrentScore = 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Content.Server._Funkystation.Objectives.Systems;
using Robust.Shared.Serialization.TypeSerializers.Implementations;

namespace Content.Server._Funkystation.Objectives.Components;

/// <summary>
/// Modifies the price of an entity for scorethief, including possibly making it worthless
/// </summary>
[RegisterComponent, Access(typeof(ScoreThiefConditionSystem))]
public sealed partial class ScoreThiefPriceModifierComponent : Component
{
/// <summary>
/// Must be a Loc string
/// </summary>
[DataField]
public string? Reason = null;

[DataField(required: true)]
public double Multiplier;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
using Content.Server._Funkystation.Objectives.Components;
using Content.Server.Cargo.Systems;
using Content.Shared.Interaction;
using Content.Shared.Mind.Components;
using Content.Shared.Objectives.Components;
using Content.Shared.Objectives.Systems;
using JetBrains.Annotations;
using Robust.Shared.Containers;
using Robust.Shared.Random;
using Robust.Shared.Utility;

namespace Content.Server._Funkystation.Objectives.Systems;

/// <summary>
/// The objective system for scorethief
/// </summary>
// Large portions of this were taken from https://github.com/funky-station/forky-station/blob/22a547c7c8aa1f0f6ac5f8c3e9941f2dfc25bd17/Content.Server/Objectives/Systems/StealConditionSystem.cs
[UsedImplicitly]
public sealed partial class ScoreThiefConditionSystem : EntitySystem
{
[Dependency] private IRobustRandom _random = default!;
[Dependency] private MetaDataSystem _metaData = default!;
[Dependency] private SharedObjectivesSystem _objectives = default!;
[Dependency] private EntityLookupSystem _lookup = default!;
[Dependency] private SharedInteractionSystem _interaction = default!;
[Dependency] private IEntityManager _entManager = default!;
[Dependency] private EntityQuery<ContainerManagerComponent> _containerQuery = default!;
[Dependency] private EntityQuery<ScoreThiefPriceModifierComponent> _modifierQuery = default!;
[Dependency] private EntityQuery<MindContainerComponent> _mindQuery = default!;

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

SubscribeLocalEvent<ScoreThiefConditionComponent, ObjectiveAssignedEvent>(OnAssigned);
SubscribeLocalEvent<ScoreThiefConditionComponent, ObjectiveAfterAssignEvent>(OnAfterAssign);
SubscribeLocalEvent<ScoreThiefConditionComponent, ObjectiveGetProgressEvent>(OnGetProgress);

}

private void OnAssigned(Entity<ScoreThiefConditionComponent> condition, ref ObjectiveAssignedEvent args)
{
condition.Comp.TargetScore = _random.Next(
(condition.Comp.AmountSpesos - condition.Comp.AmountSpesosVariance)/condition.Comp.AmountSpesosVarianceInterval,
(condition.Comp.AmountSpesos + condition.Comp.AmountSpesosVariance)/condition.Comp.AmountSpesosVarianceInterval
) * condition.Comp.AmountSpesosVarianceInterval;
}

private void OnAfterAssign(Entity<ScoreThiefConditionComponent> condition, ref ObjectiveAfterAssignEvent args)
{
string rsiState;
switch(condition.Comp.TargetScore)
{
case 1:
rsiState = "cash";
break;
case <= 10:
rsiState = "cash_10";
break;
case <= 100:
rsiState = "cash_100";
break;
case <= 500:
rsiState = "cash_500";
break;
case <= 1000:
rsiState = "cash_1000";
break;
case <= 5000:
rsiState = "cash_5000";
break;
case <= 10000:
rsiState = "cash_10000";
break;
case <= 25000:
rsiState = "cash_25000";
break;
case <= 50000:
rsiState = "cash_50000";
break;
case <= 100000:
rsiState = "cash_100000";
break;
default:
rsiState = "cash_1000000";
break;
}
var sprite = new SpriteSpecifier.Rsi(new ResPath("/Textures/Objects/Economy/cash.rsi"), rsiState);

_metaData.SetEntityName(condition.Owner,
Loc.GetString("scorethief-objective-title-one") + " " + condition.Comp.TargetScore + " " + Loc.GetString("scorethief-objective-title-two"),
args.Meta);
_objectives.SetIcon(condition.Owner, sprite, args.Objective);
}

private void OnGetProgress(Entity<ScoreThiefConditionComponent> condition, ref ObjectiveGetProgressEvent args)
{
condition.Comp.CurrentScore = 0;
var checkPlayer = true;

// Check steal areas
if (condition.Comp.CheckStealAreas)
{
var areasQuery = AllEntityQuery<StealAreaComponent, TransformComponent>();
while (areasQuery.MoveNext(out var uid, out var area, out var xform))
{
if (!area.Owners.Contains(args.MindId))
continue;

HashSet<Entity<TransformComponent>> nearestEnts = new();

_lookup.GetEntitiesInRange<TransformComponent>(xform.Coordinates, area.Range, nearestEnts);
foreach (var ent in nearestEnts)
{
if (!_interaction.InRangeUnobstructed((uid, xform), (ent, ent.Comp), range: area.Range))
continue;

condition.Comp.CurrentScore += GetValue(ent, out _, area: true);
if (ent == args.Mind.CurrentEntity)
{
checkPlayer = false;
}
}
}
}

// Check thief's inventory
if (args.Mind.CurrentEntity != null && checkPlayer)
{
condition.Comp.CurrentScore += GetValue(args.Mind.CurrentEntity.Value, out _, self: true);
}

args.Progress = Math.Clamp((float)condition.Comp.CurrentScore / condition.Comp.TargetScore, 0f, 1f);
_metaData.SetEntityDescription(condition.Owner, Math.Clamp((int)((float)condition.Comp.CurrentScore/condition.Comp.TargetScore*100), 0, 100) + "%");
}

/// Get the price of an item (not including contained items) taking into account ScoreThiefPriceModifierComponent
public int GetValue(EntityUid entity, out string? reason, bool area = false, bool self = false)
{
reason = null;
var priceSystem = _entManager.System<PricingSystem>();
double multiplier = 1;
if (_modifierQuery.TryGetComponent(entity, out var modifier))
{
multiplier = modifier.Multiplier;
if (modifier.Reason != null)
{
reason = Loc.GetString(modifier.Reason);
}
}

if (_mindQuery.HasComp(entity))
{
if (!self)
{
reason = Loc.GetString("scorethief-modifier-alive");
return 0;
}
multiplier = 0;
}

var price = 0;

price = (int)(priceSystem.GetPrice(entity, false)*multiplier);

if (_containerQuery.TryComp(entity, out var containerManager) && !area)
{
foreach (var container in containerManager.Containers.Values)
{
foreach (var ent in container.ContainedEntities)
{
price += GetValue(ent, out _);
}
}
}

return price;
}

private int GetValueRecursive(ContainerManagerComponent currentManager)
{
var value = 0;
// recursively check each container
// checks inventory, bag, implants, etc.
foreach (var container in currentManager.Containers.Values)
{
foreach (var entity in container.ContainedEntities)
{
value += GetValue(entity, out _);
}
}
return value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Content.Server._Funkystation.ScoreThief.Systems;

namespace Content.Server._Funkystation.ScoreThief.Components;

/// <summary>
/// Gives an entity the innate ability to appraise items it looks at
/// </summary>
[RegisterComponent, Access(typeof(InnateAppraisalSystem))]
public sealed partial class InnateAppraisalComponent : Component
{
// Use ScoreThiefPriceModifierComponent?
[DataField]
public bool BlackMarket = false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using Content.Server._Funkystation.ScoreThief.Components;
using Content.Shared.Examine;
using Content.Shared.Verbs;
using JetBrains.Annotations;
using Robust.Shared.Utility;
using Content.Server._Funkystation.Objectives.Systems;
using Content.Server.Cargo.Systems;
using Robust.Shared.Containers;

namespace Content.Server._Funkystation.ScoreThief.Systems;

[UsedImplicitly]
public sealed partial class InnateAppraisalSystem : EntitySystem
{

[Dependency] private EntityQuery<InnateAppraisalComponent> _appraisalQuery = default!;
[Dependency] private ExamineSystemShared _examineSystem = default!;
[Dependency] private IEntityManager _entManager = default!;

public override void Initialize()
{
base.Initialize();
// Transform component because everything you can examine has it. We can't make args ref without this.
// Jank solution but it works sooooo whatever
SubscribeLocalEvent<TransformComponent, GetVerbsEvent<ExamineVerb>>(OnExamineVerb);
}

// Parts of this method were taken from https://github.com/funky-station/forky-station/blob/272393a35fb0a88097f7041c49356fb595aac138/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.cs
private void OnExamineVerb(Entity<TransformComponent> _, ref GetVerbsEvent<ExamineVerb> args)
{
if (!_appraisalQuery.TryComp(args.User, out var comp))
return;
var target = args.Target;
var user = args.User;
var verb = new ExamineVerb()
{
Act = () =>
{
var pricingSystem = _entManager.System<PricingSystem>();
var scoreThiefConditionSystem = _entManager.System<ScoreThiefConditionSystem>();
var price = 0;
string? reason = null;
if (comp.BlackMarket)
{
price = scoreThiefConditionSystem.GetValue(target, out reason);
}
else
{
price = (int)pricingSystem.GetPrice(target);
}
var markup = new FormattedMessage();
markup.AddMarkupOrThrow(Loc.GetString("scorethief-inspect-one") + " [color=green]" + price + "[/color] " + Loc.GetString("scorethief-inspect-two"));
if (reason != null)
{
markup.AddMarkupOrThrow("\n\n[color=gold]" + reason + "[/color]");
}
_examineSystem.SendExamineTooltip(user, target, markup, false, false);
},
Text = Loc.GetString("scorethief-appraise"),
Message = Loc.GetString("scorethief-appraise"),
Category = VerbCategory.Examine,
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Objects/Tools/appraisal-tool.rsi"), "icon"),
};

args.Verbs.Add(verb);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
scorethief-objective-title-one = Steal
scorethief-objective-title-two = worth of spesos of items
scorethief-inspect-one = This is worth
scorethief-inspect-two = spesos.
scorethief-appraise = Estimate the price of the item
scorethief-modifier-alive = Living things are too hard to transport to be worth it and dead things spoil.
scorethief-modifier-id = Basic ID cards are too traceable to be worth anything.
scorethief-modifier-cap-id = Certain people are willing to pay a lot for all-access on a Nanotrasen station.
scorethief-modifier-hop-id = Certain people are willing to pay a lot for near all-access on a Nanotrasen station.
scorethief-modifier-master-comms = Certain people are willing to pay a lot for all-comms on a Nanotrasen station.
scorethief-modifier-centcomm-comms = Certain people are willing to pay a lot to snoop on Central Command.
scorethief-modifier-command-comms = Certain people are willing to pay a lot for command comms.
scorethief-modifier-sec-comms = Certain people are willing to pay for security comms.
scorethief-modifier-critical-infrastructure = Critical station infrastructure is too high profile and easily traceable to be worth anything.
scorethief-modifier-money = Spesos' microdots make them easily traceable.

scorethief-role-greeting-human =
You are criminal scum, a professional thief previously arrested and on parole for grand theft. You are back to steal again.
You were forcibly given a pacifism implant after your last arrest, but that won't stop you from getting meeting the market's demands.

scorethief-role-greeting-animal =
You are a kleptomaniac animal.
Steal things that you like.

scorethief-role-greeting-equipment =
You have a satchel of thieves' tools and possess the innate ability to steal without notice. Choose your starting equipment, and do your work stealthily.
5 changes: 5 additions & 0 deletions Resources/Prototypes/Entities/Mobs/Player/silicon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,11 @@
- StationAiCoreElectronics
- type: StaticPrice
price: 5000
# Start funky changes
- type: ScoreThiefPriceModifier
reason: "scorethief-modifier-critical-infrastructure"
multiplier: 0
# End funky changes

# The job-ready version of an AI spawn.
- type: entity
Expand Down
Loading
Loading