Trading request system (#1460)

* mapping public stores update

* base selling platform update

* basic UI setup

* Update coin icon textures

Refreshed the c, g, p, and s coin images in the interface textures. This likely improves their appearance or corrects previous visual issues.

* parse requests data into UI

* selling platform UI state now include price

Updated the selling platform UI to display the calculated price of placed items. Moved the UpdateSellingUIState logic from the shared system to the server system, and modified the CP14SellingPlatformUiState to include a price field. The client window now uses the state-provided price instead of a hardcoded value.

* Update selling UI state on item placed or removed

Added event subscriptions for ItemPlacedEvent and ItemRemovedEvent to update the selling UI state when items are placed or removed from the selling platform. Refactored UpdateSellingUIState to remove the user parameter, as it is no longer needed.

* sell button works now

Replaces the previous sell request mechanism with a new CP14TradingSellAttempt message for selling items on the platform. Updates client and server logic to use this new message, adds a CanSell helper for item validation, and refactors related UI and event handling code for improved clarity and maintainability.

* auto pricing requirements

* Refactor reputation reward to use cashback rate

Reputation rewards for selling requests are now calculated as a percentage (cashback) of the sale price, rather than a fixed value. Updated the relevant UI, server logic, and prototype fields to reflect this change. Also cleaned up the brad_potions.yml prototype file by removing a duplicate entry and correcting an ID.

* request rerolling
This commit is contained in:
Red
2025-06-23 01:21:25 +03:00
committed by GitHub
parent fb76a9d80d
commit b1a9fca5ee
53 changed files with 31114 additions and 5958 deletions

View File

@@ -0,0 +1,40 @@
<Control xmlns="https://spacestation14.io"
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
HorizontalExpand="True"
Margin="5">
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
<PanelContainer Margin="0 10 0 0" VerticalExpand="True">
<PanelContainer.PanelOverride>
<graphics:StyleBoxFlat BackgroundColor="#35363b" />
</PanelContainer.PanelOverride>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
<!-- Request requirements content -->
<!-- Added by code -->
<BoxContainer
Name="ItemRequirements"
Margin="10"
Orientation="Vertical" VerticalExpand="True"
HorizontalExpand="True" />
<!-- Reward -->
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
<BoxContainer Orientation="Horizontal" Margin="0 0 12 5" HorizontalExpand="True"
VerticalExpand="True" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<TextureRect VerticalAlignment="Center" Visible="True" HorizontalAlignment="Center"
Margin="10" TextureScale="2, 2"
TexturePath="/Textures/_CP14/Interface/Misc/star.png" />
<Label Name="Reputation" />
</BoxContainer>
<BoxContainer Orientation="Horizontal" Margin="0 0 0 10">
<BoxContainer SetWidth="100" Name="PriceHolder" VerticalAlignment="Center"
HorizontalExpand="True" HorizontalAlignment="Right" />
</BoxContainer>
</BoxContainer>
</BoxContainer>
</PanelContainer>
<!-- Request Button -->
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
<Button Name="RequestButton" HorizontalExpand="True" Text="{Loc cp14-trading-ui-request-sell}" ToolTip="{Loc cp14-trading-ui-request-sell-tooltip}"/>
</BoxContainer>
</BoxContainer>
</Control>

View File

@@ -0,0 +1,48 @@
using Content.Client._CP14.UserInterface;
using Content.Client._CP14.Workbench;
using Content.Shared._CP14.Trading.Prototypes;
using Content.Shared._CP14.Trading.Systems;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client._CP14.Trading;
[GenerateTypedNameReferences]
public sealed partial class CP14SellingRequestControl : Control
{
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
public event Action? OnSellAttempt;
public CP14SellingRequestControl(ProtoId<CP14TradingRequestPrototype> request, bool active)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
if (!_proto.TryIndex(request, out var indexedRequest))
return;
//Requirements
ItemRequirements.RemoveAllChildren();
foreach (var requirement in indexedRequest.Requirements)
{
ItemRequirements.AddChild(new CP14WorkbenchRequirementControl(requirement));
}
//Coin reward
PriceHolder.RemoveAllChildren();
var economySystem = _entityManager.System<CP14SharedStationEconomySystem>();
var price = economySystem.GetPrice(indexedRequest);
PriceHolder.AddChild(new CP14PriceControl(price ?? 10000));
//Rep reward
Reputation.Text = ((price ?? 0) * indexedRequest.ReputationCashback).ToString("0.00");
RequestButton.OnPressed += _ => OnSellAttempt?.Invoke();
RequestButton.Disabled = !active;
}
}

View File

@@ -11,7 +11,6 @@ using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Client.Utility;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
@@ -25,19 +24,16 @@ public sealed partial class CP14TradingPlatformWindow : DefaultWindow
[Dependency] private readonly ILogManager _log = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IEntityManager _e = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPlayerManager _player = default!;
private readonly CP14ClientTradingPlatformSystem _tradingSystem;
private readonly CP14ClientStationEconomySystem _economySystem;
private readonly SharedAudioSystem _audio = default!;
private CP14TradingPlatformUiState? _cacheState;
private Entity<CP14TradingReputationComponent>? _cachedUser;
private Entity<CP14TradingPlatformComponent>? _cachedPlatform;
private IEnumerable<CP14TradingPositionPrototype> _allPositions = [];
private IEnumerable<CP14TradingFactionPrototype> _allFactions = [];
private ProtoId<CP14TradingFactionPrototype>? _selectedFaction;
private CP14TradingPositionPrototype? _selectedPosition;
@@ -68,7 +64,6 @@ public sealed partial class CP14TradingPlatformWindow : DefaultWindow
_tradingSystem = _e.System<CP14ClientTradingPlatformSystem>();
_economySystem = _e.System<CP14ClientStationEconomySystem>();
_audio = _e.System<SharedAudioSystem>();
GraphControl.OnOffsetChanged += offset =>
{
@@ -145,7 +140,6 @@ public sealed partial class CP14TradingPlatformWindow : DefaultWindow
private void CacheSkillProto()
{
_allPositions = _proto.EnumeratePrototypes<CP14TradingPositionPrototype>();
_allFactions = _proto.EnumeratePrototypes<CP14TradingFactionPrototype>().OrderBy(tree => Loc.GetString(tree.Name));
UpdateGraphControl();
}

View File

@@ -0,0 +1,32 @@
using Content.Shared._CP14.Trading;
using Content.Shared._CP14.Trading.Systems;
using Robust.Client.UserInterface;
namespace Content.Client._CP14.Trading.Selling;
public sealed class CP14SellingPlatformBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
{
private CP14SellingPlatformWindow? _window;
protected override void Open()
{
base.Open();
_window = this.CreateWindow<CP14SellingPlatformWindow>();
_window.OnSell += () => SendMessage(new CP14TradingSellAttempt());
_window.OnRequestSell += pair => SendMessage(new CP14TradingRequestSellAttempt(pair.Item1, pair.Item2));
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
switch (state)
{
case CP14SellingPlatformUiState storeState:
_window?.UpdateState(storeState);
break;
}
}
}

View File

@@ -0,0 +1,37 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
Name="Window"
Title="{Loc 'cp14-trading-ui-title'}"
MinSize="400 300"
SetSize="800 600">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
<!-- Left General sell tab -->
<BoxContainer Margin="3" MinWidth="300" Orientation="Vertical" HorizontalExpand="False" VerticalExpand="True">
<PanelContainer Margin="3" HorizontalExpand="True" VerticalExpand="True" RectClipContent="True">
<BoxContainer Margin="8" VerticalExpand="True" HorizontalExpand="True" VerticalAlignment="Bottom" Orientation="Vertical">
<BoxContainer SetWidth="100" Name="SellPriceHolder" VerticalAlignment="Center" HorizontalExpand="True" HorizontalAlignment="Center" />
<SpriteView Name="SpriteView" Scale="4 4" Access="Public"/>
<Button Name="SellButton" StyleClasses="OpenBoth" Access="Public" MaxWidth="100" SetHeight="30">
<Label Text="{Loc cp14-trading-ui-button-sell}" Margin="-5 0 0 0" HorizontalAlignment="Center"/>
</Button>
</BoxContainer>
<!-- Tree Tabs -->
<BoxContainer Margin="3" VerticalAlignment="Top" HorizontalAlignment="Right" Orientation="Vertical" VerticalExpand="True">
<BoxContainer Name="TreeTabsContainer" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Access="Public"/>
</BoxContainer>
</PanelContainer>
</BoxContainer>
<!-- Right Requests tab -->
<BoxContainer Margin="3" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
<BoxContainer HorizontalExpand="True" HorizontalAlignment="Center" Margin="0 0 0 5">
<Label Name="TreeName" Access="Public" StyleClasses="LabelHeadingBigger" VAlign="Center"
HorizontalExpand="True" HorizontalAlignment="Center"/>
</BoxContainer>
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" HScrollEnabled="False">
<BoxContainer Name="Requests" Orientation="Vertical" HorizontalExpand="True"/>
</ScrollContainer>
</BoxContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -0,0 +1,123 @@
using System.Linq;
using Content.Client._CP14.UserInterface;
using Content.Shared._CP14.Trading;
using Content.Shared._CP14.Trading.Components;
using Content.Shared._CP14.Trading.Prototypes;
using Robust.Client.AutoGenerated;
using Robust.Client.Player;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Client._CP14.Trading.Selling;
[GenerateTypedNameReferences]
public sealed partial class CP14SellingPlatformWindow : DefaultWindow
{
[Dependency] private readonly ILogManager _log = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IEntityManager _e = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPlayerManager _player = default!;
private readonly CP14ClientTradingPlatformSystem _tradingSystem;
private readonly CP14ClientStationEconomySystem _economySystem;
private Entity<CP14TradingReputationComponent>? _cachedUser;
private Entity<CP14SellingPlatformComponent>? _cachedPlatform;
private CP14TradingFactionPrototype? _selectedFaction;
public event Action<(ProtoId<CP14TradingRequestPrototype>, ProtoId<CP14TradingFactionPrototype>)>? OnRequestSell;
public event Action? OnSell;
private ISawmill Sawmill { get; init; }
public CP14SellingPlatformWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
Sawmill = _log.GetSawmill("cp14_selling");
_tradingSystem = _e.System<CP14ClientTradingPlatformSystem>();
_economySystem = _e.System<CP14ClientStationEconomySystem>();
SellButton.OnPressed += _ => OnSell?.Invoke();
}
public void UpdateState(CP14SellingPlatformUiState state)
{
if (!_e.TryGetComponent<CP14TradingReputationComponent>(_player.LocalEntity, out var repComp))
return;
_cachedUser = (_player.LocalEntity.Value, repComp);
var plat = _e.GetEntity(state.Platform);
if (!_e.TryGetComponent<CP14SellingPlatformComponent>(plat, out var platComp))
return;
_cachedPlatform = (plat, platComp);
//SpriteView
SpriteView.SetEntity(_cachedPlatform);
//SellPrice
SellPriceHolder.RemoveAllChildren();
SellPriceHolder.AddChild(new CP14PriceControl(state.Price));
SellButton.Disabled = state.Price == 0;
//Faction tabs update
TreeTabsContainer.RemoveAllChildren();
foreach (var (faction, rep) in _cachedUser.Value.Comp.Reputation)
{
if (!_proto.TryIndex(faction, out var indexedFaction))
continue;
var factionButton = new CP14TradingFactionButtonControl(
indexedFaction.Color,
Loc.GetString(indexedFaction.Name),
rep);
factionButton.OnPressed += () =>
{
SelectFaction(indexedFaction);
};
TreeTabsContainer.AddChild(factionButton);
}
if (_selectedFaction == null)
{
var firstFaction = _cachedUser.Value.Comp.Reputation.Keys.First();
if (_proto.TryIndex(firstFaction, out var indexedFaction))
SelectFaction(indexedFaction);
}
else if (_selectedFaction != null)
{
SelectFaction(_selectedFaction);
}
}
private void SelectFaction(CP14TradingFactionPrototype faction)
{
if (_cachedPlatform is null)
return;
_selectedFaction = faction;
TreeName.Text = Loc.GetString("cp14-trading-faction-request-prefix") + " " + Loc.GetString(faction.Name);
//Update requests
Requests.RemoveAllChildren();
foreach (var request in _economySystem.GetRequests(faction))
{
var canFullfill = _tradingSystem.CanFulfillRequest(_cachedPlatform.Value, request);
var requestControl = new CP14SellingRequestControl(request, canFullfill);
requestControl.OnSellAttempt += () => OnRequestSell?.Invoke((request, faction));
Requests.AddChild(requestControl);
}
}
}

View File

@@ -18,6 +18,7 @@ using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using System.Linq;
using Content.Server._CP14.Trading;
using Content.Shared.Cargo.Components;
using Content.Shared.Research.Prototypes;
namespace Content.Server.Cargo.Systems;

View File

@@ -207,9 +207,9 @@ public sealed class CP14ModularCraftSystem : CP14SharedModularCraftSystem
}
}
if (TryComp<StaticPriceComponent>(part, out var staticPartPrice))
if (TryComp<Shared.Cargo.Components.StaticPriceComponent>(part, out var staticPartPrice))
{
var startStaticPrice = EnsureComp<StaticPriceComponent>(start);
var startStaticPrice = EnsureComp<Shared.Cargo.Components.StaticPriceComponent>(start);
startStaticPrice.Price += staticPartPrice.Price;
}

View File

@@ -1,4 +1,6 @@
using System.Linq;
using Content.Server.Cargo.Systems;
using Content.Server.GameTicking;
using Content.Server.Station.Events;
using Content.Shared._CP14.Trading.BuyServices;
using Content.Shared._CP14.Trading.Components;
@@ -6,6 +8,7 @@ using Content.Shared._CP14.Trading.Prototypes;
using Content.Shared._CP14.Trading.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server._CP14.Trading;
@@ -14,6 +17,9 @@ public sealed partial class CP14StationEconomySystem : CP14SharedStationEconomyS
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly PricingSystem _price = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
public override void Initialize()
{
base.Initialize();
@@ -24,19 +30,22 @@ public sealed partial class CP14StationEconomySystem : CP14SharedStationEconomyS
private void OnPrototypesReloaded(PrototypesReloadedEventArgs ev)
{
if (!ev.WasModified<CP14TradingPositionPrototype>())
if (!ev.WasModified<CP14TradingPositionPrototype>() && !ev.WasModified<CP14TradingRequestPrototype>())
return;
var query = EntityQueryEnumerator<CP14StationEconomyComponent>();
while (query.MoveNext(out var uid, out var economyComponent))
{
UpdatePricing((uid, economyComponent));
UpdateRequestPricing((uid, economyComponent));
}
}
private void OnStationPostInit(Entity<CP14StationEconomyComponent> ent, ref StationPostInitEvent args)
{
UpdatePricing(ent);
UpdateRequestPricing(ent);
GenerateStartingRequests(ent);
}
private void UpdatePricing(Entity<CP14StationEconomyComponent> ent)
@@ -63,4 +72,125 @@ public sealed partial class CP14StationEconomySystem : CP14SharedStationEconomyS
}
Dirty(ent);
}
private void UpdateRequestPricing(Entity<CP14StationEconomyComponent> ent)
{
ent.Comp.RequestPricing.Clear();
foreach (var trade in _proto.EnumeratePrototypes<CP14TradingRequestPrototype>())
{
double price = 0;
foreach (var req in trade.Requirements)
{
price += req.GetPrice(EntityManager, _proto);
}
price += trade.AdditionalReward;
ent.Comp.RequestPricing.TryAdd(trade, (int) price);
}
Dirty(ent);
}
public bool TryRerollRequest(ProtoId<CP14TradingFactionPrototype> faction,
ProtoId<CP14TradingRequestPrototype> request)
{
var query = EntityQueryEnumerator<CP14StationEconomyComponent>();
while (query.MoveNext(out var uid, out var economy))
{
if (!economy.ActiveRequests.TryGetValue(faction, out var requests))
continue;
if (!requests.Contains(request))
continue;
requests.Add(GetNextRequest(faction, requests) ?? request);
requests.Remove(request);
Dirty(uid, economy);
return true;
}
return false;
}
private void GenerateStartingRequests(Entity<CP14StationEconomyComponent> ent)
{
ent.Comp.ActiveRequests.Clear();
var allFactions = _proto.EnumeratePrototypes<CP14TradingFactionPrototype>();
foreach (var faction in allFactions)
{
var requests = new HashSet<ProtoId<CP14TradingRequestPrototype>>();
for (int i = 0; i < ent.Comp.MaxRequestCount; i++)
{
var nextRequest = GetNextRequest(faction.ID, requests);
if (nextRequest == null)
break; // No more suitable requests
requests.Add(nextRequest);
}
ent.Comp.ActiveRequests.Add(faction, requests);
}
}
private CP14TradingRequestPrototype? GetNextRequest(ProtoId<CP14TradingFactionPrototype> faction, HashSet<ProtoId<CP14TradingRequestPrototype>> existing)
{
Dictionary<CP14TradingRequestPrototype, float> suitableRequestsWeights = new();
var allRequests = _proto.EnumeratePrototypes<CP14TradingRequestPrototype>();
foreach (var request in allRequests)
{
var passed = true;
if (existing.Contains(request))
passed = false;
if (!request.PossibleFactions.Contains(faction))
passed = false;
var stationTime = _timing.CurTime.Subtract(_gameTicker.RoundStartTimeSpan);
if (passed && TimeSpan.FromMinutes(request.FromMinutes) > stationTime)
passed = false;
if (passed && request.ToMinutes.HasValue && TimeSpan.FromMinutes(request.ToMinutes.Value) < stationTime)
passed = false;
if (passed)
suitableRequestsWeights.Add(request, request.GenerationWeight);
}
return RequestPick(suitableRequestsWeights, _random);
}
/// <summary>
/// Optimization moment: avoid re-indexing for weight selection
/// </summary>
private static CP14TradingRequestPrototype? RequestPick(Dictionary<CP14TradingRequestPrototype, float> weights, IRobustRandom random)
{
if (weights.Count == 0)
return null; // No suitable requests
var picks = weights;
var sum = picks.Values.Sum();
var accumulated = 0f;
var rand = random.NextFloat() * sum;
foreach (var (key, weight) in picks)
{
accumulated += weight;
if (accumulated >= rand)
{
return key;
}
}
// Shouldn't happen
throw new InvalidOperationException($"Invalid weighted pick in CP14StationEconomySystem!");
}
}

View File

@@ -1,19 +1,18 @@
using Content.Server._CP14.Currency;
using Content.Server._CP14.MagicEnergy;
using Content.Server.Cargo.Systems;
using Content.Server.Storage.Components;
using Content.Shared._CP14.MagicEnergy;
using Content.Shared._CP14.Trading;
using Content.Shared._CP14.Trading.Components;
using Content.Shared._CP14.Trading.Prototypes;
using Content.Shared._CP14.Trading.Systems;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.Placeable;
using Content.Shared.Popups;
using Content.Shared.Storage;
using Content.Shared.Tag;
using Content.Shared.UserInterface;
using Robust.Server.GameObjects;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.Trading;
@@ -26,59 +25,135 @@ public sealed partial class CP14TradingPlatformSystem : CP14SharedTradingPlatfor
[Dependency] private readonly CP14CurrencySystem _cp14Currency = default!;
[Dependency] private readonly CP14StationEconomySystem _economy = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly CP14MagicEnergySystem _magicEnergy = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14TradingPlatformComponent, CP14TradingPositionBuyAttempt>(OnBuyAttempt);
SubscribeLocalEvent<CP14SellingPlatformComponent, CP14MagicEnergyLevelChangeEvent>(OnMagicChange);
SubscribeLocalEvent<CP14SellingPlatformComponent, BeforeActivatableUIOpenEvent>(OnBeforeSellingUIOpen);
SubscribeLocalEvent<CP14SellingPlatformComponent, ItemPlacedEvent>(OnItemPlaced);
SubscribeLocalEvent<CP14SellingPlatformComponent, ItemRemovedEvent>(OnItemRemoved);
SubscribeLocalEvent<CP14SellingPlatformComponent, CP14TradingSellAttempt>(OnSellAttempt);
SubscribeLocalEvent<CP14SellingPlatformComponent, CP14TradingRequestSellAttempt>(OnSellRequestAttempt);
}
private void OnMagicChange(Entity<CP14SellingPlatformComponent> ent, ref CP14MagicEnergyLevelChangeEvent args)
private void OnSellAttempt(Entity<CP14SellingPlatformComponent> ent, ref CP14TradingSellAttempt args)
{
if (args.NewValue != args.MaxValue)
return;
_magicEnergy.ClearEnergy(ent.Owner);
if (!TryComp<ItemPlacerComponent>(ent, out var itemPlacer))
return;
double price = 0;
double balance = 0;
foreach (var placed in itemPlacer.PlacedEntities)
{
if (HasComp<MobStateComponent>(placed))
continue;
if (HasComp<EntityStorageComponent>(placed))
continue;
if (HasComp<StorageComponent>(placed))
if (!CanSell(placed))
continue;
var proto = MetaData(placed).EntityPrototype;
if (proto != null && !proto.ID.StartsWith("CP14")) //Shitfix, we dont wanna sell anything vanilla (like mob organs)
var price = _price.GetPrice(placed);
if (price <= 0)
continue;
var placedPrice = _price.GetPrice(placed);
if (placedPrice <= 0)
continue;
price += placedPrice;
balance += _price.GetPrice(placed);
QueueDel(placed);
}
if (balance <= 0)
return;
_audio.PlayPvs(ent.Comp.SellSound, Transform(ent).Coordinates);
_cp14Currency.GenerateMoney(price, Transform(ent).Coordinates);
_cp14Currency.GenerateMoney(balance, Transform(ent).Coordinates);
SpawnAtPosition(ent.Comp.SellVisual, Transform(ent).Coordinates);
UpdateSellingUIState(ent);
}
private void OnSellRequestAttempt(Entity<CP14SellingPlatformComponent> ent, ref CP14TradingRequestSellAttempt args)
{
if (!TryComp<ItemPlacerComponent>(ent, out var itemPlacer))
return;
if (!CanFulfillRequest(ent, args.Request))
return;
if (!Proto.TryIndex(args.Request, out var indexedRequest))
return;
if (!_economy.TryRerollRequest(args.Faction, args.Request))
return;
foreach (var req in indexedRequest.Requirements)
{
req.PostCraft(EntityManager, Proto, itemPlacer.PlacedEntities, null);
}
_audio.PlayPvs(ent.Comp.SellSound, Transform(ent).Coordinates);
var price = _economy.GetPrice(indexedRequest) ?? 0;
_cp14Currency.GenerateMoney(price, Transform(ent).Coordinates);
AddReputation(args.Actor, args.Faction, price * indexedRequest.ReputationCashback);
SpawnAtPosition(ent.Comp.SellVisual, Transform(ent).Coordinates);
UpdateSellingUIState(ent);
}
private void OnItemRemoved(Entity<CP14SellingPlatformComponent> ent, ref ItemRemovedEvent args)
{
UpdateSellingUIState(ent);
}
private void OnItemPlaced(Entity<CP14SellingPlatformComponent> ent, ref ItemPlacedEvent args)
{
UpdateSellingUIState(ent);
}
private void OnBuyAttempt(Entity<CP14TradingPlatformComponent> ent, ref CP14TradingPositionBuyAttempt args)
{
TryBuyPosition(args.Actor, ent, args.Position);
UpdateUIState(ent, args.Actor);
UpdateTradingUIState(ent, args.Actor);
}
private void OnBeforeSellingUIOpen(Entity<CP14SellingPlatformComponent> ent, ref BeforeActivatableUIOpenEvent args)
{
UpdateSellingUIState(ent);
}
private void UpdateSellingUIState(Entity<CP14SellingPlatformComponent> ent)
{
if (!TryComp<ItemPlacerComponent>(ent, out var itemPlacer))
return;
//Calculate
double balance = 0;
foreach (var placed in itemPlacer.PlacedEntities)
{
if (!CanSell(placed))
continue;
balance += _price.GetPrice(placed);
}
_userInterface.SetUiState(ent.Owner, CP14TradingUiKey.Sell, new CP14SellingPlatformUiState(GetNetEntity(ent), (int)balance));
}
public bool CanSell(EntityUid uid)
{
if (_tag.HasTag(uid, "CP14Coin")) //Boo hardcoding
return false;
if (HasComp<MobStateComponent>(uid))
return false;
if (HasComp<EntityStorageComponent>(uid))
return false;
if (HasComp<StorageComponent>(uid))
return false;
var proto = MetaData(uid).EntityPrototype;
if (proto != null && !proto.ID.StartsWith("CP14")) //Shitfix, we dont wanna sell anything vanilla (like mob organs)
return false;
return true;
}
public bool TryBuyPosition(Entity<CP14TradingReputationComponent?> user, Entity<CP14TradingPlatformComponent> platform, ProtoId<CP14TradingPositionPrototype> position)

View File

@@ -1,4 +1,4 @@
namespace Content.Server.Cargo.Components;
namespace Content.Shared.Cargo.Components;
/// <summary>
/// This is used for pricing stacks of items.

View File

@@ -1,4 +1,4 @@
namespace Content.Server.Cargo.Components;
namespace Content.Shared.Cargo.Components;
/// <summary>
/// This is used for setting a static, unchanging price for an object.

View File

@@ -5,7 +5,8 @@ namespace Content.Shared._CP14.Trading;
[Serializable, NetSerializable]
public enum CP14TradingUiKey
{
Key,
Buy,
Sell,
}
[Serializable, NetSerializable]
@@ -14,6 +15,13 @@ public sealed class CP14TradingPlatformUiState(NetEntity platform) : BoundUserIn
public NetEntity Platform = platform;
}
[Serializable, NetSerializable]
public sealed class CP14SellingPlatformUiState(NetEntity platform, int price) : BoundUserInterfaceState
{
public NetEntity Platform = platform;
public int Price = price;
}
[Serializable, NetSerializable]
public readonly struct CP14TradingProductEntry
{

View File

@@ -1,7 +1,7 @@
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.Trading;
namespace Content.Shared._CP14.Trading.Components;
/// <summary>
/// Allows you to sell items by overloading the platform with energy

View File

@@ -1,6 +1,7 @@
using Content.Shared._CP14.Trading.Prototypes;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.Trading.Components;
@@ -13,4 +14,13 @@ public sealed partial class CP14StationEconomyComponent : Component
{
[DataField, AutoNetworkedField]
public Dictionary<ProtoId<CP14TradingPositionPrototype>, int> Pricing = new();
[DataField, AutoNetworkedField]
public Dictionary<ProtoId<CP14TradingRequestPrototype>, int> RequestPricing = new();
[DataField, AutoNetworkedField]
public Dictionary<ProtoId<CP14TradingFactionPrototype>, HashSet<ProtoId<CP14TradingRequestPrototype>> > ActiveRequests = new();
[DataField]
public int MaxRequestCount = 5;
}

View File

@@ -0,0 +1,31 @@
using Content.Shared._CP14.Workbench;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Trading.Prototypes;
[Prototype("cp14TradingRequest")]
public sealed partial class CP14TradingRequestPrototype : IPrototype
{
[IdDataField] public string ID { get; private set; } = default!;
[DataField]
public HashSet<ProtoId<CP14TradingFactionPrototype>> PossibleFactions = [];
[DataField]
public float GenerationWeight = 1f;
[DataField]
public int FromMinutes = 0;
[DataField]
public int? ToMinutes;
[DataField]
public int AdditionalReward = 10;
[DataField]
public float ReputationCashback = 0.015f;
[DataField(required: true)]
public List<CP14WorkbenchCraftRequirement> Requirements = new();
}

View File

@@ -0,0 +1,138 @@
using Content.Shared.Cargo;
using Content.Shared.Cargo.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Materials;
using Content.Shared.Stacks;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Trading.Systems;
//TODO: All of this should be removed when PricingSystem in the upstream moves to Shared.
public abstract partial class CP14SharedStationEconomySystem
{
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
/// <summary>
/// Get a rough price for an entityprototype. Does not consider contained entities.
/// </summary>
public double GetEstimatedPrice(EntityPrototype prototype)
{
var ev = new EstimatedPriceCalculationEvent(prototype);
RaiseLocalEvent(ref ev);
if (ev.Handled)
return ev.Price;
var price = ev.Price;
price += GetMaterialsPrice(prototype);
price += GetSolutionsPrice(prototype);
// Can't use static price with stackprice
var oldPrice = price;
price += GetStackPrice(prototype);
if (oldPrice.Equals(price))
{
price += GetStaticPrice(prototype);
}
// TODO: Proper container support.
return price;
}
private double GetStaticPrice(EntityPrototype prototype)
{
var price = 0.0;
if (prototype.Components.TryGetValue(Factory.GetComponentName<StaticPriceComponent>(), out var staticProto))
{
var staticPrice = (StaticPriceComponent) staticProto.Component;
price += staticPrice.Price;
}
return price;
}
private double GetMaterialsPrice(EntityPrototype prototype)
{
double price = 0;
//CP14 We take materials into account when calculating the price in any case.
if ((prototype.Components.ContainsKey(Factory.GetComponentName<MaterialComponent>()) || prototype.ID.StartsWith("CP14")) &&
prototype.Components.TryGetValue(Factory.GetComponentName<PhysicalCompositionComponent>(), out var composition))
{
var compositionComp = (PhysicalCompositionComponent) composition.Component;
var matPrice = GetMaterialPrice(compositionComp);
if (prototype.Components.TryGetValue(Factory.GetComponentName<StackComponent>(), out var stackProto))
{
matPrice *= ((StackComponent) stackProto.Component).Count;
}
price += matPrice;
}
return price;
}
private double GetMaterialPrice(PhysicalCompositionComponent component)
{
double price = 0;
foreach (var (id, quantity) in component.MaterialComposition)
{
price += _prototypeManager.Index<MaterialPrototype>(id).Price * quantity;
}
return price;
}
private double GetSolutionsPrice(EntityPrototype prototype)
{
var price = 0.0;
if (prototype.Components.TryGetValue(Factory.GetComponentName<SolutionContainerManagerComponent>(), out var solManager))
{
var solComp = (SolutionContainerManagerComponent) solManager.Component;
price += GetSolutionPrice(solComp);
}
return price;
}
private double GetSolutionPrice(SolutionContainerManagerComponent component)
{
var price = 0.0;
foreach (var (_, prototype) in _solutionContainerSystem.EnumerateSolutions(component))
{
foreach (var (reagent, quantity) in prototype.Contents)
{
if (!_prototypeManager.TryIndex<ReagentPrototype>(reagent.Prototype, out var reagentProto))
continue;
// TODO check ReagentData for price information?
price += (float) quantity * reagentProto.PricePerUnit;
}
}
return price;
}
private double GetStackPrice(EntityPrototype prototype)
{
var price = 0.0;
if (prototype.Components.TryGetValue(Factory.GetComponentName<StackPriceComponent>(), out var stackpriceProto) &&
prototype.Components.TryGetValue(Factory.GetComponentName<StackComponent>(), out var stackProto) &&
!prototype.Components.ContainsKey(Factory.GetComponentName<MaterialComponent>()))
{
var stackPrice = (StackPriceComponent) stackpriceProto.Component;
var stack = (StackComponent) stackProto.Component;
price += stack.Count * stackPrice.Price;
}
return price;
}
}

View File

@@ -20,4 +20,34 @@ public abstract partial class CP14SharedStationEconomySystem : EntitySystem
return null;
}
public int? GetPrice(ProtoId<CP14TradingRequestPrototype> request)
{
var query = EntityQueryEnumerator<CP14StationEconomyComponent>();
while (query.MoveNext(out var uid, out var economy))
{
if (!economy.RequestPricing.TryGetValue(request, out var price))
return null;
return price;
}
return null;
}
public HashSet<ProtoId<CP14TradingRequestPrototype>> GetRequests(ProtoId<CP14TradingFactionPrototype> faction)
{
var query = EntityQueryEnumerator<CP14StationEconomyComponent>();
while (query.MoveNext(out var uid, out var economy))
{
if (!economy.ActiveRequests.TryGetValue(faction, out var requests))
continue;
return requests;
}
return [];
}
}

View File

@@ -8,12 +8,17 @@ public abstract partial class CP14SharedTradingPlatformSystem
{
private void InitializeUI()
{
SubscribeLocalEvent<CP14TradingPlatformComponent, BeforeActivatableUIOpenEvent>(OnBeforeUIOpen);
SubscribeLocalEvent<CP14TradingPlatformComponent, BeforeActivatableUIOpenEvent>(OnBeforeTradingUIOpen);
}
private void OnBeforeUIOpen(Entity<CP14TradingPlatformComponent> ent, ref BeforeActivatableUIOpenEvent args)
private void OnBeforeTradingUIOpen(Entity<CP14TradingPlatformComponent> ent, ref BeforeActivatableUIOpenEvent args)
{
UpdateUIState(ent, args.User);
UpdateTradingUIState(ent, args.User);
}
protected void UpdateTradingUIState(Entity<CP14TradingPlatformComponent> ent, EntityUid user)
{
_userInterface.SetUiState(ent.Owner, CP14TradingUiKey.Buy, new CP14TradingPlatformUiState(GetNetEntity(ent)));
}
public string GetTradeDescription(CP14TradingPositionPrototype position)

View File

@@ -1,6 +1,7 @@
using Content.Shared._CP14.Trading.Components;
using Content.Shared._CP14.Trading.Prototypes;
using Content.Shared.Interaction.Events;
using Content.Shared.Placeable;
using Content.Shared.Popups;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
@@ -59,14 +60,6 @@ public abstract partial class CP14SharedTradingPlatformSystem : EntitySystem
QueueDel(ent);
}
protected void UpdateUIState(Entity<CP14TradingPlatformComponent> ent, EntityUid user)
{
if (!TryComp<CP14TradingReputationComponent>(user, out var repComp))
return;
_userInterface.SetUiState(ent.Owner, CP14TradingUiKey.Key, new CP14TradingPlatformUiState(GetNetEntity(ent)));
}
public bool CanBuyPosition(Entity<CP14TradingReputationComponent?> user, ProtoId<CP14TradingPositionPrototype> position)
{
if (!Resolve(user.Owner, ref user.Comp, false))
@@ -93,6 +86,23 @@ public abstract partial class CP14SharedTradingPlatformSystem : EntitySystem
Dirty(user);
}
public bool CanFulfillRequest(EntityUid platform, ProtoId<CP14TradingRequestPrototype> request)
{
if (!TryComp<ItemPlacerComponent>(platform, out var itemPlacer))
return false;
if (!Proto.TryIndex(request, out var indexedRequest))
return false;
foreach (var requirement in indexedRequest.Requirements)
{
if (!requirement.CheckRequirement(EntityManager, Proto, itemPlacer.PlacedEntities, null))
return false;
}
return true;
}
}
[Serializable, NetSerializable]
@@ -100,3 +110,16 @@ public sealed class CP14TradingPositionBuyAttempt(ProtoId<CP14TradingPositionPro
{
public readonly ProtoId<CP14TradingPositionPrototype> Position = position;
}
[Serializable, NetSerializable]
public sealed class CP14TradingRequestSellAttempt(ProtoId<CP14TradingRequestPrototype> request, ProtoId<CP14TradingFactionPrototype> faction) : BoundUserInterfaceMessage
{
public readonly ProtoId<CP14TradingRequestPrototype> Request = request;
public readonly ProtoId<CP14TradingFactionPrototype> Faction = faction;
}
[Serializable, NetSerializable]
public sealed class CP14TradingSellAttempt : BoundUserInterfaceMessage
{
}

View File

@@ -24,7 +24,7 @@ public sealed partial class MaterialResource : CP14WorkbenchCraftRequirement
EntityManager entManager,
IPrototypeManager protoManager,
HashSet<EntityUid> placedEntities,
EntityUid user)
EntityUid? user)
{
var count = 0;
foreach (var ent in placedEntities)
@@ -56,7 +56,7 @@ public sealed partial class MaterialResource : CP14WorkbenchCraftRequirement
return true;
}
public override void PostCraft(EntityManager entManager, IPrototypeManager protoManager, HashSet<EntityUid> placedEntities, EntityUid user)
public override void PostCraft(EntityManager entManager, IPrototypeManager protoManager, HashSet<EntityUid> placedEntities, EntityUid? user)
{
var stackSystem = entManager.System<SharedStackSystem>();
@@ -99,6 +99,17 @@ public sealed partial class MaterialResource : CP14WorkbenchCraftRequirement
}
}
public override double GetPrice(EntityManager entManager,
IPrototypeManager protoManager)
{
if (protoManager.TryIndex(Material, out var indexedMaterial))
{
return indexedMaterial.Price * Count;
}
return 0;
}
public override string GetRequirementTitle(IPrototypeManager protoManager)
{
if (!protoManager.TryIndex(Material, out var indexedMaterial))

View File

@@ -3,7 +3,7 @@
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
*/
using Content.Shared._CP14.Workbench.Prototypes;
using Content.Shared._CP14.Trading.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
@@ -22,14 +22,14 @@ public sealed partial class ProtoIdResource : CP14WorkbenchCraftRequirement
public override bool CheckRequirement(EntityManager entManager,
IPrototypeManager protoManager,
HashSet<EntityUid> placedEntities,
EntityUid user)
EntityUid? user)
{
var indexedIngredients = IndexIngredients(entManager, placedEntities);
return indexedIngredients.TryGetValue(ProtoId, out var availableQuantity) && availableQuantity >= Count;
}
public override void PostCraft(EntityManager entManager,IPrototypeManager protoManager, HashSet<EntityUid> placedEntities, EntityUid user)
public override void PostCraft(EntityManager entManager,IPrototypeManager protoManager, HashSet<EntityUid> placedEntities, EntityUid? user)
{
var requiredCount = Count;
@@ -50,6 +50,17 @@ public sealed partial class ProtoIdResource : CP14WorkbenchCraftRequirement
}
}
public override double GetPrice(EntityManager entManager,
IPrototypeManager protoManager)
{
if (!protoManager.TryIndex(ProtoId, out var indexedProto))
return 0;
var priceSys = entManager.System<CP14SharedStationEconomySystem>();
return priceSys.GetEstimatedPrice(indexedProto) * Count;
}
public override string GetRequirementTitle(IPrototypeManager protoManager)
{
if (!protoManager.TryIndex(ProtoId, out var indexedProto))

View File

@@ -16,14 +16,17 @@ public sealed partial class SkillRequired : CP14WorkbenchCraftRequirement
public override bool CheckRequirement(EntityManager entManager,
IPrototypeManager protoManager,
HashSet<EntityUid> placedEntities,
EntityUid user)
EntityUid? user)
{
if (user is null)
return false;
var knowledgeSystem = entManager.System<CP14SharedSkillSystem>();
var haveAllSkills = true;
foreach (var skill in Skills)
{
if (!knowledgeSystem.HaveSkill(user, skill))
if (!knowledgeSystem.HaveSkill(user.Value, skill))
{
haveAllSkills = false;
break;
@@ -33,7 +36,13 @@ public sealed partial class SkillRequired : CP14WorkbenchCraftRequirement
return haveAllSkills;
}
public override void PostCraft(EntityManager entManager, IPrototypeManager protoManager, HashSet<EntityUid> placedEntities, EntityUid user)
public override double GetPrice(EntityManager entManager,
IPrototypeManager protoManager)
{
return 0;
}
public override void PostCraft(EntityManager entManager, IPrototypeManager protoManager, HashSet<EntityUid> placedEntities, EntityUid? user)
{
}

View File

@@ -23,7 +23,7 @@ public sealed partial class StackGroupResource : CP14WorkbenchCraftRequirement
public override bool CheckRequirement(EntityManager entManager,
IPrototypeManager protoManager,
HashSet<EntityUid> placedEntities,
EntityUid user)
EntityUid? user)
{
if (!protoManager.TryIndex(Group, out var indexedGroup))
return false;
@@ -48,7 +48,7 @@ public sealed partial class StackGroupResource : CP14WorkbenchCraftRequirement
public override void PostCraft(EntityManager entManager, IPrototypeManager protoManager,
HashSet<EntityUid> placedEntities,
EntityUid user)
EntityUid? user)
{
var stackSystem = entManager.System<SharedStackSystem>();
@@ -75,6 +75,13 @@ public sealed partial class StackGroupResource : CP14WorkbenchCraftRequirement
}
}
public override double GetPrice(EntityManager entManager,
IPrototypeManager protoManager)
{
//Idk how to price this, so we just return 0.
return 0;
}
public override string GetRequirementTitle(IPrototypeManager protoManager)
{
var indexedGroup = protoManager.Index(Group);

View File

@@ -3,6 +3,7 @@
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
*/
using Content.Shared._CP14.Trading.Systems;
using Content.Shared._CP14.Workbench.Prototypes;
using Content.Shared.Stacks;
using Robust.Shared.Prototypes;
@@ -23,7 +24,7 @@ public sealed partial class StackResource : CP14WorkbenchCraftRequirement
public override bool CheckRequirement(EntityManager entManager,
IPrototypeManager protoManager,
HashSet<EntityUid> placedEntities,
EntityUid user)
EntityUid? user)
{
var count = 0;
foreach (var ent in placedEntities)
@@ -45,7 +46,7 @@ public sealed partial class StackResource : CP14WorkbenchCraftRequirement
public override void PostCraft(EntityManager entManager, IPrototypeManager protoManager,
HashSet<EntityUid> placedEntities,
EntityUid user)
EntityUid? user)
{
var stackSystem = entManager.System<SharedStackSystem>();
@@ -69,6 +70,20 @@ public sealed partial class StackResource : CP14WorkbenchCraftRequirement
}
}
public override double GetPrice(EntityManager entManager,
IPrototypeManager protoManager)
{
if (!protoManager.TryIndex(Stack, out var indexedStack))
return 0;
if (!protoManager.TryIndex(indexedStack.Spawn, out var indexedProto))
return 0;
var priceSys = entManager.System<CP14SharedStationEconomySystem>();
return priceSys.GetEstimatedPrice(indexedProto) * Count;
}
public override string GetRequirementTitle(IPrototypeManager protoManager)
{
if (!protoManager.TryIndex(Stack, out var indexedStack))

View File

@@ -30,7 +30,7 @@ public sealed partial class TagResource : CP14WorkbenchCraftRequirement
EntityManager entManager,
IPrototypeManager protoManager,
HashSet<EntityUid> placedEntities,
EntityUid user)
EntityUid? user)
{
var tagSystem = entManager.System<TagSystem>();
@@ -49,7 +49,7 @@ public sealed partial class TagResource : CP14WorkbenchCraftRequirement
return true;
}
public override void PostCraft(EntityManager entManager, IPrototypeManager protoManager, HashSet<EntityUid> placedEntities, EntityUid user)
public override void PostCraft(EntityManager entManager, IPrototypeManager protoManager, HashSet<EntityUid> placedEntities, EntityUid? user)
{
var tagSystem = entManager.System<TagSystem>();
@@ -66,6 +66,12 @@ public sealed partial class TagResource : CP14WorkbenchCraftRequirement
entManager.DeleteEntity(placedEntity);
}
}
public override double GetPrice(EntityManager entManager,
IPrototypeManager protoManager)
{
//Idk how to price tags, so just return 0 for now.
return 0;
}
public override string GetRequirementTitle(IPrototypeManager protoManager)
{

View File

@@ -26,7 +26,7 @@ public abstract partial class CP14WorkbenchCraftRequirement
public abstract bool CheckRequirement(EntityManager entManager,
IPrototypeManager protoManager,
HashSet<EntityUid> placedEntities,
EntityUid user);
EntityUid? user);
/// <summary>
/// An event that is triggered after crafting. This is the place to put important things like removing items, spending stacks or other things.
@@ -34,7 +34,10 @@ public abstract partial class CP14WorkbenchCraftRequirement
public abstract void PostCraft(EntityManager entManager,
IPrototypeManager protoManager,
HashSet<EntityUid> placedEntities,
EntityUid user);
EntityUid? user);
public abstract double GetPrice(EntityManager entManager,
IPrototypeManager protoManager);
/// <summary>
/// This text will be displayed in the description of the craft recipe. Write something like Wooden planks: х10 here

View File

@@ -14,6 +14,7 @@ cp14-lock-shape-blacksmith1 = forge №1
cp14-lock-shape-blacksmith2 = forge №2
cp14-lock-shape-blacksmith3 = forge №3
cp14-lock-shape-merchant-public = public shop
cp14-lock-shape-merchant1 = shop №1
cp14-lock-shape-merchant2 = shop №2
cp14-lock-shape-merchant3 = shop №3

View File

@@ -1,10 +1,16 @@
cp14-trading-ui-button-sell = Sell
cp14-trading-ui-button-sell-tooltip = All items located on the trading platform will be sent to the Empire, and you will receive money equal to the value of the items.
cp14-trading-ui-button-buy = Buy
cp14-trading-ui-button-buy-tooltip = You spend the funds on the trading platform and buy the specified equipment or service from the selected vendor, which also increases your reputation. The equipment will be instantly delivered to you by spatial magic, and the service will be rendered as soon as possible.
cp14-trading-ui-request-sell = Execute request
cp14-trading-ui-request-sell-tooltip = You sell the items requested in the request, receiving money and bonus reputation with the faction in return.
cp14-trading-ui-title = Empire Trade link Platform
cp14-trading-ui-cooldown = Cooldown:
cp14-trading-faction-prefix = Trading with:
cp14-trading-faction-request-prefix = Requests from:
cp14-trading-failure-popup-money = Not enough funds on the platform!

View File

@@ -14,6 +14,7 @@ cp14-lock-shape-blacksmith1 = кузня №1
cp14-lock-shape-blacksmith2 = кузня №2
cp14-lock-shape-blacksmith3 = кузня №3
cp14-lock-shape-merchant-public = публичный магазин
cp14-lock-shape-merchant1 = магазин №1
cp14-lock-shape-merchant2 = магазин №2
cp14-lock-shape-merchant3 = магазин №3

View File

@@ -1,10 +1,16 @@
cp14-trading-ui-button-buy = Купить
cp14-trading-ui-button-buy-tooltip = Вы тратите средства, расположенные на торговой платформе и закупаете указанное снаряжение или услугу у выбранного продавца, что так же увеличивает вашу репутацию. Снаряжение будет мгновенно доставлено вам путем пространственной магии, а услуга оказана в ближайшее время.
cp14-trading-ui-button-sell = Продать
cp14-trading-ui-button-sell-tooltip = Все предметы, расположенные на торговой платформе будут отправлены в Империю, и вы получите деньги в размере стоимости предметов.
cp14-trading-ui-button-buy = Купить
cp14-trading-ui-button-buy-tooltip = Вы тратите средства, расположенные на торговой платформе и закупаете указанное снаряжение или услугу у выбранного продавца, что так же увеличивает вашу репутацию. Снаряжение будет мгновенно доставлено вам путем пространственной магии, а услуга оказана в ближайшее время.
cp14-trading-ui-request-sell = Выполнить запрос
cp14-trading-ui-request-sell-tooltip = Вы продаете требуемые в запросе предметы, получая за это деньги и бонусную репутацию с фракцией.
cp14-trading-ui-title = Платформа торговой связи с империей
cp14-trading-ui-cooldown = Перезарядка:
cp14-trading-faction-prefix = Торговля с:
cp14-trading-faction-request-prefix = Запросы от:
cp14-trading-failure-popup-money = Недостаточно средств на платформе!

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,14 @@
- type: CP14AbstractKey
group: Merchant
- type: entity
parent: CP14KeyCopperBlank
id: CP14KeyMercantShopPublic
suffix: Merchant public shop
components:
- type: CP14Key
autoGenerateShape: ShopPublic
- type: entity
parent: CP14KeyIronBlank
id: CP14KeyMercantShop1

View File

@@ -95,6 +95,7 @@
components:
- type: StorageFill
contents:
- id: CP14KeyMercantShopPublic
- id: CP14KeyTavernMerchantShopAbstract
- type: entity

View File

@@ -1,5 +1,23 @@
# Wooden
- type: entity
parent: CP14WoodenDoor
id: CP14WoodenDoorMerchantShopPublic
suffix: Merchant public shop
components:
- type: CP14Lock
autoGenerateShape: ShopPublic
- type: Lock
locked: false #Public shops opened by roundstart
- type: entity
parent:
- CP14WoodenDoorMerchantShopPublic
- CP14WoodenDoorMirrored
id: CP14WoodenDoorMerchantShopPublicMirrored
suffix: Merchant public shop, Mirrored
- type: entity
parent: CP14WoodenDoor
id: CP14WoodenDoorMerchantShop1
@@ -17,6 +35,7 @@
id: CP14WoodenDoorMerchantShopMirrored1
suffix: Merchant shop 1, Mirrored
- type: entity
parent: CP14WoodenDoor
id: CP14WoodenDoorMerchantShop2
@@ -34,6 +53,7 @@
id: CP14WoodenDoorMerchantShopMirrored2
suffix: Merchant shop 2, Mirrored
- type: entity
parent: CP14WoodenDoor
id: CP14WoodenDoorMerchantShop3

View File

@@ -16,13 +16,13 @@
sprite: _CP14/Structures/Specific/Economy/buy_platform.rsi
state: base
- type: ActivatableUI
key: enum.CP14TradingUiKey.Key
key: enum.CP14TradingUiKey.Buy
- type: Clickable
- type: InteractionOutline
- type: CP14TradingPlatform
- type: UserInterface
interfaces:
enum.CP14TradingUiKey.Key:
enum.CP14TradingUiKey.Buy:
type: CP14TradingPlatformBoundUserInterface
- type: PlaceableSurface
- type: ItemPlacer
@@ -71,6 +71,12 @@
- type: PlaceableSurface
- type: ItemPlacer
maxEntities: 0
- type: ActivatableUI
key: enum.CP14TradingUiKey.Sell
- type: UserInterface
interfaces:
enum.CP14TradingUiKey.Sell:
type: CP14SellingPlatformBoundUserInterface
- type: Fixtures
fixtures:
fix1:
@@ -84,14 +90,6 @@
- MidImpassable
- LowImpassable
hard: false
- type: CP14MagicEnergyContainer
maxEnergy: 30
energy: 0
unsafeSupport: true
- type: CP14MagicEnergyDraw
energy: -1
delay: 3 # 5m to full restore
- type: CP14MagicEnergyExaminable
- type: entity
id: CP14CashImpact

View File

@@ -78,6 +78,11 @@
complexity: 5
name: cp14-lock-shape-blacksmith3
- type: CP14LockType
id: ShopPublic
complexity: 3
name: cp14-lock-shape-merchant-public
- type: CP14LockType
id: Shop1
group: Merchant

View File

@@ -1,16 +1,6 @@
# Rep 0
- type: cp14TradingPosition
id: CP14OreCopper5
faction: DwarfMining
uiPosition: 0
icon:
sprite: _CP14/Objects/Materials/copper_ore.rsi
state: ore2
service: !type:CP14BuyItemsService
product: CP14OreCopper5
- type: cp14TradingPosition
id: CP14CopperBar5
faction: DwarfMining
@@ -32,16 +22,6 @@
service: !type:CP14BuyItemsService
product: CP14GlassSheet5
- type: cp14TradingPosition
id: CP14Torch
faction: DwarfMining
uiPosition: 7
icon:
sprite: _CP14/Objects/Tools/torch.rsi
state: torch-unlit
service: !type:CP14BuyItemsService
product: CP14Torch
- type: cp14TradingPosition
id: CP14ModularIronPickaxe
faction: DwarfMining
@@ -76,17 +56,6 @@
# Rep 1
- type: cp14TradingPosition
id: CP14OreIron5
faction: DwarfMining
reputationLevel: 1
uiPosition: 0
icon:
sprite: _CP14/Objects/Materials/iron_ore.rsi
state: ore2
service: !type:CP14BuyItemsService
product: CP14OreIron5
- type: cp14TradingPosition
id: CP14IronBar5
faction: DwarfMining
@@ -101,28 +70,6 @@
# Rep 2
- type: cp14TradingPosition
id: CP14OreGold5
faction: DwarfMining
reputationLevel: 2
uiPosition: 0
icon:
sprite: _CP14/Objects/Materials/gold_ore.rsi
state: ore2
service: !type:CP14BuyItemsService
product: CP14OreGold5
#- type: cp14TradingPosition
# id: CP14OreMithril5
# faction: DwarfMining
# reputationLevel: 2
# uiPosition: 1
# icon:
# sprite: _CP14/Objects/Materials/mithril_ore.rsi
# state: ore2
# service: !type:CP14BuyItemsService
# product: CP14OreMithril5
- type: cp14TradingPosition
id: CP14GoldBar5
faction: DwarfMining
@@ -135,18 +82,6 @@
service: !type:CP14BuyItemsService
product: CP14GoldBar5
#- type: cp14TradingPosition
# id: CP14MithrilBar5
# faction: DwarfMining
# reputationLevel: 2
# priceMarkup: 5
# uiPosition: 5
# icon:
# sprite: _CP14/Objects/Materials/mithril_bar.rsi
# state: bar_2
# service: !type:CP14BuyItemsService
# product: CP14MithrilBar5
- type: cp14TradingPosition
id: CP14BaseSharpeningStoneStructure
faction: DwarfMining

View File

@@ -0,0 +1,89 @@
- type: cp14TradingRequest
id: BradPotionsWildSage
possibleFactions:
- BradPotions
requirements:
- !type:ProtoIdResource
protoId: CP14WildSage
count: 5
- type: cp14TradingRequest
id: BradPotionsAirLily
possibleFactions:
- BradPotions
requirements:
- !type:ProtoIdResource
protoId: CP14AirLily
count: 5
- type: cp14TradingRequest
id: BradPotionsChromiumSlime
possibleFactions:
- BradPotions
requirements:
- !type:ProtoIdResource
protoId: CP14ChromiumSlime
count: 5
- type: cp14TradingRequest
id: BradPotionsAgaricMushroom
possibleFactions:
- BradPotions
requirements:
- !type:ProtoIdResource
protoId: CP14AgaricMushroom
count: 5
- type: cp14TradingRequest
id: BradPotionsDayflin
possibleFactions:
- BradPotions
requirements:
- !type:ProtoIdResource
protoId: CP14Dayflin
count: 5
- type: cp14TradingRequest
id: BradPotionsBloodFlower
possibleFactions:
- BradPotions
requirements:
- !type:ProtoIdResource
protoId: CP14BloodFlower
count: 5
- type: cp14TradingRequest
id: BradPotionsSilverNeedle
possibleFactions:
- BradPotions
requirements:
- !type:ProtoIdResource
protoId: CP14SilverNeedle
count: 5
- type: cp14TradingRequest
id: BradPotionsLumiMushroom
possibleFactions:
- BradPotions
requirements:
- !type:ProtoIdResource
protoId: CP14LumiMushroom
count: 5
- type: cp14TradingRequest
id: BradPotionsBlueAmanita
possibleFactions:
- BradPotions
requirements:
- !type:ProtoIdResource
protoId: CP14BlueAmanita
count: 5
- type: cp14TradingRequest
id: BradPotionsQuartz
possibleFactions:
- BradPotions
requirements:
- !type:ProtoIdResource
protoId: CP14CrystalShardQuartz
count: 5

View File

@@ -0,0 +1,68 @@
- type: cp14TradingRequest
id: DwarfMiningCopper
possibleFactions:
- DwarfMining
requirements:
- !type:StackResource
stack: CP14OreCopper
count: 10
- type: cp14TradingRequest
id: DwarfMiningIron
possibleFactions:
- DwarfMining
requirements:
- !type:StackResource
stack: CP14OreIron
count: 10
- type: cp14TradingRequest
id: DwarfMiningDirt
possibleFactions:
- DwarfMining
requirements:
- !type:StackResource
stack: CP14Dirt
count: 50
- type: cp14TradingRequest
id: DwarfMiningStone
possibleFactions:
- DwarfMining
requirements:
- !type:StackResource
stack: CP14Stone
count: 50
- type: cp14TradingRequest
id: DwarfMiningTorch
possibleFactions:
- DwarfMining
requirements:
- !type:ProtoIdResource
protoId: CP14Torch
count: 10
# 30 minutes
- type: cp14TradingRequest
id: DwarfMiningGold
possibleFactions:
- DwarfMining
fromMinutes: 30
requirements:
- !type:StackResource
stack: CP14OreGold
count: 10
# 60 minutes
- type: cp14TradingRequest
id: DwarfMiningMithril
possibleFactions:
- DwarfMining
fromMinutes: 60
requirements:
- !type:StackResource
stack: CP14OreMithril
count: 10

View File

@@ -0,0 +1,8 @@
- type: cp14TradingRequest
id: ThaumaturgyDimensit
possibleFactions:
- Thaumaturgy
requirements:
- !type:ProtoIdResource
protoId: CP14DimensitCrystal
count: 5

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 B

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 B

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 B

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 B

After

Width:  |  Height:  |  Size: 177 B