Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trading & Contraband Crate Destinations #2602

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4c121fb
cargo destinations, WIP
whatston3 Dec 22, 2024
795770c
trade crate visualizations
whatston3 Dec 22, 2024
6bacb6a
Merge branch 'master' of https://github.com/new-frontiers-14/frontier…
whatston3 Dec 22, 2024
b004a8c
fix cargo destination icons
whatston3 Dec 22, 2024
f5c0230
fix & clean dependencies
whatston3 Dec 22, 2024
87c0ec1
fix cargo priority delays
whatston3 Dec 22, 2024
ab65676
minor cleanup & fixes
whatston3 Dec 23, 2024
563932c
TradeCrate: no freebies without destinations
whatston3 Dec 23, 2024
7b42b14
TradeCrateDestination: use string, validate proto
whatston3 Dec 23, 2024
664b75e
fix crate duration vars
whatston3 Dec 23, 2024
938e16e
force icon visible, fix active sprite
whatston3 Dec 23, 2024
010b78e
Fix trade crate priority markers
whatston3 Dec 23, 2024
e1b4da9
Swap contraband1 and 2 sprites
whatston3 Dec 23, 2024
79b8a7d
rotate inactive cargo priority sprite
whatston3 Dec 23, 2024
3f60ee2
Trade crate examine, bonus only on dest. delivery
whatston3 Dec 24, 2024
0588302
Add trade posts as dest, crates ignore market rate
whatston3 Dec 24, 2024
d2c555e
Count the cove as a wildcard trade crate dest
whatston3 Dec 24, 2024
4b83a0b
Remove filled trading crates (they aren't needed)
whatston3 Dec 24, 2024
3025d3c
Remove guidebook references to cargo crates
whatston3 Dec 24, 2024
6c75dd3
Merge branch 'master' of https://github.com/new-frontiers-14/frontier…
whatston3 Dec 24, 2024
8136aec
25 minutes for cargo crates with a giant comment
whatston3 Dec 25, 2024
5d4ed0d
slightly nicer letters (A,J,T,V)
whatston3 Dec 25, 2024
cfcf4a5
Most requested revisions
whatston3 Dec 26, 2024
912eb97
Clean CargoSystem.Shuttle.cs imports
whatston3 Dec 26, 2024
4632f79
examine text cleanup
whatston3 Dec 26, 2024
add6762
Rename TradeCrateComponent file
whatston3 Dec 26, 2024
5bb6bc0
Add NetworkedComponent attribute to TradeCrateComp
whatston3 Dec 26, 2024
5cce28b
Milon's suggestions, round 2
whatston3 Dec 27, 2024
03a03f0
Merge branch 'master' of https://github.com/new-frontiers-14/frontier…
whatston3 Dec 27, 2024
1dd80a0
emphasize trade crate express status
whatston3 Dec 27, 2024
a27193f
Downcast Entity to EntityUid
whatston3 Dec 27, 2024
9f6bf91
No serializer, missing space
whatston3 Dec 27, 2024
e7a8a6b
Merge branch 'master' of https://github.com/new-frontiers-14/frontier…
whatston3 Dec 27, 2024
12c09fe
Consolidate NF14 guidebook, add cargo hauling
whatston3 Dec 28, 2024
675d933
Add missing cargo hauling fluent entry
whatston3 Dec 28, 2024
2117622
Merge branch 'master' into 2024-12-22-cargo-destinations
whatston3 Dec 28, 2024
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
52 changes: 52 additions & 0 deletions Content.Client/_NF/Trade/TradeCrateVisualizerSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Content.Shared._NF.Trade;
using Robust.Client.GameObjects;
using Robust.Shared.Prototypes;

namespace Content.Client._NF.Trade;

/// <summary>
/// Visualizer for trade crates, largely based on Nyano's mail visualizer (thank you)
/// </summary>
public sealed class TradeCrateVisualizerSystem : VisualizerSystem<TradeCrateComponent>
{
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;

private const string FallbackIconID = "CargoOther";
private const string CargoPriorityActiveState = "cargo_priority_active";
private const string CargoPriorityInactiveState = "cargo_priority_inactive";

protected override void OnAppearanceChange(EntityUid uid, TradeCrateComponent component, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
return;

_appearance.TryGetData(uid, TradeCrateVisuals.DestinationIcon, out string job, args.Component);

if (string.IsNullOrEmpty(job))
job = FallbackIconID;

if (!_proto.TryIndex<TradeCrateDestinationPrototype>(job, out var icon))
icon = _proto.Index<TradeCrateDestinationPrototype>(FallbackIconID);

args.Sprite.LayerSetTexture(TradeCrateVisualLayers.Icon, _sprite.Frame0(icon.Icon));
args.Sprite.LayerSetVisible(TradeCrateVisualLayers.Icon, true);
if (_appearance.TryGetData(uid, TradeCrateVisuals.IsPriority, out bool isPriority) && isPriority)
{
args.Sprite.LayerSetVisible(TradeCrateVisualLayers.Priority, true);
if (_appearance.TryGetData(uid, TradeCrateVisuals.IsPriorityInactive, out bool inactive) && inactive)
args.Sprite.LayerSetState(TradeCrateVisualLayers.Priority, CargoPriorityInactiveState);
else
args.Sprite.LayerSetState(TradeCrateVisualLayers.Priority, CargoPriorityActiveState);
}
else
args.Sprite.LayerSetVisible(TradeCrateVisualLayers.Priority, false);
}
}

public enum TradeCrateVisualLayers : byte
{
Icon,
Priority
}
34 changes: 24 additions & 10 deletions Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
using Content.Server.Cargo.Components;
using Content.Shared.Stacks;
using Content.Shared.Bank.Components;
using Content.Shared.Cargo;
using Content.Shared.Cargo.BUI;
using Content.Shared.Cargo.Components;
using Content.Shared.Cargo.Events;
using Content.Shared.GameTicking;
using Content.Shared.Mobs;
using Robust.Shared.Map;
using Robust.Shared.Random;
whatston3 marked this conversation as resolved.
Show resolved Hide resolved
using Robust.Shared.Audio;
using Content.Shared.Mind.Components; // Frontier
using Content.Server._NF.Cargo.Components; // Frontier
using Content.Shared.Bank.Components; // Frontier
using Content.Shared.Mobs; // Frontier

namespace Content.Server.Cargo.Systems;

Expand Down Expand Up @@ -67,11 +67,14 @@ private void UpdatePalletConsoleInterface(EntityUid uid)
new CargoPalletConsoleInterfaceState(0, 0, false));
return;
}
GetPalletGoods(uid, gridUid, out var toSell, out var amount);
GetPalletGoods(uid, gridUid, out var toSell, out var amount, out var noModAmount); // Frontier: add noModAmount
// Frontier
if (TryComp<MarketModifierComponent>(uid, out var priceMod))
{
amount *= priceMod.Mod;
}
amount += noModAmount;
// End Frontier
_uiSystem.SetUiState(uid, CargoPalletConsoleUiKey.Sale,
new CargoPalletConsoleInterfaceState((int) amount, toSell.Count, true));
}
Expand Down Expand Up @@ -259,11 +262,11 @@ public static double CalculateDistance(EntityCoordinates point1, EntityCoordinat

#region Station

private bool SellPallets(EntityUid consoleUid, EntityUid gridUid, out double amount)
private bool SellPallets(EntityUid consoleUid, EntityUid gridUid, out double amount, out double noMultiplierAmount) // Frontier: add noMultiplierAmount
{
GetPalletGoods(consoleUid, gridUid, out var toSell, out amount);
GetPalletGoods(consoleUid, gridUid, out var toSell, out amount, out noMultiplierAmount); // Frontier: add noMultiplierAmount

Log.Debug($"Cargo sold {toSell.Count} entities for {amount}");
Log.Debug($"Cargo sold {toSell.Count} entities for {amount} (plus {noMultiplierAmount} without mods)"); // Frontier: add section in parentheses

if (toSell.Count == 0)
return false;
Expand All @@ -280,9 +283,10 @@ private bool SellPallets(EntityUid consoleUid, EntityUid gridUid, out double amo
return true;
}

private void GetPalletGoods(EntityUid consoleUid, EntityUid gridUid, out HashSet<EntityUid> toSell, out double amount)
private void GetPalletGoods(EntityUid consoleUid, EntityUid gridUid, out HashSet<EntityUid> toSell, out double amount, out double noMultiplierAmount) // Frontier: add noMultiplierAmount
{
amount = 0;
noMultiplierAmount = 0;
toSell = new HashSet<EntityUid>();

foreach (var (palletUid, _, _) in GetCargoPallets(consoleUid, gridUid, BuySellType.Sell))
Expand Down Expand Up @@ -313,7 +317,13 @@ private void GetPalletGoods(EntityUid consoleUid, EntityUid gridUid, out HashSet
if (price == 0)
continue;
toSell.Add(ent);
amount += price;

// Frontier: check for items that are immune to market modifiers
if (HasComp<IgnoreMarketModifierComponent>(ent))
noMultiplierAmount += price;
else
amount += price;
// End Frontier: check for items that are immune to market modifiers
}
}
}
Expand Down Expand Up @@ -356,13 +366,16 @@ private void OnPalletSale(EntityUid uid, CargoPalletConsoleComponent component,
return;
}

if (!SellPallets(uid, gridUid, out var price))
if (!SellPallets(uid, gridUid, out var price, out var noMultiplierPrice)) // Frontier: add noMultiplierPrice
return;

// Frontier: market modifiers & immune objects
if (TryComp<MarketModifierComponent>(uid, out var priceMod))
{
price *= priceMod.Mod;
}
price += noMultiplierPrice;
// End Frontier: market modifiers & immune objects
var stackPrototype = _protoMan.Index<StackPrototype>(component.CashType);
_stack.Spawn((int) price, stackPrototype, xform.Coordinates);
_audio.PlayPvs(ApproveSound, uid);
Expand All @@ -374,6 +387,7 @@ private void OnPalletSale(EntityUid uid, CargoPalletConsoleComponent component,
private void OnRoundRestart(RoundRestartCleanupEvent ev)
{
Reset();
CleanupTradeCrateDestinations(); // Frontier
}
}

Expand Down
5 changes: 2 additions & 3 deletions Content.Server/Cargo/Systems/CargoSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
using Robust.Shared.Timing;
using Robust.Shared.Random;
using Content.Server._NF.SectorServices; // Frontier
using Content.Shared._NF.Trade.Components; // Frontier
using Content.Shared._NF.Trade; // Frontier
using Content.Shared.Whitelist; // Frontier

namespace Content.Server.Cargo.Systems;
Expand Down Expand Up @@ -50,7 +50,6 @@ public sealed partial class CargoSystem : SharedCargoSystem

private EntityQuery<TransformComponent> _xformQuery;
private EntityQuery<CargoSellBlacklistComponent> _blacklistQuery;
private EntityQuery<TradeCrateComponent> _tradeCrateQuery;
private EntityQuery<MobStateComponent> _mobQuery;
private EntityQuery<TradeStationComponent> _tradeQuery;

Expand All @@ -64,7 +63,6 @@ public override void Initialize()

_xformQuery = GetEntityQuery<TransformComponent>();
_blacklistQuery = GetEntityQuery<CargoSellBlacklistComponent>();
_tradeCrateQuery = GetEntityQuery<TradeCrateComponent>();
_mobQuery = GetEntityQuery<MobStateComponent>();
_tradeQuery = GetEntityQuery<TradeStationComponent>();

Expand All @@ -74,6 +72,7 @@ public override void Initialize()
InitializeBounty();
// Frontier: add specific initialization calls here.
InitializePirateBounty();
InitializeTradeCrates();
// End Frontier
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Content.Server._NF.Cargo.Components;

/// <summary>
/// Designates an entity as ignoring market modifiers.
/// </summary>
[RegisterComponent]
public sealed partial class IgnoreMarketModifierComponent : Component;
110 changes: 110 additions & 0 deletions Content.Server/_NF/Cargo/Systems/CargoSystem.TradeCrates.cs
whatston3 marked this conversation as resolved.
Show resolved Hide resolved
whatston3 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using System.Threading;
using Content.Server._NF.Trade;
using Content.Shared._NF.Trade;
using Content.Shared.Examine;
using Timer = Robust.Shared.Timing.Timer;

namespace Content.Server.Cargo.Systems; // Needs to collide with base namespace

public sealed partial class CargoSystem
{
private readonly List<EntityUid> _destinations = new();

private void InitializeTradeCrates()
{
SubscribeLocalEvent<TradeCrateComponent, PriceCalculationEvent>(OnTradeCrateGetPriceEvent);
SubscribeLocalEvent<TradeCrateComponent, ComponentInit>(OnTradeCrateInit);
SubscribeLocalEvent<TradeCrateComponent, ComponentRemove>(OnTradeCrateRemove);
SubscribeLocalEvent<TradeCrateComponent, ExaminedEvent>(OnTradeCrateExamined);

SubscribeLocalEvent<TradeCrateDestinationComponent, ComponentInit>(OnDestinationInit);
SubscribeLocalEvent<TradeCrateDestinationComponent, ComponentRemove>(OnDestinationRemove);
}

private void OnTradeCrateGetPriceEvent(Entity<TradeCrateComponent> ent, ref PriceCalculationEvent ev)
{
var owningStation = _station.GetOwningStation(ent.Owner);
whatston3 marked this conversation as resolved.
Show resolved Hide resolved
var atDestination = ent.Comp.DestinationStation != EntityUid.Invalid
&& owningStation == ent.Comp.DestinationStation
|| HasComp<TradeCrateWildcardDestinationComponent>(owningStation);
ev.Price = atDestination ? ent.Comp.ValueAtDestination : ent.Comp.ValueElsewhere;
if (ent.Comp.ExpressDeliveryTime != null)
{
if (_timing.CurTime <= ent.Comp.ExpressDeliveryTime && atDestination)
ev.Price += ent.Comp.ExpressOnTimeBonus;
else if (_timing.CurTime > ent.Comp.ExpressDeliveryTime)
ev.Price -= ent.Comp.ExpressLatePenalty;
}
ev.Price = double.Max(0.0, ev.Price); // Ensure non-negative values.
}

private void OnTradeCrateInit(Entity<TradeCrateComponent> ent, ref ComponentInit ev)
{
// If there are no available destinations, tough luck.
if (_destinations.Count > 0)
{
var randomIndex = _random.Next(_destinations.Count);
// Better have more than one destination.
if (_station.GetOwningStation(ent.Owner) == _destinations[randomIndex])
whatston3 marked this conversation as resolved.
Show resolved Hide resolved
{
randomIndex = (randomIndex + 1 + _random.Next(_destinations.Count - 1)) % _destinations.Count;
}
var destination = _destinations[randomIndex];
ent.Comp.DestinationStation = destination;
if (TryComp<TradeCrateDestinationComponent>(destination, out var destComp))
_appearance.SetData(ent.Owner, TradeCrateVisuals.DestinationIcon, destComp.DestinationProto.Id);
whatston3 marked this conversation as resolved.
Show resolved Hide resolved
}

if (ent.Comp.ExpressDeliveryDuration > TimeSpan.Zero)
{
ent.Comp.ExpressDeliveryTime = _timing.CurTime + ent.Comp.ExpressDeliveryDuration;
_appearance.SetData(ent.Owner, TradeCrateVisuals.IsPriority, true);
whatston3 marked this conversation as resolved.
Show resolved Hide resolved

ent.Comp.ExpressCancelToken = new CancellationTokenSource();
Timer.Spawn((int)ent.Comp.ExpressDeliveryDuration.TotalMilliseconds,
() => DisableTradeCratePriority(ent.Owner),
whatston3 marked this conversation as resolved.
Show resolved Hide resolved
ent.Comp.ExpressCancelToken.Token);
}
}

private void OnTradeCrateRemove(Entity<TradeCrateComponent> ent, ref ComponentRemove ev)
{
ent.Comp.ExpressCancelToken?.Cancel();
}

private void OnTradeCrateExamined(Entity<TradeCrateComponent> ent, ref ExaminedEvent ev)
{
if (!TryComp(ent.Comp.DestinationStation, out MetaDataComponent? metadata))
return;

ev.PushMarkup(Loc.GetString("trade-crate-destination-station", ("destination", metadata.EntityName)));

if (ent.Comp.ExpressDeliveryTime == null)
return;

ev.PushMarkup(ent.Comp.ExpressDeliveryTime >= _timing.CurTime ?
Loc.GetString("trade-crate-priority-active") :
Loc.GetString("trade-crate-priority-inactive"));
}

private void DisableTradeCratePriority(EntityUid uid)
{
_appearance.SetData(uid, TradeCrateVisuals.IsPriorityInactive, true);
}

private void OnDestinationInit(Entity<TradeCrateDestinationComponent> ent, ref ComponentInit ev)
{
if (!_destinations.Contains(ent.Owner))
_destinations.Add(ent.Owner);
whatston3 marked this conversation as resolved.
Show resolved Hide resolved
}

private void OnDestinationRemove(Entity<TradeCrateDestinationComponent> ent, ref ComponentRemove ev)
{
_destinations.Remove(ent.Owner);
whatston3 marked this conversation as resolved.
Show resolved Hide resolved
}

private void CleanupTradeCrateDestinations()
{
_destinations.Clear();
}
}
2 changes: 1 addition & 1 deletion Content.Server/_NF/GameRule/NfAdventureRuleSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using Content.Server.Cargo.Components;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules;
using Content.Shared._NF.CCVar; // Frontier
using Content.Shared._NF.CCVar;
using Robust.Shared.Configuration;
using Content.Shared._NF.Bank;
using Content.Server._NF.GameRule.Components;
Expand Down
10 changes: 10 additions & 0 deletions Content.Server/_NF/GameRule/PointOfInterestSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Content.Server.GameTicking;
using Content.Shared._NF.CCVar;
using Content.Shared.GameTicking;
using Content.Server._NF.Trade;

namespace Content.Server._NF.GameRule;

Expand Down Expand Up @@ -83,6 +84,15 @@ public void GenerateDepots(MapId mapUid, List<PointOfInterestPrototype> depotPro
overrideName += $" {i + 1}"; // " 27", " 28"...
if (TrySpawnPoiGrid(mapUid, proto, offset, out var depotUid, overrideName: overrideName) && depotUid is { Valid: true } depot)
{
// Nasty jank: set up destination in the station.
var depotStation = _station.GetOwningStation(depot);
if (TryComp<TradeCrateDestinationComponent>(depotStation, out var destComp))
{
if (i < 26)
destComp.DestinationProto = $"Cargo{(char)('A' + i)}";
else
destComp.DestinationProto = "CargoOther";
}
depotStations.Add(depot);
AddStationCoordsToSet(offset); // adjust list of actual station coords
}
Expand Down
14 changes: 14 additions & 0 deletions Content.Server/_NF/Trade/TradeCrateDestinationComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Content.Shared._NF.Trade;
using Robust.Shared.Prototypes;

namespace Content.Server._NF.Trade;

/// <summary>
/// This is used to mark an entity to be used as a destination for trade crates.
/// </summary>
[RegisterComponent]
public sealed partial class TradeCrateDestinationComponent : Component
{
[DataField(required: true)]
public ProtoId<TradeCrateDestinationPrototype> DestinationProto;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Content.Server._NF.Trade;

/// <summary>
/// This marks a station as matching all trade crate destinations.
/// Useful, for example, for black market stations or pirate coves.
/// </summary>
[RegisterComponent]
public sealed partial class TradeCrateWildcardDestinationComponent : Component;
2 changes: 1 addition & 1 deletion Content.Shared/Access/Systems/AccessReaderSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
using Robust.Shared.Collections;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Content.Shared._NF.Trade.Components;
using Content.Shared._NF.Trade;

namespace Content.Shared.Access.Systems;

Expand Down
3 changes: 0 additions & 3 deletions Content.Shared/Lock/LockSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@
using JetBrains.Annotations;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Utility;
using Content.Shared._NF.Trade.Components;
using Content.Shared.Emag.Components;
using System.Text;
using Content.Shared.Storage;
whatston3 marked this conversation as resolved.
Show resolved Hide resolved
using Robust.Shared.Audio; // Frontier - DEMAG

namespace Content.Shared.Lock;
Expand Down
Loading
Loading