Skip to content

Commit

Permalink
Smuggling posters are now random and NFSD gets rewarded for getting p…
Browse files Browse the repository at this point in the history
…rints of posters and dead drops (#1667)

* Changed the time between dead drops and distance

* Removed deprecated GetMapEntityId for TryGetMap

* Removed tags that match autogenereated ones and simplified new Color

* Made the distance even smaller

* Revert "Made the distance even smaller"

This reverts commit a008ba6.

* Added check to see how many dead drop components are nearby

* Changed behaviour of dead drop posters and added all of the previous posters to the dead drop system

* Posters are finally random, only one can be active per point of interest

* Added a message of the drop pod location to the NSFD after 15 minutes and made the wait time faster for posters

* Scanning activated dead drop posters gives 30k cash to NFSD and dead drop location is now said by NFSD Outpost

* NFSD scanning objects on the dead drop will reward them with 60k spessos and functioned the code for giving rewards

* Changed spessos rewards to FUC

* The timer now resets for the current poster if it detects any other posters that are active nearby

* Lowered the chance of posters appearing and thus being Dead Drops, made pirates have a 1/3 of knowing the smuggler's ship ID after 15 minutes and added a guidebook entry

* Increased the MinimumCooldown to 15 minutes and NFSD now gets progressive hints at dead drop posters' locations

* Syndicate Supply Ships are now limited to 5 and if more are spawned, the oldest one gets deleted. Also only detectives get rewards for scanning dead drops and their posters

* Moved all of the radio strings to locale and additional comments

* Forensic scanner system now tracks based on access level rather than role name, removed accidental file and added a 1/10 chance to spawn a syndicate mob in the dead drop. Also fixed some stuff from last commit

* Removed the syndicate mob guy because he would step on mines and lose his gun after FTL

* Changed the dead drop poster cooldown to 5-10 minutes but now only 2 can be active at a time

* Random contraband generation, part one

* Station dead drop config, generation

* Forensics cartridge, nfsd uplink entry

* forensic scanner, staton definitions

* Missing/inconsistent localization strings

* HardSuit->Hardsuit

* A few more uplink fixes

* Revise dead drop tracking, always payout, add $

* Prototype-based smuggling message passing

* POI map fixes, revert health, remove MapInit

* Logging, anchored items, no drops @ courthouse

* Dead drop value fiddling, uplink rewrites

* cleanup

* CVARS!

* Move prototype to Shared

* Fix config, cleanup, random error in drop pod msgs

* fix forensic printouts, dead drop spawn menu

* separate speso/fuc reward prints

* Min/Max delay to floats

* DeadDropSystem: type fix

* Fix pirate delay, NFSD delay: 14-16 mins

* Random fax generator & event

* Roundstart hint generation

* Remove test dead drop hints

* Bugfixes for dead drop hint gen

* more paper!

* Smuggling guidebook entry, remove unneeded sec pgs

* More smoog crate value, c3 trade crates, debug

* Better drop pod scanner rewards

* DD writable VV field, fix crate parent

* WindowedEvent fixes

* event naming

* Add time to dead drop notes

* Freelancer->Freelance channel

* PodLocation messages: fix precision for vectors

* Disable shipyard sale component, tweak smoog param

* Multiple faxes per event

* fax and logic

* security_uplink_catalog: forensic module 2->4 FUC

---------

Co-authored-by: Dvir <[email protected]>
Co-authored-by: Whatstone <[email protected]>
Co-authored-by: Checkraze <[email protected]>
  • Loading branch information
4 people committed Sep 22, 2024
1 parent d8a0027 commit 43af034
Show file tree
Hide file tree
Showing 90 changed files with 2,104 additions and 424 deletions.
150 changes: 149 additions & 1 deletion Content.Server/Forensics/Systems/ForensicScannerSystem.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
using System.Linq;
using System.Text;
using Content.Server.Popups;
using Content.Server.Stack; // Frontier
using Content.Server._NF.Smuggling; // Frontier
using Content.Server._NF.Smuggling.Components; // Frontier
using Content.Server.Cargo.Systems; // Frontier
using Content.Server.Radio.EntitySystems; // Frontier
using Content.Shared.UserInterface;
using Content.Shared.DoAfter;
using Content.Shared.Fluids.Components;
Expand All @@ -9,13 +14,24 @@
using Content.Shared.Interaction;
using Content.Shared.Paper;
using Content.Shared.Verbs;
using Content.Shared.Stacks; // Frontier
using Content.Shared.Radio; // Frontier
using Content.Shared.Access.Systems; // Frontier
using Robust.Shared.Prototypes; // Frontier
using Content.Shared.Tag;
using Robust.Shared.Audio.Systems;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Player;
using Robust.Shared.Timing;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Containers.ItemSlots; // Frontier
using Content.Server.Cargo.Components; // Frontier
using Content.Server._NF.SectorServices; // Frontier
using Content.Shared.FixedPoint; // Frontier
using Robust.Shared.Configuration; // Frontier
using Content.Shared._NF.CCVar;
using Content.Shared._NF.Bank; // Frontier

// todo: remove this stinky LINQy

namespace Content.Server.Forensics
Expand All @@ -33,6 +49,30 @@ public sealed class ForensicScannerSystem : EntitySystem
[Dependency] private readonly ForensicsSystem _forensicsSystem = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly StackSystem _stackSystem = default!; // Frontier
[Dependency] private readonly SharedAudioSystem _audio = default!; // Frontier
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; // Frontier
[Dependency] private readonly RadioSystem _radio = default!; // Frontier
[Dependency] private readonly AccessReaderSystem _accessReader = default!; // Frontier
[Dependency] private readonly DeadDropSystem _deadDrop = default!; // Frontier
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!; // Frontier
[Dependency] private readonly CargoSystem _cargo = default!; // Frontier
[Dependency] private readonly SectorServiceSystem _service = default!; // Frontier
[Dependency] private readonly IConfigurationManager _cfg = default!; // Frontier

// Frontier: payout constants
// Temporary values, sane defaults, will be overwritten by CVARs.
private int _minFUCPayout = 2;

private const int ActiveUnusedDeadDropSpesoReward = 20000;
private const float ActiveUnusedDeadDropFUCReward = 2.0f;
private const int ActiveUsedDeadDropSpesoReward = 10000;
private const float ActiveUsedDeadDropFUCReward = 1.0f;
private const int InactiveUsedDeadDropSpesoReward = 5000;
private const float InactiveUsedDeadDropFUCReward = 0.5f;
private const int DropPodSpesoReward = 10000;
private const float DropPodFUCReward = 1.0f;
// End Frontier: payout constants

public override void Initialize()
{
Expand All @@ -45,7 +85,73 @@ public override void Initialize()
SubscribeLocalEvent<ForensicScannerComponent, ForensicScannerPrintMessage>(OnPrint);
SubscribeLocalEvent<ForensicScannerComponent, ForensicScannerClearMessage>(OnClear);
SubscribeLocalEvent<ForensicScannerComponent, ForensicScannerDoAfterEvent>(OnDoAfter);

Subs.CVar(_cfg, NFCCVars.SmugglingMinFucPayout, OnMinFucPayoutChanged, true); // Frontier
}

private void OnMinFucPayoutChanged(int newMin)
{
_minFUCPayout = newMin;
}

// Frontier: add dead drop rewards
/// <summary>
/// Rewards the NFSD department for scanning a dead drop.
/// Gives some amount of spesos and FUC to the
/// </summary>
private void GiveReward(EntityUid uidOrigin, EntityUid target, int spesoAmount, FixedPoint2 fucAmount, string msg)
{
SoundSpecifier confirmSound = new SoundPathSpecifier("/Audio/Effects/Cargo/ping.ogg");
_audio.PlayPvs(_audio.GetSound(confirmSound), uidOrigin);

// Credit the NFSD's bank account (todo: split these)
if (spesoAmount > 0)
{
var queryBank = EntityQuery<StationBankAccountComponent>();
foreach (var account in queryBank)
{
_cargo.DeductFunds(account, -spesoAmount);
}
}
else
spesoAmount = 0;

if (fucAmount > 0)
{
// Accumulate sector-wide FUCs, pay out if min threshold met
if (TryComp<SectorDeadDropComponent>(_service.GetServiceEntity(), out var sectorDD))
{
sectorDD.FUCAccumulator += fucAmount;
if (sectorDD.FUCAccumulator >= _minFUCPayout)
{
// inherent floor
int payout = sectorDD.FUCAccumulator.Int();
sectorDD.FUCAccumulator -= payout;

var stackPrototype = _prototypeManager.Index<StackPrototype>("FrontierUplinkCoin");
_stackSystem.Spawn(payout, stackPrototype, Transform(target).Coordinates);
}
}
}
else
fucAmount = 0;

var channel = _prototypeManager.Index<RadioChannelPrototype>("Nfsd");
string msgString = Loc.GetString(msg);
if (fucAmount >= 1)
{
msgString = msgString + " " + Loc.GetString("forensic-reward-amount",
("spesos", BankSystemExtensions.ToSpesoString(spesoAmount)),
("fuc", BankSystemExtensions.ToFUCString(fucAmount.Int())));
}
else
{
msgString = msgString + " " + Loc.GetString("forensic-reward-amount-speso-only",
("spesos", BankSystemExtensions.ToSpesoString(spesoAmount)));
}
_radio.SendRadioMessage(uidOrigin, msgString, channel, uidOrigin);
}
// End Frontier: add dead drop rewards

private void UpdateUserInterface(EntityUid uid, ForensicScannerComponent component)
{
Expand Down Expand Up @@ -87,6 +193,48 @@ private void OnDoAfter(EntityUid uid, ForensicScannerComponent component, DoAfte
scanner.Residues = forensics.Residues.ToList();
}

// Frontier: contraband poster/pod scanning
if (_itemSlots.TryGetSlot(uid, "forensics_cartridge", out var itemSlot) && itemSlot.HasItem)
{
EntityUid target = args.Args.Target.Value;
if (TryComp<DeadDropComponent>(target, out var deadDrop))
{
// If there's a dead drop note present, pay out regardless and compromise the dead drop.
if (_gameTiming.CurTime >= deadDrop.NextDrop)
{
int spesoReward;
FixedPoint2 fucReward;
string msg;
if (deadDrop.DeadDropCalled)
{
spesoReward = ActiveUsedDeadDropSpesoReward;
fucReward = ActiveUsedDeadDropFUCReward;
msg = "forensic-reward-dead-drop-used-present";
}
else
{
spesoReward = ActiveUnusedDeadDropSpesoReward;
fucReward = ActiveUnusedDeadDropFUCReward;
msg = "forensic-reward-dead-drop-unused";
}
GiveReward(uid, target, spesoReward, fucReward, msg);
_deadDrop.CompromiseDeadDrop(target, deadDrop);
}
// Otherwise, if it's been used, pay out at a reduced rate and compromise it.
else if (deadDrop.DeadDropCalled)
{
GiveReward(uid, target, InactiveUsedDeadDropSpesoReward, InactiveUsedDeadDropFUCReward, "forensic-reward-dead-drop-used-gone");
_deadDrop.CompromiseDeadDrop(target, deadDrop);
}
}
else if (TryComp<ContrabandPodGridComponent>(Transform(target).GridUid, out var pod) && !pod.Scanned)
{
GiveReward(uid, target, DropPodSpesoReward, DropPodFUCReward, "forensic-reward-pod");
pod.Scanned = true;
}
}
// End Frontier: contraband poster/pod scanning

if (_tag.HasTag(args.Args.Target.Value, "DNASolutionScannable"))
{
scanner.SolutionDNAs = _forensicsSystem.GetSolutionsDNA(args.Args.Target.Value);
Expand Down
34 changes: 34 additions & 0 deletions Content.Server/Shipyard/Systems/ShipyardSystem.Consoles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
using Robust.Shared.Audio.Systems;
using Content.Shared.Access;
using Content.Shared.Tiles;
using Content.Server._NF.Smuggling.Components;

namespace Content.Server.Shipyard.Systems;

Expand Down Expand Up @@ -367,6 +368,17 @@ public void OnSellMessage(EntityUid uid, ShipyardConsoleComponent component, Shi

var shuttleName = ToPrettyString(shuttleUid); // Grab the name before it gets 1984'd

// Check for shipyard blacklisting components
var disableSaleQuery = GetEntityQuery<DisableShipyardSaleComponent>();
var xformQuery = GetEntityQuery<TransformComponent>();
var disableSaleMsg = FindDisableShipyardSaleObjects(shuttleUid, (ShipyardConsoleUiKey)args.UiKey, disableSaleQuery, xformQuery);
if (disableSaleMsg != null)
{
ConsolePopup(args.Actor, Loc.GetString(disableSaleMsg));
PlayDenySound(args.Actor, uid, component);
return;
}

var saleResult = TrySellShuttle(stationUid, shuttleUid, out var bill);
if (saleResult.Error != ShipyardSaleError.Success)
{
Expand Down Expand Up @@ -606,6 +618,28 @@ private void OnItemSlotChanged(EntityUid uid, ShipyardConsoleComponent component
return null;
}

/// <summary>
/// Looks for a living, sapient being aboard a particular entity.
/// </summary>
/// <param name="uid">The entity to search (e.g. a shuttle, a station)</param>
/// <param name="mobQuery">A query to get the MobState from an entity</param>
/// <param name="xformQuery">A query to get the transform component of an entity</param>
/// <returns>The name of the sapient being if one was found, null otherwise.</returns>
public string? FindDisableShipyardSaleObjects(EntityUid shuttle, ShipyardConsoleUiKey key, EntityQuery<DisableShipyardSaleComponent> disableSaleQuery, EntityQuery<TransformComponent> xformQuery)
{
var xform = xformQuery.GetComponent(shuttle);
var childEnumerator = xform.ChildEnumerator;

while (childEnumerator.MoveNext(out var child))
{
if (disableSaleQuery.TryGetComponent(child, out var disableSale)
&& !disableSale.AllowedShipyardTypes.Contains(key))
return disableSale.Reason;
}

return null;
}

private struct IDShipAccesses
{
public IReadOnlyCollection<ProtoId<AccessLevelPrototype>> Tags;
Expand Down
4 changes: 4 additions & 0 deletions Content.Server/Shipyard/Systems/ShipyardSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using Content.Shared.Shipyard.Events;
using Content.Shared.Mobs.Components;
using Robust.Shared.Containers;
using Content.Server._NF.Smuggling.Components;

namespace Content.Server.Shipyard.Systems;

Expand Down Expand Up @@ -46,12 +47,15 @@ public enum ShipyardSaleError
Undocked, // Ship is not docked with the station.
OrganicsAboard, // Sapient intelligence is aboard, cannot sell, would delete the organics
InvalidShip, // Ship is invalid
MessageOverwritten, // Overwritten message.
}

// TODO: swap to strictly being a formatted message.
public struct ShipyardSaleResult
{
public ShipyardSaleError Error; // Whether or not the ship can be sold.
public string? OrganicName; // In case an organic is aboard, this will be set to the first that's aboard.
public string? OverwrittenMessage; // The message to write if Error is MessageOverwritten.
}

public override void Initialize()
Expand Down
4 changes: 4 additions & 0 deletions Content.Server/_NF/Forensics/ForensicsCartridgeComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace Content.Server._NF.Forensics;

[RegisterComponent]
public sealed partial class ForensicsCartridgeComponent : Component;
7 changes: 7 additions & 0 deletions Content.Server/_NF/GameRule/NfAdventureRuleSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
using Content.Shared._NF.GameRule;
using Content.Server.Procedural;
using Content.Shared.Bank.Components;
using Content.Server._NF.GameTicking.Events;
using Content.Server.GameTicking.Events;
using Content.Server.GameTicking.Rules.Components;
using Content.Shared.Procedural;
using Robust.Server.GameObjects;
using Robust.Server.Maps;
Expand All @@ -23,6 +26,7 @@
using Robust.Shared.Random;
using Robust.Shared.Map.Components;
using Content.Shared.Shuttles.Components;
using Content.Server._NF.GameTicking.Events;
using Content.Server.Shuttles.Systems;
using Content.Server.Cargo.Components;
using Content.Server.GameTicking;
Expand Down Expand Up @@ -161,6 +165,9 @@ protected override void Started(EntityUid uid, AdventureRuleComponent component,

base.Started(uid, component, gameRule, args);

// Using invalid entity, we don't have a relevant entity to reference here.
RaiseLocalEvent(EntityUid.Invalid, new StationsGeneratedEvent(), broadcast: true); // TODO: attach this to a meaningful entity.

var dungenTypes = _prototypeManager.EnumeratePrototypes<DungeonConfigPrototype>();

foreach (var dunGen in dungenTypes)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Robust.Shared.Prototypes;

namespace Content.Server.GameTicking.Rules.VariationPass.Components;

/// <summary>
/// This handles generating round-start dead drop hints.
/// </summary>
[RegisterComponent]
public sealed partial class DeadDropHintVariationPassComponent : Component
{
/// <summary>
/// Chance that a potential hint will be generated on a table.
/// Remember, the average number
/// </summary>
[DataField]
public float HintSpawnChance = 0.02f;

/// <summary>
/// The entity to spawn for a hint.
/// </summary>
[DataField]
public EntProtoId HintSpawnPrototype = "PaperDeadDropHint";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Content.Server._NF.Smuggling.Components;
using Content.Server.GameTicking.Rules.VariationPass.Components;
using Content.Shared.Climbing.Components;
using Content.Shared.Placeable;

namespace Content.Server.GameTicking.Rules.VariationPass;

/// <inheritdoc cref="DeadDropHintVariationPassComponent"/>
public sealed class DeadDropHintVariationPass : VariationPassSystem<DeadDropHintVariationPassComponent>
{
protected override void ApplyVariation(Entity<DeadDropHintVariationPassComponent> ent, ref StationVariationPassEvent args)
{
if (HasComp<StationDeadDropHintExemptComponent>(args.Station))
return;

// Best query for table-like objects: bonkable filters out grills.
var query = AllEntityQuery<BonkableComponent, PlaceableSurfaceComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var _, out var _, out var xform))
{
if (!IsMemberOfStation((uid, xform), ref args))
continue;

var prob = Random.NextFloat();
if (prob < ent.Comp.HintSpawnChance)
{
SpawnAttachedTo(ent.Comp.HintSpawnPrototype, xform.Coordinates);
}
}
}
}
11 changes: 11 additions & 0 deletions Content.Server/_NF/GameTicking/SectorGeneratedEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Content.Server._NF.GameTicking.Events;

/// <summary>
/// Raised once all of the stations have been generated.
/// </summary>
public sealed class StationsGeneratedEvent : EntityEventArgs
{
public StationsGeneratedEvent()
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Content.Server._NF.Smuggling.Components;

/// <summary>
/// Denotes a grid that is brought in via a dead drop.
/// </summary>
[RegisterComponent]
public sealed partial class ContrabandPodGridComponent : Component
{
/// <summary>
/// Maximum number of dead drops to spawn on the station.
/// </summary>
[DataField]
public bool Scanned = false;
}
Loading

0 comments on commit 43af034

Please sign in to comment.