Another Merchant gameplay attempt (#1308)

* setup UI

* setup debug data

* graph control setup

* reputation trade component

* unlocking logic

* smoe real reputation costing

* remove sponsors part, add trading specific UI nodes

* port to default pricing system

* buy cooldown

* fuck off trading cabinets

* real good cooldown UI

* Cool unlock sound

* reputation earning

* cool purchare sound

* coin & sprite work

* delete old guidebooks

* cool purcharing VFX

* better ui

* victoria gardens

* Update migration.yml

* Update migration.yml

* cooldown removed

* contracts

* Update migration.yml

* remove CP14Material

* materials appraise

* food appraise

* auto economy pricing system

* alchemy reagents appraise

* coins resprite

* alchemy appraise 2

* modular weapon appraise

* selling platform

* Update PricingSystem.cs

* Update CP14TradingPlatformSystem.cs

* merchants returns + map update

* Update CP14StationEconomySystem.Price.cs
This commit is contained in:
Red
2025-05-29 00:22:47 +03:00
committed by GitHub
parent 0551caf98f
commit cde388f5dd
250 changed files with 3715 additions and 4830 deletions

View File

@@ -0,0 +1,7 @@
using Content.Shared._CP14.Trading.Systems;
namespace Content.Client._CP14.Trading;
public sealed partial class CP14ClientStationEconomySystem : CP14SharedStationEconomySystem
{
}

View File

@@ -0,0 +1,7 @@
using Content.Shared._CP14.Trading.Systems;
namespace Content.Client._CP14.Trading;
public sealed partial class CP14ClientTradingPlatformSystem : CP14SharedTradingPlatformSystem
{
}

View File

@@ -0,0 +1,20 @@
<Control xmlns="https://spacestation14.io" HorizontalExpand="True">
<BoxContainer Name="MainContainer"
Orientation="Horizontal"
HorizontalExpand="True">
<Button Name="MainButton"
HorizontalExpand="True"
VerticalExpand="True"
StyleClasses="OpenRight"
Margin="0 0 -1 0">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" HorizontalAlignment="Right">
<TextureRect VerticalAlignment="Center" Visible="True" HorizontalAlignment="Center" Margin="0 0 8 0" TextureScale="2, 2" TexturePath="/Textures/_CP14/Interface/Misc/star.png"/>
<Label Name="SkillTreeLabel" Margin="-5 0 0 0"/>
</BoxContainer>
</Button>
<PanelContainer Name="ColorPanel"
VerticalExpand="True"
SetWidth="7"
Margin="0 1 0 0" />
</BoxContainer>
</Control>

View File

@@ -0,0 +1,23 @@
using Content.Shared.FixedPoint;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client._CP14.Trading;
[GenerateTypedNameReferences]
public sealed partial class CP14TradingFactionButtonControl : Control
{
public event Action? OnPressed;
public CP14TradingFactionButtonControl(Color color, string label, FixedPoint2 reputation)
{
RobustXamlLoader.Load(this);
ColorPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = color };
SkillTreeLabel.Text = $"{reputation} {label}";
MainButton.OnPressed += args => OnPressed?.Invoke();
}
}

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;
public sealed class CP14TradingPlatformBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
{
private CP14TradingPlatformWindow? _window;
protected override void Open()
{
base.Open();
_window = this.CreateWindow<CP14TradingPlatformWindow>();
_window.OnUnlock += pos => SendMessage(new CP14TradingPositionUnlockAttempt(pos));
_window.OnBuy += pos => SendMessage(new CP14TradingPositionBuyAttempt(pos));
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
switch (state)
{
case CP14TradingPlatformUiState storeState:
_window?.UpdateState(storeState);
break;
}
}
}

View File

@@ -0,0 +1,96 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
xmlns:parallax="clr-namespace:Content.Client.Parallax"
xmlns:nodeTree="clr-namespace:Content.Client._CP14.UserInterface.Systems.NodeTree"
Name="Window"
Title="{Loc 'cp14-trading-ui-title'}"
MinSize="1200 800"
SetSize="1200 800">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
<!-- Selected Location -->
<BoxContainer Margin="10 10 10 10" MaxWidth="340" SetWidth="340" Orientation="Vertical"
HorizontalExpand="False" VerticalExpand="True">
<!-- Location View -->
<PanelContainer Name="BackPanel" HorizontalAlignment="Center">
<PanelContainer.PanelOverride>
<graphics:StyleBoxTexture Modulate="#1B1B1E" PatchMarginBottom="10" PatchMarginLeft="10"
PatchMarginRight="10" PatchMarginTop="10" />
</PanelContainer.PanelOverride>
<BoxContainer HorizontalExpand="True" VerticalExpand="True">
<TextureRect Stretch="Scale" Name="LocationView" SetSize="64 64" HorizontalAlignment="Center"
VerticalAlignment="Center" MinSize="64 64"
HorizontalExpand="True" VerticalExpand="True" Access="Public" />
</BoxContainer>
</PanelContainer>
<customControls:HSeparator StyleClasses="HighDivider" Margin="0 15 0 10" />
<!-- Location Data -->
<BoxContainer Name="NodeViewContainer" Orientation="Vertical" VerticalExpand="True">
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True">
<BoxContainer Orientation="Vertical" HorizontalExpand="False" VerticalExpand="True">
<BoxContainer Name="InfoContainer" Orientation="Vertical" HorizontalExpand="True"
VerticalExpand="True">
<BoxContainer HorizontalExpand="True">
<Label Name="Name" Access="Public" StyleClasses="LabelHeadingBigger" VAlign="Center"
HorizontalExpand="True" HorizontalAlignment="Center" />
</BoxContainer>
<!-- Description -->
<BoxContainer HorizontalExpand="True">
<RichTextLabel Name="Description" HorizontalExpand="True" Access="Public" />
</BoxContainer>
</BoxContainer>
</BoxContainer>
</ScrollContainer>
<Control MinHeight="5" />
<customControls:HSeparator StyleClasses="HighDivider" Margin="0 15 0 10" />
<!-- Buttons -->
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
<BoxContainer Name="UnlockBox" Orientation="Horizontal" HorizontalExpand="True" Visible="True">
<Button Name="UnlockButton" Text="{Loc 'cp14-trading-ui-button-unlock'}"
ToolTip="{Loc 'cp14-trading-ui-button-unlock-tooltip'}" StyleClasses="OpenRight"
HorizontalExpand="True" MinHeight="35" Access="Public"/>
<BoxContainer SetWidth="100" MaxWidth="100" Orientation="Horizontal">
<TextureRect VerticalAlignment="Center" Margin="20 0 5 0" HorizontalAlignment="Left" TextureScale="2, 2" TexturePath="/Textures/_CP14/Interface/Misc/star.png"/>
<RichTextLabel Name="UnlockCost" Access="Public" Text="0"/>
</BoxContainer>
</BoxContainer>
<BoxContainer Name="BuyBox" Orientation="Horizontal" HorizontalExpand="True" Visible="True">
<Button Name="BuyButton" Text="{Loc 'cp14-trading-ui-button-buy'}"
ToolTip="{Loc 'cp14-trading-ui-button-buy-tooltip'}" StyleClasses="OpenRight"
HorizontalExpand="True" MinHeight="35" Access="Public"/>
<BoxContainer Orientation="Horizontal">
<BoxContainer SetWidth="100" Name="BuyPriceHolder" VerticalAlignment="Center" HorizontalExpand="True" HorizontalAlignment="Center" />
</BoxContainer>
</BoxContainer>
</BoxContainer>
</BoxContainer>
</BoxContainer>
<customControls:VSeparator StyleClasses="LowDivider" />
<!-- Demiplane map Tree -->
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
<BoxContainer HorizontalExpand="True">
<Label Name="TreeName" Access="Public" StyleClasses="LabelHeadingBigger" VAlign="Center"
HorizontalExpand="True" HorizontalAlignment="Center" />
</BoxContainer>
<PanelContainer Margin="10 10 10 10" HorizontalExpand="True" VerticalExpand="True" RectClipContent="True">
<parallax:ParallaxControl Name="ParallaxBackground" ScaleX="4" ScaleY="4"
ParallaxPrototype="CP14Astral" Access="Public" SpeedX="10" SpeedY="5" />
<BoxContainer Margin="10 10 10 10" Orientation="Horizontal" HorizontalExpand="True"
VerticalExpand="True">
<nodeTree:CP14NodeTreeGraphControl Name="GraphControl" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Access="Public" />
</BoxContainer>
<!-- Tree Tabs -->
<BoxContainer Margin="10 10 10 10" VerticalAlignment="Top" HorizontalAlignment="Right" Orientation="Vertical" VerticalExpand="True">
<BoxContainer Name="TreeTabsContainer" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Access="Public"/>
</BoxContainer>
</PanelContainer>
</BoxContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -0,0 +1,254 @@
using System.Linq;
using System.Numerics;
using Content.Client._CP14.UserInterface;
using Content.Client._CP14.UserInterface.Systems.NodeTree;
using Content.Shared._CP14.Trading;
using Content.Shared._CP14.Trading.Components;
using Content.Shared._CP14.Trading.Prototypes;
using Robust.Client.AutoGenerated;
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;
using Robust.Shared.Utility;
namespace Content.Client._CP14.Trading;
[GenerateTypedNameReferences]
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!;
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;
public event Action<ProtoId<CP14TradingPositionPrototype>>? OnUnlock;
public event Action<ProtoId<CP14TradingPositionPrototype>>? OnBuy;
private ISawmill Sawmill { get; init; }
public CP14TradingPlatformWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
Sawmill = _log.GetSawmill("cp14_trading");
CacheSkillProto();
_proto.PrototypesReloaded += _ => CacheSkillProto();
if (_cachedUser is not null)
{
foreach (var (f, _) in _cachedUser.Value.Comp.Reputation)
{
if (_proto.TryIndex(f, out var indexedFaction))
{
SelectFaction(indexedFaction);
break;
}
}
}
_tradingSystem = _e.System<CP14ClientTradingPlatformSystem>();
_economySystem = _e.System<CP14ClientStationEconomySystem>();
_audio = _e.System<SharedAudioSystem>();
GraphControl.OnOffsetChanged += offset =>
{
ParallaxBackground.Offset = -offset * 0.25f + new Vector2(1000, 1000); //hardcoding is bad
};
GraphControl.OnNodeSelected += SelectNode;
UnlockButton.OnPressed += UnlockPressed;
BuyButton.OnPressed += BuyPressed;
}
private void UnlockPressed(BaseButton.ButtonEventArgs obj)
{
if (_selectedPosition is null)
return;
OnUnlock?.Invoke(_selectedPosition);
if (_cachedUser is not null)
_audio.PlayGlobal(new SoundCollectionSpecifier("CP14CoinImpact"), _cachedUser.Value);
}
private void BuyPressed(BaseButton.ButtonEventArgs obj)
{
if (_selectedPosition is null)
return;
OnBuy?.Invoke(_selectedPosition.ID);
}
private void SelectNode(CP14NodeTreeElement? node)
{
if (node == null)
{
DeselectNode();
return;
}
if (_cacheState == null)
{
Sawmill.Error("Tried to select node without a cached state.");
return;
}
if (!_proto.TryIndex<CP14TradingPositionPrototype>(node.NodeKey, out var indexedPosition))
return;
SelectNode(indexedPosition);
}
private void SelectNode(CP14TradingPositionPrototype? node)
{
if (node is null || _cachedUser is null || _cachedPlatform is null)
{
DeselectNode();
return;
}
if (_cacheState == null)
{
Sawmill.Error("Tried to select node without a cached state.");
return;
}
_selectedPosition = node;
var unlocked = _cachedUser.Value.Comp.UnlockedPositions;
Name.Text = _tradingSystem.GetTradeName(_selectedPosition);
Description.Text = _tradingSystem.GetTradeDescription(_selectedPosition);
LocationView.Texture = _selectedPosition.Icon.Frame0();
UnlockButton.Disabled = !_tradingSystem.CanUnlockPosition((_cachedUser.Value.Owner, _cachedUser.Value.Comp), _selectedPosition);
BuyButton.Disabled = !unlocked.Contains(_selectedPosition);
UnlockCost.Text = _selectedPosition.UnlockReputationCost.ToString();
BuyPriceHolder.RemoveAllChildren();
BuyPriceHolder.AddChild(new CP14PriceControl(_economySystem.GetPrice(_selectedPosition) ?? 0));
}
private void DeselectNode()
{
Name.Text = string.Empty;
Description.Text = string.Empty;
LocationView.Texture = null;
UnlockButton.Disabled = true;
}
private void CacheSkillProto()
{
_allPositions = _proto.EnumeratePrototypes<CP14TradingPositionPrototype>();
_allFactions = _proto.EnumeratePrototypes<CP14TradingFactionPrototype>().OrderBy(tree => Loc.GetString(tree.Name));
}
public void UpdateState(CP14TradingPlatformUiState state)
{
_cacheState = state;
var ent = _e.GetEntity(state.User);
if (!_e.TryGetComponent<CP14TradingReputationComponent>(ent, out var repComp))
return;
_cachedUser = (ent, repComp);
var plat = _e.GetEntity(state.Platform);
if (!_e.TryGetComponent<CP14TradingPlatformComponent>(plat, out var platComp))
return;
_cachedPlatform = (plat, platComp);
UpdateGraphControl();
}
private void UpdateGraphControl()
{
if (_cachedUser is null)
return;
HashSet<CP14NodeTreeElement> nodeTreeElements = new();
var edges = new HashSet<(string, string)>();
foreach (var position in _allPositions)
{
if (position.Faction != _selectedFaction)
continue;
var unlocked = _cachedUser.Value.Comp.UnlockedPositions;
var gained = unlocked.Contains(position);
var active = _tradingSystem.CanUnlockPosition((_cachedUser.Value.Owner, _cachedUser.Value.Comp), position);
var node = new CP14NodeTreeElement(position.ID, gained, active, position.UiPosition * 66, position.Icon);
nodeTreeElements.Add(node);
if (position.Prerequisite != null)
{
edges.Add((position.Prerequisite, position.ID));
}
}
GraphControl.UpdateState(
new CP14NodeTreeUiState(
nodeTreeElements,
edges: edges,
frameIcon: new SpriteSpecifier.Rsi(
new ResPath("/Textures/_CP14/Interface/NodeTree/trading.rsi"),
"frame"),
hoveredIcon: new SpriteSpecifier.Rsi(
new ResPath("/Textures/_CP14/Interface/NodeTree/trading.rsi"),
"hovered"),
selectedIcon: new SpriteSpecifier.Rsi(
new ResPath("/Textures/_CP14/Interface/NodeTree/trading.rsi"),
"selected"),
learnedIcon: new SpriteSpecifier.Rsi(
new ResPath("/Textures/_CP14/Interface/NodeTree/trading.rsi"),
"learned"),
activeLineColor: new Color(172, 102, 190),
lineColor: new Color(83, 40, 121)
)
);
//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);
}
SelectNode(_selectedPosition);
}
private void SelectFaction(CP14TradingFactionPrototype faction)
{
_selectedFaction = faction;
TreeName.Text = Loc.GetString("cp14-trading-faction-prefix") + " " + Loc.GetString(faction.Name);
UpdateGraphControl();
}
}

View File

@@ -1,34 +0,0 @@
using Content.Shared._CP14.Cargo;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client._CP14.TravelingStoreShip;
public sealed class CP14StoreBoundUserInterface : BoundUserInterface
{
private CP14StoreWindow? _window;
public CP14StoreBoundUserInterface(EntityUid owner, [NotNull] Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_window = this.CreateWindow<CP14StoreWindow>();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
switch (state)
{
case CP14StoreUiState storeState:
_window?.UpdateUI(storeState);
break;
}
}
}

View File

@@ -1,24 +0,0 @@
<Control xmlns="https://spacestation14.io">
<Button Name="ProductButton" Access="Public">
<BoxContainer Orientation="Horizontal">
<EntityPrototypeView Name="EntityView"
MinSize="48 48"
MaxSize="48 48"
Scale="2,2"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Visible="False"/>
<TextureRect Name="View"
MinSize="48 48"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Stretch="KeepAspectCentered"
Visible="False"/>
<BoxContainer Orientation="Vertical">
<RichTextLabel Name="SpecialLabel" Text="{Loc 'cp14-store-ui-tab-special'}" VerticalAlignment="Center" Access="Public" Visible="False" />
<RichTextLabel Name="ProductName" VerticalAlignment="Center" Access="Public" />
</BoxContainer>
<BoxContainer Name="PriceHolder" VerticalAlignment="Center" HorizontalExpand="True" HorizontalAlignment="Right" />
</BoxContainer>
</Button>
</Control>

View File

@@ -1,40 +0,0 @@
using Content.Shared._CP14.Cargo;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client._CP14.TravelingStoreShip;
[GenerateTypedNameReferences]
public sealed partial class CP14StoreProductControl : Control
{
[Dependency] private readonly IEntityManager _entity = default!;
private readonly SpriteSystem _sprite;
public CP14StoreProductControl(CP14StoreUiProductEntry entry)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_sprite = _entity.System<SpriteSystem>();
PriceHolder.RemoveAllChildren();
PriceHolder.AddChild(new CP14PriceControl(entry.Price));
ProductName.Text = $"[bold]{entry.Name}[/bold]";
SpecialLabel.Visible = entry.Special;
if (entry.Icon is not null)
{
View.Visible = true;
View.Texture = _sprite.Frame0(entry.Icon);
}
else if (entry.EntityView is not null)
{
EntityView.Visible = true;
EntityView.SetPrototype(entry.EntityView);
}
}
}

View File

@@ -1,32 +0,0 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Name="Window"
Title=""
MinSize="800 600"
SetSize="800 600">
<BoxContainer Orientation="Horizontal">
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Horizontal">
<!-- Product list (left side UI) -->
<TabContainer MinWidth="400" Name="Tabs" HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
<BoxContainer Name="BuyProductsContainer" Orientation="Vertical" HorizontalExpand="True"/>
</ScrollContainer>
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
<BoxContainer Name="SellProductsContainer" Orientation="Vertical" HorizontalExpand="True"/>
</ScrollContainer>
</TabContainer>
<!-- Station trading data (right side UI) -->
<BoxContainer MinWidth="400" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="0 0 10 0">
<controls:StripeBack>
<PanelContainer>
<Label Text="{Loc 'cp14-store-ui-order'}" Align="Center" Margin="0 5 0 3"/>
</PanelContainer>
</controls:StripeBack>
<Label Name="TravelTimeLabel" Text="00:00" HorizontalAlignment="Center" HorizontalExpand="True" Margin="0 15 0 0"/>
<controls:HLine Color="#404040" Thickness="2" Margin="0 5"/>
<RichTextLabel Name="SelectedName" HorizontalExpand="True" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="5"/>
<RichTextLabel Name="SelectedDesc" HorizontalExpand="True" VerticalExpand="True" VerticalAlignment="Top" Margin="5"/>
</BoxContainer>
</BoxContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -1,60 +0,0 @@
using Content.Shared._CP14.Cargo;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
namespace Content.Client._CP14.TravelingStoreShip;
[GenerateTypedNameReferences]
public sealed partial class CP14StoreWindow : DefaultWindow
{
[Dependency] private readonly IGameTiming _timing = default!;
public CP14StoreWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
Tabs.SetTabTitle(0, Loc.GetString("cp14-store-ui-tab-buy"));
Tabs.SetTabTitle(1, Loc.GetString("cp14-store-ui-tab-sell"));
}
public void UpdateUI(CP14StoreUiState state)
{
Window.Title = Loc.GetString("cp14-store-ui-title", ("name", state.ShopName));
UpdateProducts(state);
}
private void UpdateProducts(CP14StoreUiState state)
{
BuyProductsContainer.RemoveAllChildren();
SellProductsContainer.RemoveAllChildren();
foreach (var product in state.ProductsBuy)
{
var control = new CP14StoreProductControl(product);
control.ProductButton.OnPressed += _ =>
{
SelectProduct(product);
};
BuyProductsContainer.AddChild(control);
}
foreach (var product in state.ProductsSell)
{
var control = new CP14StoreProductControl(product);
control.ProductButton.OnPressed += _ =>
{
SelectProduct(product);
};
SellProductsContainer.AddChild(control);
}
}
private void SelectProduct(CP14StoreUiProductEntry? entry)
{
SelectedName.Text = entry is null ? string.Empty : $"[bold]{entry.Value.Name}[/bold]";
SelectedDesc.Text = entry is null ? string.Empty : entry.Value.Desc;
}
}

View File

@@ -5,7 +5,7 @@ using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Utility; using Robust.Shared.Utility;
namespace Content.Client._CP14.TravelingStoreShip; namespace Content.Client._CP14.UserInterface;
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class CP14PriceControl : Control public sealed partial class CP14PriceControl : Control

View File

@@ -1,6 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using Content.Shared._CP14.Cargo.Prototype; using Content.Shared._CP14.Trading.Prototypes;
using Robust.Shared.GameObjects;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
namespace Content.IntegrationTests.Tests._CP14; namespace Content.IntegrationTests.Tests._CP14;
@@ -16,7 +15,6 @@ public sealed class CP14CargoTest
await using var pair = await PoolManager.GetServerClient(); await using var pair = await PoolManager.GetServerClient();
var server = pair.Server; var server = pair.Server;
var compFactory = server.ResolveDependency<IComponentFactory>();
var protoManager = server.ResolveDependency<IPrototypeManager>(); var protoManager = server.ResolveDependency<IPrototypeManager>();
await server.WaitAssertion(() => await server.WaitAssertion(() =>
@@ -25,10 +23,9 @@ public sealed class CP14CargoTest
{ {
HashSet<string> existedCodes = new(); HashSet<string> existedCodes = new();
foreach (var proto in protoManager.EnumeratePrototypes<CP14StoreBuyPositionPrototype>()) foreach (var proto in protoManager.EnumeratePrototypes<CP14TradingPositionPrototype>())
{ {
Assert.That(!existedCodes.Contains(proto.Code), $"Repeated purchasing code {proto.Code} of the {proto}");
existedCodes.Add(proto.Code);
} }
}); });
}); });

View File

@@ -16,6 +16,7 @@ using Robust.Shared.Map.Components;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using System.Linq; using System.Linq;
using Content.Server._CP14.Trading;
using Content.Shared.Research.Prototypes; using Content.Shared.Research.Prototypes;
namespace Content.Server.Cargo.Systems; namespace Content.Server.Cargo.Systems;
@@ -261,7 +262,9 @@ public sealed class PricingSystem : EntitySystem
{ {
double price = 0; double price = 0;
if (HasComp<MaterialComponent>(uid) && //CP14 We take materials into account when calculating the price in any case.
var proto = MetaData(uid).EntityPrototype?.ID ?? "";
if ((HasComp<MaterialComponent>(uid) || proto.StartsWith("CP14")) &&
TryComp<PhysicalCompositionComponent>(uid, out var composition)) TryComp<PhysicalCompositionComponent>(uid, out var composition))
{ {
var matPrice = GetMaterialPrice(composition); var matPrice = GetMaterialPrice(composition);
@@ -278,7 +281,8 @@ public sealed class PricingSystem : EntitySystem
{ {
double price = 0; double price = 0;
if (prototype.Components.ContainsKey(_factory.GetComponentName(typeof(MaterialComponent))) && //CP14 We take materials into account when calculating the price in any case.
if ((prototype.Components.ContainsKey(_factory.GetComponentName(typeof(MaterialComponent))) || prototype.ID.StartsWith("CP14")) &&
prototype.Components.TryGetValue(_factory.GetComponentName(typeof(PhysicalCompositionComponent)), out var composition)) prototype.Components.TryGetValue(_factory.GetComponentName(typeof(PhysicalCompositionComponent)), out var composition))
{ {
var compositionComp = (PhysicalCompositionComponent) composition.Component; var compositionComp = (PhysicalCompositionComponent) composition.Component;

View File

@@ -1,64 +0,0 @@
using Content.Shared._CP14.Cargo;
using Content.Shared._CP14.Cargo.Prototype;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server._CP14.Cargo.BuyServices;
public sealed partial class CP14RerollSpecialPositionsService : CP14StoreBuyService
{
[DataField] public int RerollBuy;
[DataField] public int RerollSell;
public override void Buy(EntityManager entManager, IPrototypeManager prototype, Entity<CP14TradingPortalComponent> portal)
{
var randomSystem = IoCManager.Resolve<IRobustRandom>();
var cargoSystem = entManager.System<CP14CargoSystem>();
if (RerollBuy > 0)
{
var removed = 0;
for (var i = 0; i < RerollBuy; i++)
{
if (portal.Comp.CurrentSpecialBuyPositions.Count == 0)
break;
removed++;
var position = randomSystem.Pick(portal.Comp.CurrentSpecialBuyPositions);
portal.Comp.CurrentSpecialBuyPositions.Remove(position.Key);
}
cargoSystem.AddRandomBuySpecialPosition(portal, removed);
}
if (RerollSell > 0)
{
var removed = 0;
for (var i = 0; i < RerollSell; i++)
{
if (portal.Comp.CurrentSpecialSellPositions.Count == 0)
break;
removed++;
var position = randomSystem.Pick(portal.Comp.CurrentSpecialSellPositions);
portal.Comp.CurrentSpecialSellPositions.Remove(position.Key);
}
cargoSystem.AddRandomSellSpecialPosition(portal, removed);
}
}
public override string GetName(IPrototypeManager protoMan)
{
return string.Empty;
}
public override EntProtoId? GetEntityView(IPrototypeManager protoManager)
{
return null;
}
public override SpriteSpecifier? GetTexture(IPrototypeManager protoManager)
{
return null;
}
}

View File

@@ -1,55 +0,0 @@
using Content.Server.Storage.Components;
using Content.Shared._CP14.Cargo;
using Content.Shared.Storage.Components;
namespace Content.Server._CP14.Cargo;
public sealed partial class CP14CargoSystem
{
private void InitializePortals()
{
SubscribeLocalEvent<CP14TradingPortalComponent, MapInitEvent>(OnTradePortalMapInit);
SubscribeLocalEvent<CP14TradingPortalComponent, StorageAfterCloseEvent>(OnTradePortalClose);
SubscribeLocalEvent<CP14TradingPortalComponent, StorageAfterOpenEvent>(OnTradePortalOpen);
}
private void UpdatePortals(float frameTime)
{
var query = EntityQueryEnumerator<CP14TradingPortalComponent, EntityStorageComponent>();
while (query.MoveNext(out var ent, out var portal, out var storage))
{
if (portal.ProcessFinishTime == TimeSpan.Zero || portal.ProcessFinishTime >= _timing.CurTime)
continue;
portal.ProcessFinishTime = TimeSpan.Zero;
SellingThings((ent, portal), storage);
TopUpBalance((ent, portal), storage);
BuyThings((ent, portal), storage);
CashOut((ent, portal), storage);
ThrowAllItems((ent, portal), storage);
}
}
private void OnTradePortalMapInit(Entity<CP14TradingPortalComponent> ent, ref MapInitEvent args)
{
AddRoundstartTradingPositions(ent);
UpdateStaticPositions(ent);
ent.Comp.CurrentSpecialBuyPositions.Clear();
ent.Comp.CurrentSpecialSellPositions.Clear();
AddRandomBuySpecialPosition(ent, ent.Comp.SpecialBuyPositionCount);
AddRandomSellSpecialPosition(ent, ent.Comp.SpecialSellPositionCount);
}
private void OnTradePortalClose(Entity<CP14TradingPortalComponent> ent, ref StorageAfterCloseEvent args)
{
ent.Comp.ProcessFinishTime = _timing.CurTime + ent.Comp.Delay;
}
private void OnTradePortalOpen(Entity<CP14TradingPortalComponent> ent, ref StorageAfterOpenEvent args)
{
ent.Comp.ProcessFinishTime = TimeSpan.Zero;
}
}

View File

@@ -1,112 +0,0 @@
using System.Text;
using Content.Shared._CP14.Cargo;
using Content.Shared.UserInterface;
namespace Content.Server._CP14.Cargo;
public sealed partial class CP14CargoSystem
{
public void InitializeUI()
{
SubscribeLocalEvent<CP14TradingInfoBoardComponent, BeforeActivatableUIOpenEvent>(OnBeforeUIOpen);
}
private void TryInitStore(Entity<CP14TradingInfoBoardComponent> ent)
{
//TODO: more accurate way to find the trading portal, without lookup
var entitiesInRange = _lookup.GetEntitiesInRange<CP14TradingPortalComponent>(Transform(ent).Coordinates, 2);
foreach (var trading in entitiesInRange)
{
ent.Comp.TradingPortal = trading;
ent.Comp.CahcedFaction = trading.Comp.Faction;
break;
}
}
private void OnBeforeUIOpen(Entity<CP14TradingInfoBoardComponent> ent, ref BeforeActivatableUIOpenEvent args)
{
//TODO: If you open a store on a mapping, and initStore() it, the entity will throw an error when you try to save the grid\map.
if (ent.Comp.TradingPortal is null)
TryInitStore(ent);
UpdateUIProducts(ent);
}
private void UpdateUIProducts(Entity<CP14TradingInfoBoardComponent> ent)
{
if (ent.Comp.TradingPortal is null)
return;
if (!TryComp<CP14TradingPortalComponent>(ent.Comp.TradingPortal.Value, out var tradePortalComp))
return;
var prodBuy = new HashSet<CP14StoreUiProductEntry>();
var prodSell = new HashSet<CP14StoreUiProductEntry>();
//Add special buy positions
foreach (var (proto, price) in tradePortalComp.CurrentSpecialBuyPositions)
{
var name = proto.NameOverride is null ? proto.Service.GetName(_proto) : Loc.GetString(proto.NameOverride);
var desc = new StringBuilder();
desc.Append("\n" + Loc.GetString("cp14-store-buy-hint", ("name", name), ("code", "[color=yellow][bold]#" + proto.Code + "[/bold][/color]")));
prodBuy.Add(new CP14StoreUiProductEntry(proto.ID, proto.IconOverride ?? proto.Service.GetTexture(_proto), proto.Service.GetEntityView(_proto), name, desc.ToString(), price, true));
}
//Add static buy positions
foreach (var (proto, price) in tradePortalComp.CurrentBuyPositions)
{
var name = proto.NameOverride is null ? proto.Service.GetName(_proto) : Loc.GetString(proto.NameOverride);
var desc = new StringBuilder();
desc.Append("\n" + Loc.GetString("cp14-store-buy-hint", ("name", name), ("code", "[color=yellow][bold]#" + proto.Code + "[/bold][/color]")));
prodBuy.Add(new CP14StoreUiProductEntry(proto.ID, proto.IconOverride ?? proto.Service.GetTexture(_proto), proto.Service.GetEntityView(_proto), name, desc.ToString(), price, false));
}
//Add special sell positions
foreach (var (proto, price) in tradePortalComp.CurrentSpecialSellPositions)
{
var name = proto.NameOverride is null ? proto.Service.GetName(_proto) : Loc.GetString(proto.NameOverride);
var desc = new StringBuilder();
desc.Append("\n" + Loc.GetString("cp14-store-sell-hint", ("name", name)));
prodSell.Add(new CP14StoreUiProductEntry(
proto.ID,
proto.Service.GetTexture(_proto),
proto.Service.GetEntityView(_proto),
name,
desc.ToString(),
price,
true));
}
//Add static sell positions
foreach (var (proto, price) in tradePortalComp.CurrentSellPositions)
{
var name = proto.NameOverride is null ? proto.Service.GetName(_proto) : Loc.GetString(proto.NameOverride);
var desc = new StringBuilder();
desc.Append("\n" + Loc.GetString("cp14-store-sell-hint", ("name", name)));
prodSell.Add(new CP14StoreUiProductEntry(
proto.ID,
proto.Service.GetTexture(_proto),
proto.Service.GetEntityView(_proto),
name,
desc.ToString(),
price,
false));
}
var shopName = ":3";
//Get shop name
if (ent.Comp.CahcedFaction is not null && _proto.TryIndex(ent.Comp.CahcedFaction.Value, out var indexedShop))
{
shopName = Loc.GetString(indexedShop.Name);
}
_userInterface.SetUiState(ent.Owner, CP14StoreUiKey.Key, new CP14StoreUiState(shopName, prodBuy, prodSell));
}
}

View File

@@ -1,317 +0,0 @@
using System.Linq;
using System.Numerics;
using Content.Server._CP14.Currency;
using Content.Server.Storage.Components;
using Content.Server.Storage.EntitySystems;
using Content.Shared._CP14.Cargo;
using Content.Shared._CP14.Cargo.Prototype;
using Content.Shared._CP14.Currency;
using Content.Shared.Paper;
using Content.Shared.Stacks;
using Content.Shared.Throwing;
using Robust.Server.GameObjects;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server._CP14.Cargo;
public sealed partial class CP14CargoSystem : CP14SharedCargoSystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly CP14CurrencySystem _currency = default!;
[Dependency] private readonly EntityStorageSystem _entityStorage = default!;
[Dependency] private readonly ThrowingSystem _throwing = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
private IEnumerable<CP14StoreBuyPositionPrototype>? _buyProto;
private IEnumerable<CP14StoreSellPositionPrototype>? _sellProto;
public override void Initialize()
{
base.Initialize();
InitializeUI();
InitializePortals();
_buyProto = _proto.EnumeratePrototypes<CP14StoreBuyPositionPrototype>();
_sellProto = _proto.EnumeratePrototypes<CP14StoreSellPositionPrototype>();
SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnProtoReload);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
UpdatePortals(frameTime);
}
private void OnProtoReload(PrototypesReloadedEventArgs ev)
{
_buyProto = _proto.EnumeratePrototypes<CP14StoreBuyPositionPrototype>();
_sellProto = _proto.EnumeratePrototypes<CP14StoreSellPositionPrototype>();
}
private void AddRoundstartTradingPositions(Entity<CP14TradingPortalComponent> portal)
{
if (_buyProto is not null)
{
foreach (var buy in _buyProto)
{
if (buy.RoundstartAvailable)
portal.Comp.AvailableBuyPosition.Add(buy);
}
}
if (_sellProto is not null)
{
foreach (var sell in _sellProto)
{
if (sell.RoundstartAvailable)
portal.Comp.AvailableSellPosition.Add(sell);
}
}
}
private void UpdateStaticPositions(Entity<CP14TradingPortalComponent> portal)
{
portal.Comp.CurrentBuyPositions.Clear();
portal.Comp.CurrentSellPositions.Clear();
//Add static positions + cash special ones
foreach (var buyPos in portal.Comp.AvailableBuyPosition)
{
if (buyPos.Special)
continue;
if (buyPos.Factions.Count > 0 && !buyPos.Factions.Contains(portal.Comp.Faction))
continue;
portal.Comp.CurrentBuyPositions.Add(buyPos, buyPos.Price);
}
foreach (var sellPos in portal.Comp.AvailableSellPosition)
{
if (sellPos.Special)
continue;
if (sellPos.Factions.Count > 0 && !sellPos.Factions.Contains(portal.Comp.Faction))
continue;
portal.Comp.CurrentSellPositions.Add(sellPos, sellPos.Price);
}
}
public void AddRandomBuySpecialPosition(Entity<CP14TradingPortalComponent> portal, int count)
{
if (_buyProto is null)
return;
var availableSpecialBuyPositions = new List<CP14StoreBuyPositionPrototype>();
foreach (var buyPos in _buyProto)
{
if (!buyPos.Special)
continue;
if (portal.Comp.CurrentSpecialBuyPositions.ContainsKey(buyPos))
continue;
if (buyPos.Factions.Count > 0 && !buyPos.Factions.Contains(portal.Comp.Faction))
continue;
availableSpecialBuyPositions.Add(buyPos);
}
_random.Shuffle(availableSpecialBuyPositions);
var added = 0;
foreach (var buyPos in availableSpecialBuyPositions)
{
if (added >= count)
break;
portal.Comp.CurrentSpecialBuyPositions.Add(buyPos, buyPos.Price);
added++;
}
}
public void AddRandomSellSpecialPosition(Entity<CP14TradingPortalComponent> portal, int count)
{
if (_sellProto is null)
return;
var availableSpecialSellPositions = new List<CP14StoreSellPositionPrototype>();
foreach (var sellPos in _sellProto)
{
if (!sellPos.Special)
continue;
if (portal.Comp.CurrentSpecialSellPositions.ContainsKey(sellPos))
continue;
if (sellPos.Factions.Count > 0 && !sellPos.Factions.Contains(portal.Comp.Faction))
continue;
availableSpecialSellPositions.Add(sellPos);
}
_random.Shuffle(availableSpecialSellPositions);
var added = 0;
foreach (var sellPos in availableSpecialSellPositions)
{
if (added >= count)
break;
portal.Comp.CurrentSpecialSellPositions.Add(sellPos, sellPos.Price);
added++;
}
}
/// <summary>
/// Sell all the items we can, and replenish the internal balance
/// </summary>
private void SellingThings(Entity<CP14TradingPortalComponent> portal, EntityStorageComponent storage)
{
var containedEntities = storage.Contents.ContainedEntities.ToHashSet();
//var ev = new BeforeSellEntities(ref portal.Comp.EntitiesInPortal);
//RaiseLocalEvent(ev);
foreach (var sellPos in portal.Comp.CurrentSellPositions)
{
//WHILE = sell all we can
while (sellPos.Key.Service.TrySell(EntityManager, containedEntities))
{
portal.Comp.Balance += sellPos.Value;
}
}
List<CP14StoreSellPositionPrototype> toRemove = new();
foreach (var sellPos in portal.Comp.CurrentSpecialSellPositions)
{
//IF = only 1 try
if (sellPos.Key.Service.TrySell(EntityManager, containedEntities))
{
portal.Comp.Balance += sellPos.Value;
toRemove.Add(sellPos.Key);
}
}
//Remove this special position from the list and add new random one
foreach (var position in toRemove)
{
portal.Comp.CurrentSpecialSellPositions.Remove(position);
AddRandomSellSpecialPosition(portal, 1);
}
}
/// <summary>
/// Take all the money from the portal, and credit it to the internal balance
/// </summary>
private void TopUpBalance(Entity<CP14TradingPortalComponent> portal, EntityStorageComponent storage)
{
//Get all currency in portal
var cash = 0;
foreach (var stored in storage.Contents.ContainedEntities)
{
if (TryComp<CP14CurrencyComponent>(stored, out var currency))
{
//fix currency calculation
var c = currency.Currency;
if (TryComp<StackComponent>(stored, out var stack))
c *= stack.Count;
cash += c;
QueueDel(stored);
}
}
portal.Comp.Balance += cash;
}
private void BuyThings(Entity<CP14TradingPortalComponent> portal, EntityStorageComponent storage)
{
//Reading all papers in portal
List<KeyValuePair<CP14StoreBuyPositionPrototype, int>> requests = new();
foreach (var stored in storage.Contents.ContainedEntities)
{
if (!TryComp<PaperComponent>(stored, out var paper))
continue;
var splittedText = paper.Content.Split("#");
foreach (var fragment in splittedText)
{
foreach (var buyPosition in portal.Comp.CurrentBuyPositions)
{
if (fragment.StartsWith(buyPosition.Key.Code))
requests.Add(buyPosition);
}
foreach (var buyPosition in portal.Comp.CurrentSpecialBuyPositions)
{
if (fragment.StartsWith(buyPosition.Key.Code))
requests.Add(buyPosition);
}
}
QueueDel(stored);
}
//Trying to spend inner money to buy requested things
foreach (var request in requests)
{
if (portal.Comp.Balance < request.Value)
continue;
portal.Comp.Balance -= request.Value;
if (!_proto.TryIndex<CP14StoreBuyPositionPrototype>(request.Key, out var indexedBuyed))
continue;
//Remove this position from the list and add new random one
if (request.Key.Special)
{
portal.Comp.CurrentSpecialBuyPositions.Remove(request.Key);
AddRandomBuySpecialPosition(portal, 1);
}
indexedBuyed.Service.Buy(EntityManager, _proto, portal);
}
}
/// <summary>
/// Transform all the accumulated balance into physical money, which we will give to the players.
/// </summary>
private void CashOut(Entity<CP14TradingPortalComponent> portal, EntityStorageComponent storage)
{
var coins = _currency.GenerateMoney(portal.Comp.Balance, Transform(portal).Coordinates);
foreach (var coin in coins)
{
_entityStorage.Insert(coin, portal, storage);
}
portal.Comp.Balance = 0;
}
/// <summary>
/// Return all items to the map
/// </summary>
private void ThrowAllItems(Entity<CP14TradingPortalComponent> portal, EntityStorageComponent storage)
{
var containedEntities = storage.Contents.ContainedEntities.ToList();
_entityStorage.OpenStorage(portal, storage);
var xform = Transform(portal);
var rotation = xform.LocalRotation;
foreach (var stored in containedEntities)
{
_transform.AttachToGridOrMap(stored);
var targetThrowPosition = xform.Coordinates.Offset(rotation.ToWorldVec() * 1);
_throwing.TryThrow(stored, targetThrowPosition.Offset(new Vector2(_random.NextFloat(-0.5f, 0.5f), _random.NextFloat(-0.5f, 0.5f))));
}
}
}

View File

@@ -2,6 +2,7 @@ using Content.Shared._CP14.Currency;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Stacks; using Content.Shared.Stacks;
using Content.Shared.Tag;
using Content.Shared.Verbs; using Content.Shared.Verbs;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Map; using Robust.Shared.Map;
@@ -12,6 +13,7 @@ namespace Content.Server._CP14.Currency;
public sealed partial class CP14CurrencySystem public sealed partial class CP14CurrencySystem
{ {
[Dependency] private readonly TagSystem _tag = default!;
private void InitializeConverter() private void InitializeConverter()
{ {
SubscribeLocalEvent<CP14CurrencyConverterComponent, GetVerbsEvent<Verb>>(OnGetVerb); SubscribeLocalEvent<CP14CurrencyConverterComponent, GetVerbsEvent<Verb>>(OnGetVerb);
@@ -115,14 +117,14 @@ public sealed partial class CP14CurrencySystem
private void OnInteractUsing(Entity<CP14CurrencyConverterComponent> ent, ref InteractUsingEvent args) private void OnInteractUsing(Entity<CP14CurrencyConverterComponent> ent, ref InteractUsingEvent args)
{ {
if (!TryComp<CP14CurrencyComponent>(args.Used, out var currency)) if (!_tag.HasTag(args.Used, ent.Comp.CoinTag))
return; return;
if (ent.Comp.Whitelist is not null && !_whitelist.IsValid(ent.Comp.Whitelist, args.Used)) if (ent.Comp.Whitelist is not null && !_whitelist.IsValid(ent.Comp.Whitelist, args.Used))
return; return;
var delta = GetTotalCurrencyRecursive(args.Used); var delta = _price.GetPrice(args.Used);
ent.Comp.Balance += delta; ent.Comp.Balance += (int)delta;
QueueDel(args.Used); QueueDel(args.Used);
_popup.PopupEntity(Loc.GetString("cp14-currency-converter-insert", ("cash", delta)), ent, args.User); _popup.PopupEntity(Loc.GetString("cp14-currency-converter-insert", ("cash", delta)), ent, args.User);
@@ -130,9 +132,9 @@ public sealed partial class CP14CurrencySystem
} }
public HashSet<EntityUid> GenerateMoney(EntProtoId currencyType, public HashSet<EntityUid> GenerateMoney(EntProtoId currencyType,
int target, double target,
EntityCoordinates coordinates, EntityCoordinates coordinates,
out int remainder) out double remainder)
{ {
remainder = target; remainder = target;
HashSet<EntityUid> spawns = new(); HashSet<EntityUid> spawns = new();
@@ -155,7 +157,7 @@ public sealed partial class CP14CurrencySystem
} }
public HashSet<EntityUid> GenerateMoney( public HashSet<EntityUid> GenerateMoney(
int target, double target,
EntityCoordinates coordinates) EntityCoordinates coordinates)
{ {
HashSet<EntityUid> coins = new(); HashSet<EntityUid> coins = new();
@@ -204,9 +206,9 @@ public sealed partial class CP14CurrencySystem
return coins; return coins;
} }
private bool ProcessEntity(EntityUid ent, ref int remainder, HashSet<EntityUid> spawns) private bool ProcessEntity(EntityUid ent, ref double remainder, HashSet<EntityUid> spawns)
{ {
var singleCurrency = GetTotalCurrencyRecursive(ent); var singleCurrency = _price.GetPrice(ent);
if (singleCurrency > remainder) if (singleCurrency > remainder)
{ {
@@ -229,15 +231,15 @@ public sealed partial class CP14CurrencySystem
private void AdjustStack(EntityUid ent, private void AdjustStack(EntityUid ent,
StackComponent stack, StackComponent stack,
StackPrototype stackProto, StackPrototype stackProto,
float singleCurrency, double singleCurrency,
ref int remainder) ref double remainder)
{ {
var singleStackCurrency = singleCurrency / stack.Count; var singleStackCurrency = singleCurrency / stack.Count;
var stackLeftSpace = stackProto.MaxCount - stack.Count; var stackLeftSpace = stackProto.MaxCount - stack.Count;
if (stackLeftSpace is not null) if (stackLeftSpace is not null)
{ {
var addedStack = MathF.Min((float)stackLeftSpace, MathF.Floor(remainder / singleStackCurrency)); var addedStack = MathF.Min((float)stackLeftSpace, MathF.Floor((float)(remainder / singleStackCurrency)));
if (addedStack > 0) if (addedStack > 0)
{ {

View File

@@ -1,13 +1,10 @@
using Content.Server.Cargo.Systems;
using Content.Server.Popups; using Content.Server.Popups;
using Content.Server.Stack; using Content.Server.Stack;
using Content.Server.Storage.Components;
using Content.Shared._CP14.Currency; using Content.Shared._CP14.Currency;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Stacks;
using Content.Shared.Storage;
using Content.Shared.Whitelist; using Content.Shared.Whitelist;
using Robust.Server.Audio; using Robust.Server.Audio;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
namespace Content.Server._CP14.Currency; namespace Content.Server._CP14.Currency;
@@ -19,6 +16,7 @@ public sealed partial class CP14CurrencySystem : CP14SharedCurrencySystem
[Dependency] private readonly StackSystem _stack = default!; [Dependency] private readonly StackSystem _stack = default!;
[Dependency] private readonly AudioSystem _audio = default!; [Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly PricingSystem _price = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -27,46 +25,13 @@ public sealed partial class CP14CurrencySystem : CP14SharedCurrencySystem
InitializeConverter(); InitializeConverter();
SubscribeLocalEvent<CP14CurrencyExaminableComponent, ExaminedEvent>(OnExamine); SubscribeLocalEvent<CP14CurrencyExaminableComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<CP14CurrencyComponent, CP14GetCurrencyEvent>(OnGetCurrency);
SubscribeLocalEvent<ContainerManagerComponent, CP14GetCurrencyEvent>(OnContainerGetCurrency);
}
private void OnGetCurrency(Entity<CP14CurrencyComponent> ent, ref CP14GetCurrencyEvent args)
{
if (args.CheckedEntities.Contains(ent))
return;
var total = ent.Comp.Currency;
if (TryComp<StackComponent>(ent, out var stack))
{
total *= stack.Count;
}
args.Currency += total;
args.CheckedEntities.Add(ent);
}
private void OnContainerGetCurrency(Entity<ContainerManagerComponent> ent, ref CP14GetCurrencyEvent args)
{
var total = 0;
foreach (var container in ent.Comp.Containers.Values)
{
foreach (var containedEnt in container.ContainedEntities)
{
total += GetTotalCurrencyRecursive(containedEnt);
}
}
args.Currency += total;
} }
private void OnExamine(Entity<CP14CurrencyExaminableComponent> currency, ref ExaminedEvent args) private void OnExamine(Entity<CP14CurrencyExaminableComponent> currency, ref ExaminedEvent args)
{ {
var total = GetTotalCurrencyRecursive(currency); var price = _price.GetPrice(currency);
var push = Loc.GetString("cp14-currency-examine-title"); var push = Loc.GetString("cp14-currency-examine-title");
push += GetCurrencyPrettyString(total); push += GetCurrencyPrettyString((int)price);
args.PushMarkup(push); args.PushMarkup(push);
} }
} }

View File

@@ -1,9 +1,11 @@
using Content.Server.Cargo.Components;
using Content.Server.Item; using Content.Server.Item;
using Content.Shared._CP14.ModularCraft; using Content.Shared._CP14.ModularCraft;
using Content.Shared._CP14.ModularCraft.Components; using Content.Shared._CP14.ModularCraft.Components;
using Content.Shared._CP14.ModularCraft.Prototypes; using Content.Shared._CP14.ModularCraft.Prototypes;
using Content.Shared.Throwing; using Content.Shared.Throwing;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Materials;
using Content.Shared.Verbs; using Content.Shared.Verbs;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
@@ -182,6 +184,36 @@ public sealed class CP14ModularCraftSystem : CP14SharedModularCraftSystem
var indexedPart = _proto.Index(partProto); var indexedPart = _proto.Index(partProto);
if (TryComp<PhysicalCompositionComponent>(part, out var partMaterial))
{
var startMaterial = EnsureComp<PhysicalCompositionComponent>(start);
//Merge materials
foreach (var (material, count) in partMaterial.MaterialComposition)
{
if (startMaterial.MaterialComposition.TryGetValue(material, out var existingCount))
startMaterial.MaterialComposition[material] = existingCount + count;
else
startMaterial.MaterialComposition[material] = count;
}
//Merge solutions
foreach (var (sol, count) in partMaterial.ChemicalComposition)
{
if (startMaterial.ChemicalComposition.TryGetValue(sol, out var existingCount))
startMaterial.ChemicalComposition[sol] = existingCount + count;
else
startMaterial.ChemicalComposition[sol] = count;
}
}
if (TryComp<StaticPriceComponent>(part, out var staticPartPrice))
{
var startStaticPrice = EnsureComp<StaticPriceComponent>(start);
startStaticPrice.Price += staticPartPrice.Price;
}
foreach (var modifier in indexedPart.Modifiers) foreach (var modifier in indexedPart.Modifiers)
{ {
modifier.Effect(EntityManager, start, part); modifier.Effect(EntityManager, start, part);

View File

@@ -1,42 +0,0 @@
using Content.Server._CP14.Objectives.Systems;
using Content.Shared.Objectives;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.Objectives.Components;
[RegisterComponent, Access(typeof(CP14TownSendConditionSystem))]
public sealed partial class CP14TownSendConditionComponent : Component
{
[DataField]
public ProtoId<StealTargetGroupPrototype> CollectGroup;
/// <summary>
/// The minimum number of items you need to steal to fulfill a objective
/// </summary>
[DataField]
public int MinCollectionSize = 1;
/// <summary>
/// The maximum number of items you need to steal to fulfill a objective
/// </summary>
[DataField]
public int MaxCollectionSize = 1;
/// <summary>
/// Target collection size after calculation
/// </summary>
[DataField]
public int CollectionSize;
/// <summary>
/// how many items have already been sent to the city
/// </summary>
[DataField]
public int CollectionSent = 0;
[DataField(required: true)]
public LocId ObjectiveText;
[DataField(required: true)]
public LocId ObjectiveDescription;
}

View File

@@ -1,4 +1,5 @@
using Content.Server._CP14.Objectives.Components; using Content.Server._CP14.Objectives.Components;
using Content.Server.Cargo.Systems;
using Content.Server.Objectives.Components; using Content.Server.Objectives.Components;
using Content.Shared._CP14.Currency; using Content.Shared._CP14.Currency;
using Content.Shared.Interaction; using Content.Shared.Interaction;
@@ -16,6 +17,7 @@ public sealed class CP14CurrencyCollectConditionSystem : EntitySystem
[Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly SharedObjectivesSystem _objectives = default!; [Dependency] private readonly SharedObjectivesSystem _objectives = default!;
[Dependency] private readonly CP14SharedCurrencySystem _currency = default!; [Dependency] private readonly CP14SharedCurrencySystem _currency = default!;
[Dependency] private readonly PricingSystem _price = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -40,15 +42,16 @@ public sealed class CP14CurrencyCollectConditionSystem : EntitySystem
private float GetProgress(MindComponent mind, CP14CurrencyCollectConditionComponent condition) private float GetProgress(MindComponent mind, CP14CurrencyCollectConditionComponent condition)
{ {
var count = 0; double count = 0;
if (mind.OwnedEntity is null) if (mind.OwnedEntity is null)
return 0; return 0;
count += _currency.GetTotalCurrencyRecursive(mind.OwnedEntity.Value); count += _price.GetPrice(mind.OwnedEntity.Value);
count -= _price.GetPrice(mind.OwnedEntity.Value, false); //We don't want to count the price of the entity itself.
var result = count / (float)condition.Currency; var result = count / (float)condition.Currency;
result = Math.Clamp(result, 0, 1); result = Math.Clamp(result, 0, 1);
return result; return (float)result;
} }
} }

View File

@@ -1,94 +0,0 @@
using Content.Server._CP14.Objectives.Components;
using Content.Shared._CP14.Cargo;
using Content.Shared.Objectives.Components;
using Content.Shared.Objectives.Systems;
using Content.Shared.Stacks;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server._CP14.Objectives.Systems;
public sealed class CP14TownSendConditionSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
private EntityQuery<StealTargetComponent> _stealQuery;
private EntityQuery<StackComponent> _stackQuery;
public override void Initialize()
{
base.Initialize();
_stealQuery = GetEntityQuery<StealTargetComponent>();
_stackQuery = GetEntityQuery<StackComponent>();
SubscribeLocalEvent<CP14TownSendConditionComponent, ObjectiveAfterAssignEvent>(OnAfterAssign);
SubscribeLocalEvent<CP14TownSendConditionComponent, ObjectiveGetProgressEvent>(OnGetProgress);
SubscribeLocalEvent<BeforeSellEntities>(OnBeforeSell);
}
private void OnBeforeSell(BeforeSellEntities ev)
{
var query = EntityQueryEnumerator<CP14TownSendConditionComponent>();
HashSet<EntityUid> removed = new();
while (query.MoveNext(out var uid, out var condition))
{
foreach (var sentEnt in ev.Sent)
{
if (condition.CollectionSent >= condition.CollectionSize)
continue;
if (!_stealQuery.TryComp(sentEnt, out var stealTarget))
continue;
if (stealTarget.StealGroup != condition.CollectGroup)
continue;
if (_stackQuery.TryComp(sentEnt, out var stack))
{
condition.CollectionSent += stack.Count;
}
else
{
condition.CollectionSent++;
}
if (!removed.Contains(sentEnt))
removed.Add(sentEnt);
}
}
foreach (var remove in removed)
{
ev.Sent.Remove(remove);
QueueDel(remove);
}
}
//Set the visual, name, icon for the objective.
private void OnAfterAssign(Entity<CP14TownSendConditionComponent> condition, ref ObjectiveAfterAssignEvent args)
{
condition.Comp.CollectionSize = _random.Next(condition.Comp.MinCollectionSize, condition.Comp.MaxCollectionSize);
var group = _proto.Index(condition.Comp.CollectGroup);
var title = Loc.GetString(condition.Comp.ObjectiveText, ("itemName", Loc.GetString(group.Name)), ("count", condition.Comp.CollectionSize));
var description = Loc.GetString(condition.Comp.ObjectiveDescription, ("itemName", Loc.GetString(group.Name)), ("count", condition.Comp.CollectionSize));
_metaData.SetEntityName(condition.Owner, title, args.Meta);
_metaData.SetEntityDescription(condition.Owner, description, args.Meta);
_objectives.SetIcon(condition.Owner, group.Sprite, args.Objective);
}
private void OnGetProgress(Entity<CP14TownSendConditionComponent> condition, ref ObjectiveGetProgressEvent args)
{
var result = (float)condition.Comp.CollectionSent / (float)condition.Comp.CollectionSize;
result = Math.Clamp(result, 0, 1);
args.Progress = result;
}
}

View File

@@ -0,0 +1,20 @@
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.Trading;
/// <summary>
/// Allows you to sell items by overloading the platform with energy
/// </summary>
[RegisterComponent]
public sealed partial class CP14SellingPlatformComponent : Component
{
[DataField]
public SoundSpecifier SellSound = new SoundPathSpecifier("/Audio/_CP14/Effects/cash.ogg")
{
Params = AudioParams.Default.WithVariation(0.1f),
};
[DataField]
public EntProtoId SellVisual = "CP14CashImpact";
}

View File

@@ -0,0 +1,30 @@
using Content.Server.Cargo.Systems;
using Content.Shared.Weapons.Melee;
namespace Content.Server._CP14.Trading;
public sealed partial class CP14StationEconomySystem
{
private void InitPriceEvents()
{
SubscribeLocalEvent<MeleeWeaponComponent, PriceCalculationEvent>(OnMeleeWeaponPriceCalculation);
}
private void OnMeleeWeaponPriceCalculation(Entity<MeleeWeaponComponent> ent, ref PriceCalculationEvent args)
{
//double price = 0;
//var dps = ent.Comp.Damage.GetTotal() * ent.Comp.AttackRate;
//if (dps <= 0)
// return;
//
//price += dps.Value;
//
//if (ent.Comp.ResetOnHandSelected == false)
// price *= 1.5; // If the weapon doesn't reset on hand selection, it's more valuable.
//
//if (ent.Comp.AltDisarm)
// price *= 1.5; // If the weapon has an alt disarm, it's more valuable.
//
//args.Price += price * 0.1f;
}
}

View File

@@ -0,0 +1,54 @@
using Content.Server.Cargo.Systems;
using Content.Server.Station.Events;
using Content.Shared._CP14.Trading.BuyServices;
using Content.Shared._CP14.Trading.Components;
using Content.Shared._CP14.Trading.Prototypes;
using Content.Shared._CP14.Trading.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server._CP14.Trading;
public sealed partial class CP14StationEconomySystem : CP14SharedStationEconomySystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly PricingSystem _price = default!;
[Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
base.Initialize();
InitPriceEvents();
SubscribeLocalEvent<CP14StationEconomyComponent, StationPostInitEvent>(OnStationPostInit);
}
private void OnStationPostInit(Entity<CP14StationEconomyComponent> ent, ref StationPostInitEvent args)
{
UpdatePricing(ent);
}
private void UpdatePricing(Entity<CP14StationEconomyComponent> ent)
{
ent.Comp.Pricing.Clear();
foreach (var trade in _proto.EnumeratePrototypes<CP14TradingPositionPrototype>())
{
double price = 0;
switch (trade.Service)
{
case CP14BuyItemsService buyItems:
if (!_proto.TryIndex(buyItems.Product, out var indexedProduct))
break;
price += _price.GetEstimatedPrice(indexedProduct) * buyItems.Count;
break;
}
price += trade.PriceMarkup;
//Random fluctuation
price *= 1 + _random.NextFloat(trade.PriceFluctuation);
ent.Comp.Pricing.TryAdd(trade, (int) price);
}
Dirty(ent);
}
}

View File

@@ -0,0 +1,125 @@
using Content.Server._CP14.Currency;
using Content.Server._CP14.MagicEnergy;
using Content.Server.Cargo.Systems;
using Content.Shared._CP14.MagicEnergy;
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.Tag;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.Trading;
public sealed partial class CP14TradingPlatformSystem : CP14SharedTradingPlatformSystem
{
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly PricingSystem _price = default!;
[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!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14TradingPlatformComponent, CP14TradingPositionBuyAttempt>(OnBuyAttempt);
SubscribeLocalEvent<CP14SellingPlatformComponent, CP14MagicEnergyOverloadEvent>(OnMagicOverload);
}
private void OnMagicOverload(Entity<CP14SellingPlatformComponent> ent, ref CP14MagicEnergyOverloadEvent args)
{
_magicEnergy.ClearEnergy(ent.Owner);
if (!TryComp<ItemPlacerComponent>(ent, out var itemPlacer))
return;
double price = 0;
foreach (var placed in itemPlacer.PlacedEntities)
{
if (HasComp<MobStateComponent>(placed))
continue;
var placedPrice = _price.GetPrice(placed);
if (placedPrice <= 0)
continue;
price += placedPrice;
QueueDel(placed);
}
_audio.PlayPvs(ent.Comp.SellSound, Transform(ent).Coordinates);
_cp14Currency.GenerateMoney(price, Transform(ent).Coordinates);
SpawnAtPosition(ent.Comp.SellVisual, Transform(ent).Coordinates);
}
private void OnBuyAttempt(Entity<CP14TradingPlatformComponent> ent, ref CP14TradingPositionBuyAttempt args)
{
TryBuyPosition(args.Actor, ent, args.Position);
UpdateUIState(ent, args.Actor);
}
public bool TryBuyPosition(Entity<CP14TradingReputationComponent?> user, Entity<CP14TradingPlatformComponent> platform, ProtoId<CP14TradingPositionPrototype> position)
{
if (!CanBuyPosition(user, platform!, position))
return false;
if (!Proto.TryIndex(position, out var indexedPosition))
return false;
if (!Resolve(user.Owner, ref user.Comp, false))
return false;
if (!TryComp<ItemPlacerComponent>(platform, out var itemPlacer))
return false;
//Top up balance
double balance = 0;
foreach (var placedEntity in itemPlacer.PlacedEntities)
{
if (!_tag.HasTag(placedEntity, platform.Comp.CoinTag))
continue;
balance += _price.GetPrice(placedEntity);
}
var price = _economy.GetPrice(position) ?? 10000;
if (balance < price)
{
// Not enough balance to buy the position
_popup.PopupEntity(Loc.GetString("cp14-trading-failure-popup-money"), platform);
return false;
}
foreach (var placedEntity in itemPlacer.PlacedEntities)
{
if (!_tag.HasTag(placedEntity, platform.Comp.CoinTag))
continue;
QueueDel(placedEntity);
}
balance -= price;
platform.Comp.NextBuyTime = Timing.CurTime + TimeSpan.FromSeconds(1f);
Dirty(platform);
if (indexedPosition.Service is not null)
indexedPosition.Service.Buy(EntityManager, Proto, platform);
user.Comp.Reputation[indexedPosition.Faction] += (float)price / 10;
Dirty(user);
_audio.PlayPvs(platform.Comp.BuySound, Transform(platform).Coordinates);
//return the change
_cp14Currency.GenerateMoney(balance, Transform(platform).Coordinates);
SpawnAtPosition(platform.Comp.BuyVisual, Transform(platform).Coordinates);
return true;
}
}

View File

@@ -22,7 +22,7 @@ public sealed partial class ArmorComponent : Component
/// to determine the monetary value of the armor /// to determine the monetary value of the armor
/// </summary> /// </summary>
[DataField] [DataField]
public float PriceMultiplier = 1; public float PriceMultiplier = 0.25f; //CP14 1 -> 0.25 (different economy)
/// <summary> /// <summary>
/// If true, you can examine the armor to see the protection. If false, the verb won't appear. /// If true, you can examine the armor to see the protection. If false, the verb won't appear.

View File

@@ -1,18 +0,0 @@
namespace Content.Shared._CP14.Cargo;
public class CP14SharedCargoSystem : EntitySystem
{
}
/// <summary>
/// is called in just before the goods are shipped into town, and before the profit on them is calculated. It allows you to edit the list of sent items.
/// </summary>
public sealed class BeforeSellEntities : EntityEventArgs
{
public HashSet<EntityUid> Sent;
public BeforeSellEntities(ref HashSet<EntityUid> sent)
{
Sent = sent;
}
}

View File

@@ -1,65 +0,0 @@
using Content.Shared._CP14.Workbench;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
namespace Content.Shared._CP14.Cargo;
[Serializable, NetSerializable]
public enum CP14StoreUiKey
{
Key,
}
[Serializable, NetSerializable]
public sealed class CP14StoreUiState : BoundUserInterfaceState
{
public readonly string ShopName;
public readonly HashSet<CP14StoreUiProductEntry> ProductsBuy;
public readonly HashSet<CP14StoreUiProductEntry> ProductsSell;
public CP14StoreUiState(string name, HashSet<CP14StoreUiProductEntry> productsBuy, HashSet<CP14StoreUiProductEntry> productsSell)
{
ShopName = name;
ProductsBuy = productsBuy;
ProductsSell = productsSell;
}
}
[Serializable, NetSerializable]
public readonly struct CP14StoreUiProductEntry : IEquatable<CP14StoreUiProductEntry>
{
public readonly string ProtoId;
public readonly SpriteSpecifier? Icon;
public readonly EntProtoId? EntityView;
public readonly string Name;
public readonly string Desc;
public readonly int Price;
public readonly bool Special;
public CP14StoreUiProductEntry(string protoId, SpriteSpecifier? icon, EntProtoId? entityView, string name, string desc, int price, bool special)
{
ProtoId = protoId;
Icon = icon;
EntityView = entityView;
Name = name;
Desc = desc;
Price = price;
Special = special;
}
public bool Equals(CP14StoreUiProductEntry other)
{
return ProtoId == other.ProtoId;
}
public override bool Equals(object? obj)
{
return obj is CP14StoreUiProductEntry other && Equals(other);
}
public override int GetHashCode()
{
return HashCode.Combine(ProtoId, Icon, Name, Desc, Price);
}
}

View File

@@ -1,17 +0,0 @@
using Content.Shared._CP14.Cargo.Prototype;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Cargo;
/// <summary>
/// Allows users to view information on faction trading opportunities
/// </summary>
[RegisterComponent]
public sealed partial class CP14TradingInfoBoardComponent : Component
{
[DataField]
public EntityUid? TradingPortal = null;
[DataField]
public ProtoId<CP14StoreFactionPrototype>? CahcedFaction;
}

View File

@@ -1,63 +0,0 @@
using Content.Shared._CP14.Cargo.Prototype;
using Content.Shared.Destructible.Thresholds;
using Robust.Shared.GameStates;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Cargo;
/// <summary>
/// Add to the station so ...
/// </summary>
[NetworkedComponent, RegisterComponent, AutoGenerateComponentPause, AutoGenerateComponentState]
public sealed partial class CP14TradingPortalComponent : Component
{
[DataField(required: true), AutoNetworkedField]
public ProtoId<CP14StoreFactionPrototype> Faction = default;
[DataField]
public EntityCoordinates? TradingPosition = null;
[DataField, AutoNetworkedField]
public TimeSpan Delay = TimeSpan.FromSeconds(3f);
[DataField, AutoNetworkedField]
[AutoPausedField]
public TimeSpan ProcessFinishTime = TimeSpan.Zero;
/// <summary>
/// Available to random selecting and pusharing
/// </summary>
[DataField]
public HashSet<CP14StoreBuyPositionPrototype> AvailableBuyPosition = new();
/// <summary>
/// Available to random selecting and pusharing
/// </summary>
[DataField]
public HashSet<CP14StoreSellPositionPrototype> AvailableSellPosition = new();
/// <summary>
/// Fixed prices and positions of the current flight
/// </summary>
[DataField]
public Dictionary<CP14StoreBuyPositionPrototype, int> CurrentBuyPositions = new(); //Proto, price
[DataField]
public Dictionary<CP14StoreBuyPositionPrototype, int> CurrentSpecialBuyPositions = new(); //Proto, price
[DataField]
public int SpecialBuyPositionCount = 2;
[DataField]
public Dictionary<CP14StoreSellPositionPrototype, int> CurrentSellPositions = new(); //Proto, price
[DataField]
public Dictionary<CP14StoreSellPositionPrototype, int> CurrentSpecialSellPositions = new(); //Proto, price
[DataField]
public int SpecialSellPositionCount = 2;
[DataField]
public int Balance = 0;
}

View File

@@ -1,81 +0,0 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Shared._CP14.Cargo.Prototype.BuyServices;
public sealed partial class CP14UnlockPositionsService : CP14StoreBuyService
{
[DataField]
public HashSet<ProtoId<CP14StoreBuyPositionPrototype>> AddBuyPositions = new();
[DataField]
public HashSet<ProtoId<CP14StoreSellPositionPrototype>> AddSellPositions = new();
[DataField]
public HashSet<ProtoId<CP14StoreBuyPositionPrototype>> RemoveBuyPositions = new();
[DataField]
public HashSet<ProtoId<CP14StoreSellPositionPrototype>> RemoveSellPositions = new();
[DataField]
public SpriteSpecifier? Icon = null;
[DataField]
public LocId Name = string.Empty;
public override void Buy(EntityManager entManager, IPrototypeManager prototype, Entity<CP14TradingPortalComponent> portal)
{
foreach (var buy in AddBuyPositions)
{
if (!prototype.TryIndex(buy, out var indexedBuy))
continue;
portal.Comp.AvailableBuyPosition.Add(indexedBuy);
}
foreach (var sell in AddSellPositions)
{
if (!prototype.TryIndex(sell, out var indexedSell))
continue;
portal.Comp.AvailableSellPosition.Add(indexedSell);
}
foreach (var rBuy in RemoveBuyPositions)
{
if (!prototype.TryIndex(rBuy, out var indexedBuy))
continue;
if (!portal.Comp.AvailableBuyPosition.Contains(indexedBuy))
continue;
portal.Comp.AvailableBuyPosition.Remove(indexedBuy);
}
foreach (var rSell in RemoveSellPositions)
{
if (!prototype.TryIndex(rSell, out var indexedSell))
continue;
if (!portal.Comp.AvailableSellPosition.Contains(indexedSell))
continue;
portal.Comp.AvailableSellPosition.Remove(indexedSell);
}
}
public override string GetName(IPrototypeManager protoMan)
{
return Loc.GetString(Name);
}
public override EntProtoId? GetEntityView(IPrototypeManager protoManager)
{
return null;
}
public override SpriteSpecifier? GetTexture(IPrototypeManager protoManager)
{
return Icon;
}
}

View File

@@ -1,64 +0,0 @@
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Shared._CP14.Cargo.Prototype;
/// <summary>
/// Stores the price and product/service pair that players can buy.
/// </summary>
[Prototype("storePositionBuy")]
public sealed partial class CP14StoreBuyPositionPrototype : IPrototype
{
[IdDataField, ViewVariables]
public string ID { get; private set; } = default!;
[DataField(required: true)]
public int Price = 100;
/// <summary>
/// a unique code that can be used to purchase items.
/// </summary>
[DataField(required: true)]
public string Code = string.Empty;
[DataField(required: true, serverOnly: true)]
public CP14StoreBuyService Service = default!;
[DataField]
public SpriteSpecifier? IconOverride;
[DataField]
public LocId? NameOverride;
[DataField]
public bool RoundstartAvailable = true;
/// <summary>
/// If true, this item will randomly appear under the Special Offer heading. With a chance to show up every time the ship arrives.
/// </summary>
[DataField]
public bool Special;
[DataField]
public HashSet<ProtoId<CP14StoreFactionPrototype>> Factions = new();
}
[ImplicitDataDefinitionForInheritors]
[MeansImplicitUse]
public abstract partial class CP14StoreBuyService
{
public abstract void Buy(EntityManager entManager, IPrototypeManager prototype, Entity<CP14TradingPortalComponent> portal);
public abstract string GetName(IPrototypeManager protoMan);
/// <summary>
/// You can specify an icon generated from an entity. It will support layering, colour changes and other layer options. Return null to disable.
/// </summary>
public abstract EntProtoId? GetEntityView(IPrototypeManager protoManager);
/// <summary>
/// You can specify the texture directly. Return null to disable.
/// </summary>
public abstract SpriteSpecifier? GetTexture(IPrototypeManager protoManager);
}

View File

@@ -1,16 +0,0 @@
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Cargo.Prototype;
[Prototype("storeFaction")]
public sealed partial class CP14StoreFactionPrototype : IPrototype
{
[IdDataField, ViewVariables]
public string ID { get; private set; } = default!;
[DataField(required: true)]
public LocId Name = string.Empty;
[DataField]
public LocId Desc = string.Empty;
}

View File

@@ -1,59 +0,0 @@
using Content.Shared.Destructible.Thresholds;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Shared._CP14.Cargo.Prototype;
/// <summary>
/// Stores the price and product/service pair that players can buy.
/// </summary>
[Prototype("storePositionSell")]
public sealed partial class CP14StoreSellPositionPrototype : IPrototype
{
[IdDataField, ViewVariables]
public string ID { get; private set; } = default!;
[DataField(required: true)]
public int Price = 100;
[DataField(required: true, serverOnly: true)]
public CP14StoreSellService Service = default!;
[DataField]
public SpriteSpecifier? IconOverride;
[DataField]
public LocId? NameOverride;
[DataField]
public bool RoundstartAvailable = true;
/// <summary>
/// If true, this item will randomly appear under the Special Offer heading. With a chance to show up every time the ship arrives.
/// </summary>
[DataField]
public bool Special;
[DataField]
public HashSet<ProtoId<CP14StoreFactionPrototype>> Factions = new();
}
[ImplicitDataDefinitionForInheritors]
[MeansImplicitUse]
public abstract partial class CP14StoreSellService
{
public abstract bool TrySell(EntityManager entManager, HashSet<EntityUid> entities);
public abstract string GetName(IPrototypeManager protoMan);
/// <summary>
/// You can specify an icon generated from an entity. It will support layering, colour changes and other layer options. Return null to disable.
/// </summary>
public abstract EntProtoId? GetEntityView(IPrototypeManager protoManager);
/// <summary>
/// You can specify the texture directly. Return null to disable.
/// </summary>
public abstract SpriteSpecifier? GetTexture(IPrototypeManager protoManager);
}

View File

@@ -1,65 +0,0 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Shared._CP14.Cargo.Prototype.SellServices;
public sealed partial class CP14SellPrototypeService : CP14StoreSellService
{
[DataField(required: true)]
public EntProtoId Proto;
[DataField]
public int Count = 1;
public override bool TrySell(EntityManager entManager, HashSet<EntityUid> entities)
{
HashSet<EntityUid> suitable = new();
var needCount = Count;
foreach (var ent in entities)
{
if (needCount <= 0)
break;
if (!entManager.TryGetComponent<MetaDataComponent>(ent, out var metaData))
continue;
if (metaData.EntityPrototype is null)
continue;
if (metaData.EntityPrototype != Proto)
continue;
suitable.Add(ent);
needCount -= 1;
}
if (needCount > 0)
return false;
foreach (var selledEnt in suitable)
{
entManager.DeleteEntity(selledEnt);
}
return true;
}
public override string GetName(IPrototypeManager protoMan)
{
if (!protoMan.TryIndex(Proto, out var proto))
return ":3";
return $"{proto.Name} x{Count}";
}
public override EntProtoId? GetEntityView(IPrototypeManager protoManager)
{
return Proto;
}
public override SpriteSpecifier? GetTexture(IPrototypeManager protoManager)
{
return null;
}
}

View File

@@ -1,74 +0,0 @@
using Content.Shared.Stacks;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Shared._CP14.Cargo.Prototype.SellServices;
public sealed partial class CP14SellStackService : CP14StoreSellService
{
[DataField(required: true)]
public ProtoId<StackPrototype> StackId;
[DataField(required: true)]
public int Count = 1;
public override bool TrySell(EntityManager entManager, HashSet<EntityUid> entities)
{
var stackSystem = entManager.System<SharedStackSystem>();
Dictionary<Entity<StackComponent>, int> suitable = new();
var needCount = Count;
foreach (var ent in entities)
{
if (needCount <= 0)
break;
if (!entManager.TryGetComponent<StackComponent>(ent, out var stack) || stack.StackTypeId != StackId.Id)
continue;
var consumed = Math.Min(needCount, stack.Count);
suitable.Add((ent,stack), consumed);
needCount -= consumed;
}
if (needCount > 0)
return false;
foreach (var selledEnt in suitable)
{
if (selledEnt.Key.Comp.Count == selledEnt.Value)
{
entities.Remove(selledEnt.Key);
entManager.DeleteEntity(selledEnt.Key);
}
else
{
stackSystem.Use(selledEnt.Key, selledEnt.Value);
}
}
return true;
}
public override string GetName(IPrototypeManager protoMan)
{
if (!protoMan.TryIndex(StackId, out var proto))
return ":3";
return $"{Loc.GetString(proto.Name)} x{Count}";
}
public override EntProtoId? GetEntityView(IPrototypeManager protoManager)
{
return null;
}
public override SpriteSpecifier? GetTexture(IPrototypeManager protoManager)
{
if (!protoManager.TryIndex(StackId, out var proto))
return null;
return proto.Icon;
}
}

View File

@@ -1,72 +0,0 @@
using Content.Shared.Stacks;
using Content.Shared.Whitelist;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Shared._CP14.Cargo.Prototype.SellServices;
public sealed partial class CP14SellWhitelistService : CP14StoreSellService
{
[DataField(required: true)]
public EntityWhitelist Whitelist = new();
[DataField(required: true)]
public int Count = 1;
[DataField(required: true)]
public LocId Name = string.Empty;
[DataField(required: true)]
public SpriteSpecifier? Sprite = null;
public override bool TrySell(EntityManager entManager, HashSet<EntityUid> entities)
{
var whitelistSystem = entManager.System<EntityWhitelistSystem>();
HashSet<EntityUid> suitable = new();
var needCount = Count;
foreach (var ent in entities)
{
if (needCount <= 0)
break;
if (!whitelistSystem.IsValid(Whitelist, ent))
continue;
var count = 1;
if (entManager.TryGetComponent<StackComponent>(ent, out var stack))
count = stack.Count;
suitable.Add(ent);
needCount -= count;
}
if (needCount > 0)
return false;
foreach (var selledEnt in suitable)
{
entities.Remove(selledEnt);
entManager.DeleteEntity(selledEnt);
}
return true;
}
public override string GetName(IPrototypeManager protoMan)
{
return $"{Loc.GetString(Name)} x{Count}";
}
public override EntProtoId? GetEntityView(IPrototypeManager protoManager)
{
return null;
}
public override SpriteSpecifier? GetTexture(IPrototypeManager protoManager)
{
return Sprite;
}
}

View File

@@ -1,12 +0,0 @@
namespace Content.Shared._CP14.Currency;
/// <summary>
/// Reflects the market value of an item, to guide players through the economy.
/// </summary>
[RegisterComponent, Access(typeof(CP14SharedCurrencySystem))]
public sealed partial class CP14CurrencyComponent : Component
{
[DataField]
public int Currency = 1;
}

View File

@@ -1,6 +1,8 @@
using System.Numerics; using System.Numerics;
using Content.Shared.Tag;
using Content.Shared.Whitelist; using Content.Shared.Whitelist;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Currency; namespace Content.Shared._CP14.Currency;
@@ -22,4 +24,7 @@ public sealed partial class CP14CurrencyConverterComponent : Component
[DataField] [DataField]
public SoundSpecifier InsertSound = new SoundCollectionSpecifier("CP14Coins"); public SoundSpecifier InsertSound = new SoundCollectionSpecifier("CP14Coins");
[DataField]
public ProtoId<TagPrototype> CoinTag = "CP14Coin";
} }

View File

@@ -36,19 +36,4 @@ public partial class CP14SharedCurrencySystem : EntitySystem
return sb.ToString(); return sb.ToString();
} }
public int GetTotalCurrencyRecursive(EntityUid uid)
{
var ev = new CP14GetCurrencyEvent();
RaiseLocalEvent(uid, ev);
return (int)(ev.Currency * ev.Multiplier);
}
}
public sealed class CP14GetCurrencyEvent(int currency = 0, int multiplier = 1) : EntityEventArgs
{
public HashSet<EntityUid> CheckedEntities = new();
public int Currency = currency;
public float Multiplier = multiplier;
} }

View File

@@ -112,6 +112,24 @@ public abstract class SharedCP14MagicEnergySystem : EntitySystem
UpdateMagicAlert((ent, ent.Comp)); UpdateMagicAlert((ent, ent.Comp));
} }
/// <summary>
/// Set energy to 0
/// </summary>
public void ClearEnergy(Entity<CP14MagicEnergyContainerComponent?> ent)
{
if (!Resolve(ent, ref ent.Comp, false))
return;
var oldEnergy = ent.Comp.Energy;
ent.Comp.Energy = 0;
if (oldEnergy != 0)
RaiseLocalEvent(ent, new CP14MagicEnergyLevelChangeEvent(oldEnergy, 0, ent.Comp.MaxEnergy));
UpdateMagicAlert((ent, ent.Comp));
}
public void TransferEnergy(Entity<CP14MagicEnergyContainerComponent?> sender, public void TransferEnergy(Entity<CP14MagicEnergyContainerComponent?> sender,
Entity<CP14MagicEnergyContainerComponent?> receiver, Entity<CP14MagicEnergyContainerComponent?> receiver,
FixedPoint2 energy, FixedPoint2 energy,

View File

@@ -1,11 +0,0 @@
using Content.Shared.Materials;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Material;
[RegisterComponent]
public sealed partial class CP14MaterialComponent : Component
{
[DataField(required: true)]
public Dictionary<ProtoId<MaterialPrototype>, int> Materials = new();
}

View File

@@ -1,39 +0,0 @@
using System.Text;
using Content.Shared.Examine;
using Content.Shared.Stacks;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Material;
public sealed partial class CP14MaterialSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14MaterialComponent, ExaminedEvent>(OnMaterialExamined);
}
private void OnMaterialExamined(Entity<CP14MaterialComponent> ent, ref ExaminedEvent args)
{
TryComp<StackComponent>(ent, out var stack);
var sb = new StringBuilder();
sb.Append($"{Loc.GetString("cp14-material-examine")}\n");
foreach (var material in ent.Comp.Materials)
{
if (!_proto.TryIndex(material.Key, out var indexedMaterial))
continue;
var count = material.Value;
if (stack is not null)
count *= stack.Count;
sb.Append($"[color={indexedMaterial.Color.ToHex()}]{Loc.GetString(indexedMaterial.Name)}[/color] ({count})\n");
}
args.PushMarkup(sb.ToString());
}
}

View File

@@ -1,9 +1,10 @@
using Content.Shared._CP14.Trading.Prototypes;
using Content.Shared.Stacks; using Content.Shared.Stacks;
using Content.Shared.Storage.EntitySystems; using Robust.Client.GameObjects;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Utility; using Robust.Shared.Utility;
namespace Content.Shared._CP14.Cargo.Prototype.BuyServices; namespace Content.Shared._CP14.Trading.BuyServices;
public sealed partial class CP14BuyItemsService : CP14StoreBuyService public sealed partial class CP14BuyItemsService : CP14StoreBuyService
{ {
@@ -15,14 +16,11 @@ public sealed partial class CP14BuyItemsService : CP14StoreBuyService
public override void Buy(EntityManager entManager, public override void Buy(EntityManager entManager,
IPrototypeManager prototype, IPrototypeManager prototype,
Entity<CP14TradingPortalComponent> portal) EntityUid platform)
{ {
var storageSystem = entManager.System<SharedEntityStorageSystem>();
for (var i = 0; i < Count; i++) for (var i = 0; i < Count; i++)
{ {
var spawned = entManager.Spawn(Product); entManager.SpawnNextToOrDrop(Product, platform);
storageSystem.Insert(spawned, portal);
} }
} }
@@ -38,13 +36,11 @@ public sealed partial class CP14BuyItemsService : CP14StoreBuyService
return Count > 0 ? $"{indexedProduct.Name} x{count}" : indexedProduct.Name; return Count > 0 ? $"{indexedProduct.Name} x{count}" : indexedProduct.Name;
} }
public override EntProtoId? GetEntityView(IPrototypeManager protoManager) public override string GetDesc(IPrototypeManager protoMan)
{ {
return Product; if (!protoMan.TryIndex(Product, out var indexedProduct))
} return string.Empty;
public override SpriteSpecifier? GetTexture(IPrototypeManager protoManager) return indexedProduct.Description;
{
return null;
} }
} }

View File

@@ -0,0 +1,21 @@
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.Trading;
[Serializable, NetSerializable]
public enum CP14TradingUiKey
{
Key,
}
[Serializable, NetSerializable]
public sealed class CP14TradingPlatformUiState(NetEntity user, NetEntity platform) : BoundUserInterfaceState
{
public NetEntity User = user;
public NetEntity Platform = platform;
}
[Serializable, NetSerializable]
public readonly struct CP14TradingProductEntry
{
}

View File

@@ -0,0 +1,16 @@
using Content.Shared._CP14.Trading.Prototypes;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Trading.Components;
/// <summary>
/// The server calculates all prices for all product items, saves them in this component at the station,
/// and synchronizes the data with the client for the entire round.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class CP14StationEconomyComponent : Component
{
[DataField, AutoNetworkedField]
public Dictionary<ProtoId<CP14TradingPositionPrototype>, int> Pricing = new();
}

View File

@@ -0,0 +1,18 @@
using Content.Shared._CP14.Trading.Prototypes;
using Content.Shared._CP14.Trading.Systems;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Trading.Components;
[RegisterComponent, Access(typeof(CP14SharedTradingPlatformSystem))]
public sealed partial class CP14TradingContractComponent : Component
{
[DataField]
public TimeSpan Delay = TimeSpan.FromSeconds(2);
[DataField]
public ProtoId<CP14TradingFactionPrototype> Faction;
[DataField]
public float StartReputation = 1f;
}

View File

@@ -0,0 +1,26 @@
using Content.Shared._CP14.Trading.Systems;
using Content.Shared.Tag;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Trading.Components;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(CP14SharedTradingPlatformSystem))]
public sealed partial class CP14TradingPlatformComponent : Component
{
[DataField, AutoNetworkedField]
public TimeSpan NextBuyTime = TimeSpan.Zero;
[DataField]
public SoundSpecifier BuySound = new SoundPathSpecifier("/Audio/_CP14/Effects/cash.ogg")
{
Params = AudioParams.Default.WithVariation(0.1f)
};
[DataField]
public ProtoId<TagPrototype> CoinTag = "CP14Coin";
[DataField]
public EntProtoId BuyVisual = "CP14CashImpact";
}

View File

@@ -0,0 +1,24 @@
using Content.Shared._CP14.Trading.Prototypes;
using Content.Shared._CP14.Trading.Systems;
using Content.Shared.FixedPoint;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Trading.Components;
/// <summary>
/// Reflects the entity's level of reputation, debts, and balance sheet in the “outside” world.
/// Used for personal progression in trading systems
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(CP14SharedTradingPlatformSystem))]
public sealed partial class CP14TradingReputationComponent : Component
{
/// <summary>
/// is both a reputation counter for each faction and an indicator of whether that faction is unlocked for that player.
/// </summary>
[DataField, AutoNetworkedField]
public Dictionary<ProtoId<CP14TradingFactionPrototype>, FixedPoint2> Reputation = new();
[DataField, AutoNetworkedField]
public HashSet<ProtoId<CP14TradingPositionPrototype>> UnlockedPositions = new();
}

View File

@@ -0,0 +1,21 @@
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Trading.Prototypes;
[Prototype("cp14TradingFaction")]
public sealed partial class CP14TradingFactionPrototype : IPrototype
{
[IdDataField] public string ID { get; private set; } = default!;
[DataField(required: true)]
public LocId Name = default!;
[DataField]
public Color Color = Color.White;
/// <summary>
/// If not null, this faction is automatically unlocked for players, and grants the specified amount of reputation to unlock the first positions.
/// </summary>
[DataField]
public float? RoundStart = null;
}

View File

@@ -0,0 +1,66 @@
using System.Numerics;
using Content.Shared.FixedPoint;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Shared._CP14.Trading.Prototypes;
[Prototype("cp14TradingPosition")]
public sealed partial class CP14TradingPositionPrototype : IPrototype
{
[IdDataField] public string ID { get; private set; } = default!;
/// <summary>
/// Service Title. If you leave null, the name will try to generate from first Service.GetName()
/// </summary>
[DataField]
public LocId? Name;
/// <summary>
/// Service Description. If you leave null, the description will try to generate from first Service.GetDescription()
/// </summary>
[DataField]
public LocId? Desc;
/// <summary>
/// Icon for UI. If you leave null, the icon will try to generate from first Service.GetTexture()
/// </summary>
[DataField(required: true)]
public SpriteSpecifier Icon = default!;
[DataField(required: true)]
public ProtoId<CP14TradingFactionPrototype> Faction;
[DataField]
public FixedPoint2 UnlockReputationCost = 1f;
[DataField(required: true)]
public Vector2 UiPosition = default!;
[DataField(required: true)]
public CP14StoreBuyService? Service = null;
[DataField]
public ProtoId<CP14TradingPositionPrototype>? Prerequisite;
[DataField]
public int PriceMarkup = 1;
/// <summary>
/// each round prices will differ within +X percent of the calculated value
/// </summary>
[DataField]
public float PriceFluctuation = 0.2f;
}
[ImplicitDataDefinitionForInheritors]
[MeansImplicitUse]
public abstract partial class CP14StoreBuyService
{
public abstract void Buy(EntityManager entManager, IPrototypeManager prototype, EntityUid platform);
public abstract string GetName(IPrototypeManager protoMan);
public abstract string GetDesc(IPrototypeManager protoMan);
}

View File

@@ -0,0 +1,23 @@
using Content.Shared._CP14.Trading.Components;
using Content.Shared._CP14.Trading.Prototypes;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Trading.Systems;
public abstract partial class CP14SharedStationEconomySystem : EntitySystem
{
public int? GetPrice(ProtoId<CP14TradingPositionPrototype> position)
{
var query = EntityQueryEnumerator<CP14StationEconomyComponent>();
while (query.MoveNext(out var uid, out var economy))
{
if (!economy.Pricing.TryGetValue(position, out var price))
return null;
return price;
}
return null;
}
}

View File

@@ -0,0 +1,47 @@
using Content.Shared._CP14.Trading.Components;
using Content.Shared._CP14.Trading.Prototypes;
using Content.Shared.UserInterface;
namespace Content.Shared._CP14.Trading.Systems;
public abstract partial class CP14SharedTradingPlatformSystem
{
private void InitializeUI()
{
SubscribeLocalEvent<CP14TradingPlatformComponent, CP14TradingPositionUnlockAttempt>(OnUnlockAttempt);
SubscribeLocalEvent<CP14TradingPlatformComponent, BeforeActivatableUIOpenEvent>(OnBeforeUIOpen);
}
private void OnUnlockAttempt(Entity<CP14TradingPlatformComponent> ent, ref CP14TradingPositionUnlockAttempt args)
{
TryUnlockPosition(args.Actor, args.Position);
UpdateUIState(ent, args.Actor);
}
private void OnBeforeUIOpen(Entity<CP14TradingPlatformComponent> ent, ref BeforeActivatableUIOpenEvent args)
{
UpdateUIState(ent, args.User);
}
public string GetTradeDescription(CP14TradingPositionPrototype position)
{
if (position.Desc != null)
return Loc.GetString(position.Desc);
if (position.Service is null)
return string.Empty;
return position.Service.GetDesc(Proto);
}
public string GetTradeName(CP14TradingPositionPrototype position)
{
if (position.Name != null)
return Loc.GetString(position.Name);
if (position.Service is null)
return string.Empty;
return position.Service.GetName(Proto);
}
}

View File

@@ -0,0 +1,126 @@
using Content.Shared._CP14.Trading.Components;
using Content.Shared._CP14.Trading.Prototypes;
using Content.Shared.Interaction.Events;
using Content.Shared.Popups;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Timing;
namespace Content.Shared._CP14.Trading.Systems;
public abstract partial class CP14SharedTradingPlatformSystem : EntitySystem
{
[Dependency] private readonly SharedUserInterfaceSystem _userInterface = default!;
[Dependency] protected readonly IPrototypeManager Proto = default!;
[Dependency] protected readonly IGameTiming Timing = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly INetManager _net = default!;
public override void Initialize()
{
base.Initialize();
InitializeUI();
SubscribeLocalEvent<CP14TradingReputationComponent, MapInitEvent>(OnReputationMapInit);
SubscribeLocalEvent<CP14TradingContractComponent, UseInHandEvent>(OnContractUse);
}
private void OnReputationMapInit(Entity<CP14TradingReputationComponent> ent, ref MapInitEvent args)
{
foreach (var faction in Proto.EnumeratePrototypes<CP14TradingFactionPrototype>())
{
if (faction.RoundStart is not null)
{
ent.Comp.Reputation[faction] = ent.Comp.Reputation.GetValueOrDefault(faction, 0f) + faction.RoundStart.Value;
}
}
Dirty(ent);
}
private void OnContractUse(Entity<CP14TradingContractComponent> ent, ref UseInHandEvent args)
{
if (!Proto.TryIndex(ent.Comp.Faction, out var indexedFaction))
return;
var repComp = EnsureComp<CP14TradingReputationComponent>(args.User);
repComp.Reputation.TryAdd(ent.Comp.Faction, ent.Comp.StartReputation);
_popup.PopupPredicted(Loc.GetString("cp14-trading-contract-use", ("name", Loc.GetString(indexedFaction.Name))), args.User, args.User);
if (_net.IsServer)
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(user), GetNetEntity(ent)));
}
public bool TryUnlockPosition(Entity<CP14TradingReputationComponent?> user, ProtoId<CP14TradingPositionPrototype> position)
{
if (!CanUnlockPosition(user, position))
return false;
if (!Proto.TryIndex(position, out var indexedPosition))
return false;
if (!Resolve(user.Owner, ref user.Comp, false))
return false;
user.Comp.Reputation[indexedPosition.Faction] -= indexedPosition.UnlockReputationCost;
user.Comp.UnlockedPositions.Add(position);
Dirty(user);
return true;
}
public bool CanUnlockPosition(Entity<CP14TradingReputationComponent?> user, ProtoId<CP14TradingPositionPrototype> position)
{
if (!Resolve(user.Owner, ref user.Comp, false))
return false;
if (!Proto.TryIndex(position, out var indexedPosition))
return false;
if (!user.Comp.Reputation.ContainsKey(indexedPosition.Faction))
return false;
if (user.Comp.UnlockedPositions.Contains(position))
return false;
if (indexedPosition.Prerequisite is not null && !user.Comp.UnlockedPositions.Contains(indexedPosition.Prerequisite.Value))
return false;
return user.Comp.Reputation.GetValueOrDefault(indexedPosition.Faction, 0f) >= indexedPosition.UnlockReputationCost;
}
public bool CanBuyPosition(Entity<CP14TradingReputationComponent?> user, Entity<CP14TradingPlatformComponent?> platform, ProtoId<CP14TradingPositionPrototype> position)
{
if (!Resolve(user.Owner, ref user.Comp, false))
return false;
if (!Resolve(platform.Owner, ref platform.Comp, false))
return false;
if (!user.Comp.UnlockedPositions.Contains(position))
return false;
if (Timing.CurTime < platform.Comp.NextBuyTime)
return false;
return true;
}
}
[Serializable, NetSerializable]
public sealed class CP14TradingPositionUnlockAttempt(ProtoId<CP14TradingPositionPrototype> position) : BoundUserInterfaceMessage
{
public readonly ProtoId<CP14TradingPositionPrototype> Position = position;
}
[Serializable, NetSerializable]
public sealed class CP14TradingPositionBuyAttempt(ProtoId<CP14TradingPositionPrototype> position) : BoundUserInterfaceMessage
{
public readonly ProtoId<CP14TradingPositionPrototype> Position = position;
}

View File

@@ -3,8 +3,6 @@
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT * https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
*/ */
using Content.Shared._CP14.Material;
using Content.Shared._CP14.Workbench.Prototypes;
using Content.Shared.Materials; using Content.Shared.Materials;
using Content.Shared.Stacks; using Content.Shared.Stacks;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
@@ -31,12 +29,12 @@ public sealed partial class MaterialResource : CP14WorkbenchCraftRequirement
var count = 0; var count = 0;
foreach (var ent in placedEntities) foreach (var ent in placedEntities)
{ {
if (!entManager.TryGetComponent<CP14MaterialComponent>(ent, out var material)) if (!entManager.TryGetComponent<PhysicalCompositionComponent>(ent, out var material))
continue; continue;
entManager.TryGetComponent<StackComponent>(ent, out var stack); entManager.TryGetComponent<StackComponent>(ent, out var stack);
foreach (var (key, value) in material.Materials) foreach (var (key, value) in material.MaterialComposition)
{ {
if (key != Material) if (key != Material)
continue; continue;
@@ -65,12 +63,12 @@ public sealed partial class MaterialResource : CP14WorkbenchCraftRequirement
var requiredCount = Count; var requiredCount = Count;
foreach (var placedEntity in placedEntities) foreach (var placedEntity in placedEntities)
{ {
if (!entManager.TryGetComponent<CP14MaterialComponent>(placedEntity, out var material)) if (!entManager.TryGetComponent<PhysicalCompositionComponent>(placedEntity, out var material))
continue; continue;
entManager.TryGetComponent<StackComponent>(placedEntity, out var stack); entManager.TryGetComponent<StackComponent>(placedEntity, out var stack);
foreach (var mat in material.Materials) foreach (var mat in material.MaterialComposition)
{ {
if (mat.Key != Material) if (mat.Key != Material)
continue; continue;

View File

@@ -82,3 +82,13 @@
license: "CC0-1.0" license: "CC0-1.0"
copyright: 'Created by Fenodyrie on Freesound.org' copyright: 'Created by Fenodyrie on Freesound.org'
source: "https://freesound.org/people/Fenodyrie/sounds/583950/" source: "https://freesound.org/people/Fenodyrie/sounds/583950/"
- files: ["coin_impact1.ogg", "coin_impact2.ogg", "coin_impact3.ogg", "coin_impact4.ogg"]
license: "CC-BY-NC-4.0"
copyright: 'Created by Timbre on Freesound.org'
source: "https://freesound.org/people/Timbre/sounds/103219/"
- files: ["cash.ogg"]
license: "CC0-1.0"
copyright: 'Created by Zott820 on Freesound.org'
source: "https://freesound.org/people/Zott820/sounds/209578/"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,2 +0,0 @@
cp14-buy-position-reroll-buy = Reroll purchase offers
cp14-buy-position-reroll-sell = Reroll sales offers

View File

@@ -1,4 +0,0 @@
cp14-tracker-header = Round statistic:
cp14-tracker-demiplane-open = Demiplanes opened
cp14-tracker-demiplane-deaths = Players died in demiplanes

View File

@@ -1,11 +0,0 @@
cp14-faction-name-helmir = Helmir's descendants
cp14-faction-desc-helmir = TODO
cp14-faction-name-sylphoria = The winds of Sylphoria
cp14-faction-desc-sylphoria = TODO
cp14-faction-name-spice-stream = Spice Stream
cp14-faction-desc-spice-stream = TODO
cp14-faction-name-brad-family = Brad's imperial family
cp14-faction-desc-brad-family = TODO

View File

@@ -1,40 +0,0 @@
cp14-store-buy-hint = To purchase "{$name}", leave your money and order in the trade box: Any paper that says {$code} on it will do.
cp14-store-buy-alchemy-unlock-t1-name = Trade Alliance: Alchemists
cp14-store-buy-alchemy-unlock-t1-desc = The Alchemists Guild of the Kingdom of Klanir is willing to include the settlement in their trade route in return for small gifts and payment.
cp14-store-buy-alchemy-vials-name = Alchemical vials
cp14-store-buy-alchemy-vials-desc = Now the shortage of potion vessels is no longer a problem! After all, for a rather modest price, you can order batches of shiny vials directly from the best artisans! Random alchemical devices as a gift.
cp14-store-buy-alchemy-bureaucracy-name = Bureaucratic reserve
cp14-store-buy-alchemy-bureaucracy-desc = Pens, ink pots and a big stack of paper. In folders of different colors, or without folders at all: because we make sure that you can choose the option that is most comfortable for you.
cp14-store-buy-alchemy-farm-seeds-name = Seeds for farming
cp14-store-buy-alchemy-farm-seeds-desc = A set of different seeds, for farming of all kinds! Don't limit yourself, buy several boxes at once, just in case the farmers eat everything and don't have any food left to process into seeds.
cp14-store-buy-alchemy-demiplan-name = 5 demiplane Keys
cp14-store-buy-alchemy-demiplan-desc = Unstable pocket dimensions in which doom or riches may await you. What could be better for your adventurers?
cp14-store-buy-wood-name = Wood stockpile
cp14-store-buy-wood-desc = Fresh wood with delivery to your settlement! Do you live in a region where trees do not grow? Or you simply do not have the working hands to go and cut them yourself? We are ready to do it for you! Or rather, for your money.
cp14-store-buy-fabric-name = Stock of textiles
cp14-store-buy-fabric-desc = A large supply of fabric and thread, to make exquisite outfits or other tools. Only today, only now, only for the last six months.
cp14-store-buy-energy-name = Energy reserve
cp14-store-buy-energy-desc = Energy crystals in both medium and small sizes, and in addition, mana manipulation gauntlets. A complete set to power your energy devices.
cp14-store-buy-cheese-name = Cheese stockpile
cp14-store-buy-cheese-desc = Cows don't like to sail on ships, but their cheese is quite fond of traveling! So pay its way to your table!
cp14-store-buy-copper-name = 10 copper bars
cp14-store-buy-copper-desc = Looking for quality copper ingots? Our copper ingots are suitable for all needs, whether it is blacksmithing or coinage. Order right now, before they are sold out by craftsmen from all over the empire.
cp14-store-buy-iron-name = 10 iron bars
cp14-store-buy-iron-desc = Durable, reliable and versatile metal for the most daring projects! Do you need armor, weapons, or fasteners? The highest grade iron ingots are at your service. This is the foundation of your success!
cp14-store-buy-gold-name = 10 gold bars
cp14-store-buy-gold-desc = For those who appreciate luxury and elegance. Bars of the purest gold for jewelry, inlay or investment in the future. Gold is always in the price, and our delivery is always on time!
cp14-store-buy-guidebook-name = Educational books
cp14-store-buy-guidebook-desc = Have you run out of specialists in key areas? No problem, with this set of training literature you can make even an infant a professional, and put him to work for the good of the Empire! (OOC: There are only books for the blacksmith so far.)

View File

@@ -1,10 +0,0 @@
# Buy
cp14-store-service-unlock-sell = Unlocks the ability to sell:
cp14-store-service-unlock-buy = Unlocks the ability to buy:
# Sell
cp14-store-service-sell-entities = Sale items:

View File

@@ -1,11 +0,0 @@
cp14-store-ui-title = Trading outpost "{$name}"
cp14-store-ui-order = More info
cp14-store-ui-next-travel-out = Before departure:
cp14-store-ui-next-travel-in = Before arrival:
cp14-store-ui-tab-buy = Buying
cp14-store-ui-tab-sell = Selling
cp14-store-ui-tab-special = [bold][color=#eba346]One-off offer![/color][/bold]
cp14-store-sell-hint = To sell {$name}, put the item you want in the trade cabinet, and close it. Our people will figure out what's what, pick up the item, and send you the money through the same sales cabinet.

View File

@@ -0,0 +1,3 @@
cp14-trade-faction-contracts = Zellasian Trade Guild
cp14-trade-faction-victoria-gardens = Victoria Gardens
cp14-trade-faction-brad-potions = Brad's marvelous potions

View File

@@ -0,0 +1,14 @@
cp14-trading-ui-button-unlock = Unlock contract
cp14-trading-ui-button-unlock-tooltip = You contract to purchase the specified equipment or service by spending your reputation. After that, you can buy that equipment or service with money in unlimited quantities.
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-title = Empire Trade link Platform
cp14-trading-ui-cooldown = Cooldown:
cp14-trading-faction-prefix = Trading with:
cp14-trading-failure-popup-money = Not enough funds on the platform!
cp14-trading-contract-use = Trade with "{$name}" unlocked!

View File

@@ -1,2 +0,0 @@
cp14-buy-position-reroll-buy = Реролл предложений покупки
cp14-buy-position-reroll-sell = Реролл предложений продажи

View File

@@ -1,4 +0,0 @@
cp14-tracker-header = Статистика раунда:
cp14-tracker-demiplane-open = Открыто демипланов
cp14-tracker-demiplane-deaths = Умерло игроков в демипланах

View File

@@ -1,11 +0,0 @@
cp14-faction-name-helmir = Хельмировы потомки
cp14-faction-desc-helmir = TODO
cp14-faction-name-sylphoria = Ветра Сильфории
cp14-faction-desc-sylphoria = TODO
cp14-faction-name-spice-stream = Поток пряностей
cp14-faction-desc-spice-stream = TODO
cp14-faction-name-brad-family = Имперская семья Брада
cp14-faction-desc-brad-family = TODO

View File

@@ -1,40 +0,0 @@
cp14-store-buy-hint = Чтобы приобрести "{$name}", оставьте деньги и ваш заказ в торговом ящике: Подойдет любая бумага, на которой будет написано {$code}
cp14-store-buy-alchemy-unlock-t1-name = Торговый союз: Алхимики
cp14-store-buy-alchemy-unlock-t1-desc = Гильдия алхимиков королевства Кланира готова включить поселение в свой торговый путь взамен на небольшие дары и оплату.
cp14-store-buy-alchemy-vials-name = Алхимические пузырьки
cp14-store-buy-alchemy-vials-desc = Теперь проблема дефицита емкостей для зелий больше не проблема! Ведь по довольно скромной цене вы можете заказывать партии блестящих склянок прямо от лучших ремесленников! Случайные алхимические приборы в подарок.
cp14-store-buy-alchemy-bureaucracy-name = Бюрократический запас
cp14-store-buy-alchemy-bureaucracy-desc = Ручки, чернильницы и большая пачка бумаги. В папках разных цветов, и вовсе без папок: ведь мы заботимся о том, чтобы вы могли выбирать тот вариант, который вам комфортнее.
cp14-store-buy-alchemy-farm-seeds-name = Семена для фермерства
cp14-store-buy-alchemy-farm-seeds-desc = Набор разных семян, для фермерства всех видов! Не ограничивайте себя, купите сразу несколько ящиков, на случай, если фермеры все съедят и не оставят еды на переработку в семена.
cp14-store-buy-alchemy-demiplan-name = 5 ключей демиплана
cp14-store-buy-alchemy-demiplan-desc = Нестабильные карманные измерения, в котором вас может поджидать гибель или богатства. Что может быть лучше для ваших авантюристов?
cp14-store-buy-wood-name = Запас древесины
cp14-store-buy-wood-desc = Свежая древесина с доставкой до вашего поселения! Вы живете в краю где не растут деревья? Или у вас просто нет рабочих рук, чтобы пойти и нарубить их самостоятельно? Мы готовы сделать это за вас! Точнее, за ваши деньги.
cp14-store-buy-fabric-name = Запас текстиля
cp14-store-buy-fabric-desc = Большой запас ткани и ниток, для производства изысканнейших нарядов или другого инструментария. Только сегодня, только сейчас, только последние полгода.
cp14-store-buy-energy-name = Энергетический запас
cp14-store-buy-energy-desc = Энергетические кристаллы и средних, и малых размеров, и в добавок - перчатки манипулирования маной. Полный комплект, чтобы обеспечивать ваши энергоприборы энергией.
cp14-store-buy-cheese-name = Запас сыра
cp14-store-buy-cheese-desc = Коровки не любят плавать на кораблях, а вот их сыр вполне любит путешествия! Так оплатите же ему дорогу к вашему столу!
cp14-store-buy-copper-name = 10 слитков меди
cp14-store-buy-copper-desc = Ищете качественные медные слитки? Наши медные слитки подходят для всех нужд, будь то кузнечное дело или чеканка монет. Заказывайте прямо сейчас, пока их не раскупили мастера со всех уголков империи!
cp14-store-buy-iron-name = 10 слитков железа
cp14-store-buy-iron-desc = Прочный, надежный и универсальный металл для самых смелых проектов! Нужна броня, оружие или элементы креплений? Железные слитки в высшей пробе к вашим услугам. Это основа вашего успеха!
cp14-store-buy-gold-name = 10 слитков золота
cp14-store-buy-gold-desc = Для тех, кто ценит роскошь и изящество. Слитки чистейшего золота для украшений, инкрустации или инвестиций в будущее. Золото всегда в цене, а наша доставка — всегда в срок!
cp14-store-buy-guidebook-name = Обучающие книги
cp14-store-buy-guidebook-desc = У вас закончились специалисты в ключевых областях? Не проблема, с этим набором учебной литературы вы сможете сделать профессионалом даже младенца, и заставить его работать на благо Империи! (ООС: Тут пока что только книги для кузнеца)

View File

@@ -1,9 +0,0 @@
# Buy
cp14-store-service-unlock-sell = Разблокирует возможность продажи:
cp14-store-service-unlock-buy = Разблокирует возможность покупки:
# Sell
cp14-store-service-sell-entities = Продажа предметов:

View File

@@ -1,11 +0,0 @@
cp14-store-ui-title = Торговый аванпост "{$name}"
cp14-store-ui-order = Дополнительная информация
cp14-store-ui-next-travel-out = До отправления:
cp14-store-ui-next-travel-in = До прибытия:
cp14-store-ui-tab-buy = Покупка
cp14-store-ui-tab-sell = Продажа
cp14-store-ui-tab-special = [bold][color=#eba346]Разовое предложение![/color][/bold]
cp14-store-sell-hint = Чтобы продать {$name}, засуньте необходимый товар в торговый шкаф, и закройте его. Наши люди разберутся что к чему, заберут товар и отправят вам деньги через этот же торговый шкаф.

View File

@@ -0,0 +1,3 @@
cp14-trade-faction-contracts = Торговая гильдия Зелласиан
cp14-trade-faction-victoria-gardens = Сады Виктории
cp14-trade-faction-brad-potions = Великолепные зелья Брада

View File

@@ -0,0 +1,14 @@
cp14-trading-ui-button-unlock = Разблокировать контракт
cp14-trading-ui-button-unlock-tooltip = Вы заключаете контракт, затрачивая на это свою репутацию. После этого, вы можете покупать это снаряжение или услугу за деньги в неограниченном количестве.
cp14-trading-ui-button-buy = Купить
cp14-trading-ui-button-buy-tooltip = Вы тратите средства, расположенные на торговой платформе и закупаете указанное снаряжение или услугу у выбранного продавца, что так же увеличивает вашу репутацию. Снаряжение будет мгновенно доставлено вам путем пространственной магии, а услуга оказана в ближайшее время.
cp14-trading-ui-title = Платформа торговой связи с империей
cp14-trading-ui-cooldown = Перезарядка:
cp14-trading-faction-prefix = Торговля с:
cp14-trading-failure-popup-money = Недостаточно средств на платформе!
cp14-trading-contract-use = Торговля с "{$name}" разблокирована!

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,7 @@
amount: 1.5 amount: 1.5
- !type:PlantAdjustHealth - !type:PlantAdjustHealth
amount: 0.75 amount: 0.75
pricePerUnit: 2 pricePerUnit: 0.2
- type: reagent - type: reagent
id: Vitamin #Anything "healthy" id: Vitamin #Anything "healthy"
@@ -53,7 +53,7 @@
amount: 0.5 amount: 0.5
- !type:PlantAdjustHealth - !type:PlantAdjustHealth
amount: 1.5 amount: 1.5
pricePerUnit: 2.5 pricePerUnit: 0.25
- type: reagent - type: reagent
id: Protein #Meat and beans id: Protein #Meat and beans
@@ -78,7 +78,7 @@
- !type:OrganType - !type:OrganType
type: CP14Vampire type: CP14Vampire
shouldHave: false shouldHave: false
pricePerUnit: 3 pricePerUnit: 0.3
- type: reagent - type: reagent
id: Sugar #Candy and grains id: Sugar #Candy and grains

View File

@@ -1,275 +0,0 @@
- type: storePositionBuy
id: AlchemyVials
code: VIALS
price: 40
iconOverride:
sprite: _CP14/Objects/Specific/Alchemy/vial_medium.rsi
state: vial
factions:
- BradFamily
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledAlchemy
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledAlchemy
name: alchemical vials chest
components:
- type: StorageFill
contents:
- id: CP14VialTiny
amount: 5
- id: CP14VialSmall
amount: 5
- id: CP14VialMedium
amount: 5
- id: CP14GlassShard #Lol. Something broken
prob: 0.2
- type: storePositionBuy
id: CP14VialSmallHealingBrute
code: HEAL_BRUTE
price: 50
iconOverride:
sprite: _CP14/Objects/Specific/Alchemy/vial_small.rsi
state: vial
factions:
- BradFamily
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledSmallHealingBrute
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledSmallHealingBrute
name: healing potions chest
components:
- type: StorageFill
contents:
- id: CP14VialSmallHealingBrute
amount: 5
- type: storePositionBuy
id: CP14VialSmallHealingPoison
code: HEAL_POISON
price: 50
iconOverride:
sprite: _CP14/Objects/Specific/Alchemy/vial_small.rsi
state: vial
factions:
- BradFamily
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledSmallHealingPoison
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledSmallHealingPoison
name: antidote potions chest
components:
- type: StorageFill
contents:
- id: CP14VialSmallHealingPoison
amount: 5
- type: storePositionBuy
id: CP14VialSmallHealingAirloss
code: HEAL_AIRLOSS
price: 50
iconOverride:
sprite: _CP14/Objects/Specific/Alchemy/vial_small.rsi
state: vial
factions:
- BradFamily
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledSmallHealingAirloss
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledSmallHealingAirloss
name: airloss healing potions chest
components:
- type: StorageFill
contents:
- id: CP14VialSmallHealingAirloss
amount: 5
- type: storePositionBuy
id: CP14VialSmallHealingBlood
code: HEAL_BLOOD
price: 50
iconOverride:
sprite: _CP14/Objects/Specific/Alchemy/vial_small.rsi
state: vial
factions:
- BradFamily
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledSmallHealingBlood
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledSmallHealingBlood
name: blood restoration potions chest
components:
- type: StorageFill
contents:
- id: CP14VialSmallHealingBlood
amount: 5
- type: storePositionBuy
id: CP14VialSmallHealingMana
code: HEAL_MANA
price: 70
iconOverride:
sprite: _CP14/Objects/Specific/Alchemy/vial_small.rsi
state: vial
factions:
- BradFamily
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledSmallHealingMana
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledSmallHealingMana
name: mana potions chest
components:
- type: StorageFill
contents:
- id: CP14VialSmallHealingMana
amount: 5
- type: storePositionBuy
id: CP14VialSmallHealingManaDepletion
code: HEAL_MANA_DEPLETION
price: 70
iconOverride:
sprite: _CP14/Objects/Specific/Alchemy/vial_small.rsi
state: vial
factions:
- BradFamily
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledSmallHealingManaDepletion
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledSmallHealingManaDepletion
name: mana-depletion potions chest
components:
- type: StorageFill
contents:
- id: CP14VialSmallHealingManaDepletion
amount: 5
- type: storePositionBuy
id: CP14VialSmallSpeedUp
code: SPEED_UP
price: 70
iconOverride:
sprite: _CP14/Objects/Specific/Alchemy/vial_small.rsi
state: vial
factions:
- BradFamily
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledSmallSpeedUp
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledSmallSpeedUp
name: accseleration potions chest
components:
- type: StorageFill
contents:
- id: CP14VialSmallSpeedUp
amount: 5
- type: storePositionBuy
id: CP14VialSmallRainbow
code: FUNNY_POTION
price: 100
iconOverride:
sprite: _CP14/Objects/Specific/Alchemy/vial_small.rsi
state: vial
factions:
- BradFamily
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledSmallRainbow
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledSmallRainbow
name: funny potions chest
components:
- type: StorageFill
contents:
- id: CP14VialSmallRainbow
amount: 5
- type: storePositionBuy
id: Candles
code: CANDLES
price: 100
iconOverride:
sprite: Objects/Misc/candles.rsi
state: loadout
factions:
- BradFamily
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledCandles
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledCandles
name: candles chest
components:
- type: StorageFill
contents:
- id: CP14CandleRed
amount: 2
- id: CP14CandleBlue
amount: 2
- id: CP14CandleBlack
amount: 2
- id: CP14CandleGreen
amount: 2
- id: CP14CandlePurple
amount: 2
- id: CP14CandleRedSmall
amount: 2
- id: CP14CandleBlueSmall
amount: 2
- id: CP14CandleBlackSmall
amount: 2
- id: CP14CandleGreenSmall
amount: 2
- id: CP14CandlePurpleSmall
amount: 2
- type: storePositionBuy
id: SmokePowder
code: TOBACCO
price: 80
iconOverride:
sprite: _CP14/Objects/Misc/reagent_fillings.rsi
state: tobacco_small
factions:
- BradFamily
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledSmokePowder
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledSmokePowder
name: smoking powder chest
components:
- type: StorageFill
contents:
- id: CP14GroundTobacco
amount: 10
- id: CP14GroundSage
amount: 5

View File

@@ -1,14 +0,0 @@
- type: storePositionSell
id: CP14AlchemicalHerbals
price: 50
factions:
- BradFamily
service: !type:CP14SellWhitelistService
whitelist:
tags:
- CP14AlchemicalHerbals
count: 10
name: cp14-entity-group-alchemical-herbals
sprite:
sprite: _CP14/Objects/Flora/Wild/store_position.rsi
state: sell

View File

@@ -1,89 +0,0 @@
- type: storePositionSell
id: CP14BloodFlower
special: true
price: 200
factions:
- BradFamily
service: !type:CP14SellPrototypeService
proto: CP14BloodFlower
count: 20
- type: storePositionSell
id: CP14AgaricMushroom
special: true
price: 200
factions:
- BradFamily
service: !type:CP14SellPrototypeService
proto: CP14AgaricMushroom
count: 20
- type: storePositionSell
id: CP14ChromiumSlime
special: true
price: 600
factions:
- BradFamily
service: !type:CP14SellPrototypeService
proto: CP14ChromiumSlime
count: 20
- type: storePositionSell
id: CP14WildSage
special: true
price: 200
factions:
- BradFamily
service: !type:CP14SellPrototypeService
proto: CP14WildSage
count: 20
- type: storePositionSell
id: CP14LumiMushroom
special: true
price: 400
factions:
- BradFamily
service: !type:CP14SellPrototypeService
proto: CP14LumiMushroom
count: 20
- type: storePositionSell
id: CP14BlueAmanita
special: true
price: 200
factions:
- BradFamily
service: !type:CP14SellPrototypeService
proto: CP14BlueAmanita
count: 20
- type: storePositionSell
id: CP14Dayflin
special: true
price: 200
factions:
- BradFamily
service: !type:CP14SellPrototypeService
proto: CP14Dayflin
count: 20
- type: storePositionSell
id: CP14AirLily
special: true
price: 300
factions:
- BradFamily
service: !type:CP14SellPrototypeService
proto: CP14AirLily
count: 20
- type: storePositionSell
id: CP14BaseAlchemyBomb
special: true
price: 250
factions:
- BradFamily
service: !type:CP14SellPrototypeService
proto: CP14BaseAlchemyBomb
count: 3

View File

@@ -1,21 +0,0 @@
- type: storePositionBuy
id: RerollSell
code: REROLL_SELL
price: 20
nameOverride: cp14-buy-position-reroll-sell
iconOverride:
sprite: _CP14/Interface/Misc/reroll.rsi
state: reroll
service: !type:CP14RerollSpecialPositionsService
rerollSell: 5
#- type: storePositionBuy #Неактуально, т.к. позиций таких нет
# id: RerollBuy
# code: REROLL_BUY
# price: 20
# nameOverride: cp14-buy-position-reroll-buy
# iconOverride:
# sprite: _CP14/Interface/Misc/reroll.rsi
# state: reroll
# service: !type:CP14RerollSpecialPositionsService
# rerollBuy: 5

View File

@@ -1,99 +0,0 @@
- type: storePositionBuy
id: CP14ModularIronArrow
code: ARROW
price: 100
factions:
- HelmirWeapon
service: !type:CP14BuyItemsService
product: CP14ModularIronArrow
count: 6
- type: storePositionBuy
id: CP14ModularIronAxe
code: AXE
price: 150
factions:
- HelmirWeapon
service: !type:CP14BuyItemsService
product: CP14ModularIronAxe
count: 3
- type: storePositionBuy
id: CP14ModularIronDagger
code: DAGGER
price: 150
factions:
- HelmirWeapon
service: !type:CP14BuyItemsService
product: CP14ModularIronDagger
count: 7
- type: storePositionBuy
id: CP14ModularIronHammer
code: HAMMER
price: 150
factions:
- HelmirWeapon
service: !type:CP14BuyItemsService
product: CP14ModularIronHammer
count: 5
- type: storePositionBuy
id: CP14ModularIronMace
code: MACE
price: 150
factions:
- HelmirWeapon
service: !type:CP14BuyItemsService
product: CP14ModularIronMace
count: 5
- type: storePositionBuy
id: CP14ModularIronPickaxe
code: PICKAXE
price: 150
factions:
- HelmirWeapon
service: !type:CP14BuyItemsService
product: CP14ModularIronPickaxe
count: 5
- type: storePositionBuy
id: CP14ModularIronShovel
code: SHOVEL
price: 150
factions:
- HelmirWeapon
service: !type:CP14BuyItemsService
product: CP14ModularIronShovel
count: 5
- type: storePositionBuy
id: CP14ModularIronSickle
code: SICKLE
price: 150
factions:
- HelmirWeapon
service: !type:CP14BuyItemsService
product: CP14ModularIronSickle
count: 7
- type: storePositionBuy
id: CP14ModularIronSpear
code: SPEAR
price: 150
factions:
- HelmirWeapon
service: !type:CP14BuyItemsService
product: CP14ModularIronSpear
count: 5
- type: storePositionBuy
id: CP14ModularIronSword
code: SWORD
price: 150
factions:
- HelmirWeapon
service: !type:CP14BuyItemsService
product: CP14ModularIronSword
count: 5

View File

@@ -1,169 +0,0 @@
- type: storePositionBuy
id: FarmSeeds
code: SEEDS
iconOverride:
sprite: _CP14/Objects/Specific/Farming/seeds.rsi
state: seeds
price: 70
factions:
- SpiceStream
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledFarmSeeds
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledFarmSeeds
name: farm seeds chest
components:
- type: StorageFill
contents:
- id: CP14SeedWheat
amount: 3
- id: CP14SeedPumpkin
amount: 3
- id: CP14SeedCabbage
amount: 3
- id: CP14SeedCucumber
amount: 3
- id: CP14SeedTomato
amount: 3
- id: CP14SeedPepper
amount: 3
- id: CP14SeedCotton
amount: 3
- type: storePositionBuy
id: Cheese
code: CHEESE
iconOverride:
sprite: _CP14/Objects/Consumable/Food/cheese.rsi
state: cheese_wheel
price: 100
factions:
- SpiceStream
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledCheese
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledCheese
name: cheese chest
components:
- type: StorageFill
contents:
- id: CP14FoodCheeseWheel
amount: 5
- type: storePositionBuy
id: Wood
code: WOOD
price: 50
factions:
- SpiceStream
service: !type:CP14BuyItemsService
product: CP14WoodenPlanks10
count: 5
- type: storePositionBuy
id: Fabric
code: FABRIC
price: 30
factions:
- SpiceStream
service: !type:CP14BuyItemsService
product: CP14Cloth10
count: 3
- type: storePositionBuy
id: CP14String
code: STRINGS
price: 30
factions:
- SpiceStream
service: !type:CP14BuyItemsService
product: CP14String
count: 5
- type: storePositionBuy
id: CopperBar
code: COPPER
price: 250
factions:
- SpiceStream
service: !type:CP14BuyItemsService
product: CP14CopperBar10
- type: storePositionBuy
id: IronBar
code: IRON
price: 500
factions:
- SpiceStream
service: !type:CP14BuyItemsService
product: CP14IronBar10
- type: storePositionBuy
id: GoldBar
code: GOLD
price: 2000
factions:
- SpiceStream
service: !type:CP14BuyItemsService
product: CP14GoldBar10
- type: storePositionBuy
id: Bureaucracy
code: PAPER
iconOverride:
sprite: _CP14/Objects/Bureaucracy/paper.rsi
state: folder_red
price: 100
factions:
- SpiceStream
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledBureaucracy
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledBureaucracy
name: bureaucracy chest
components:
- type: StorageFill
contents:
- id: CP14PaperFolderBlue
amount: 5
- id: CP14PaperFolderRed
amount: 5
- id: CP14Paper
amount: 5
- id: CP14PenFeather
amount: 3
- type: storePositionBuy
id: EnergyCrystals
code: ENERGY
iconOverride:
sprite: _CP14/Objects/Specific/Thaumaturgy/powerline_gauntlet.rsi
state: icon
price: 150
factions:
- SpiceStream
service: !type:CP14BuyItemsService
product: CP14WoodenChestFilledEnergyCrystals
- type: entity
parent: CP14WoodenChest
id: CP14WoodenChestFilledEnergyCrystals
name: energy crystals chest
components:
- type: StorageFill
contents:
- id: CP14EnergyCrystalMediumEmpty
amount: 5
- id: CP14ManaOperationGlove
amount: 2

View File

@@ -1,45 +0,0 @@
# ANCHORABLE PROBLEMS
#- type: storePositionBuy
# id: DwarfBeer
# code: BEER_DWARF
# special: true
# nameOverride: cp14-reagent-name-dwarfbeer
# price: 150
# factions:
# - SpiceStream
# service: !type:CP14BuyItemsService
# product: CP14CraneBarrelDwarfBeer
#
#- type: storePositionBuy
# id: BeerGerbil
# code: BEER_BREEZE
# special: true
# nameOverride: cp14-reagent-name-breeze
# price: 70
# factions:
# - SpiceStream
# service: !type:CP14BuyItemsService
# product: CP14CraneBarrelSmallBeerBreeze
#
#- type: storePositionBuy
# id: AleBottomless
# code: BEER_BOTTOMLESS
# special: true
# nameOverride: cp14-reagent-name-bottomless
# price: 70
# factions:
# - SpiceStream
# service: !type:CP14BuyItemsService
# product: CP14CraneBarrelSmallAleBottomless
#
#- type: storePositionBuy
# id: WineZellasian
# code: WINE_ZELLASIAN
# special: true
# nameOverride: cp14-reagent-name-zellasian-pleasure
# price: 150
# factions:
# - SpiceStream
# service: !type:CP14BuyItemsService
# product: CP14CraneBarrelWineZellasianPleasure

View File

@@ -1,94 +0,0 @@
- type: storePositionSell
id: CopperBars
price: 150
factions:
- SpiceStream
- HelmirWeapon
service: !type:CP14SellStackService
stackId: CP14CopperBar
count: 10
- type: storePositionSell
id: CopperOre
price: 20
factions:
- SpiceStream
service: !type:CP14SellStackService
stackId: CP14OreCopper
count: 10
- type: storePositionSell
id: IronBars
price: 300
factions:
- SpiceStream
- HelmirWeapon
service: !type:CP14SellStackService
stackId: CP14IronBar
count: 10
- type: storePositionSell
id: IronOre
price: 30
factions:
- SpiceStream
service: !type:CP14SellStackService
stackId: CP14OreIron
count: 10
- type: storePositionSell
id: GoldBars
price: 1200
factions:
- SpiceStream
- HelmirWeapon
service: !type:CP14SellStackService
stackId: CP14GoldBar
count: 10
- type: storePositionSell
id: GoldOre
price: 120
factions:
- SpiceStream
service: !type:CP14SellStackService
stackId: CP14OreGold
count: 10
- type: storePositionSell
id: MithrilBars
price: 2500
factions:
- SpiceStream
- HelmirWeapon
service: !type:CP14SellStackService
stackId: CP14MithrilBar
count: 10
- type: storePositionSell
id: MithrilOre
price: 250
factions:
- SpiceStream
service: !type:CP14SellStackService
stackId: CP14OreMithril
count: 10
- type: storePositionSell
id: Wood
price: 5
factions:
- SpiceStream
- HelmirWeapon
service: !type:CP14SellStackService
stackId: CP14WoodenPlanks
count: 30
- type: storePositionSell
id: Glass
price: 100
factions:
- SpiceStream
service: !type:CP14SellStackService
stackId: CP14GlassSheet
count: 10

View File

@@ -1,129 +0,0 @@
- type: storePositionSell
id: CP14DyeRed
special: true
price: 75
factions:
- SpiceStream
service: !type:CP14SellPrototypeService
proto: CP14DyeRed
count: 5
- type: storePositionSell
id: CP14DyeYellow
special: true
price: 75
factions:
- SpiceStream
service: !type:CP14SellPrototypeService
proto: CP14DyeYellow
count: 5
- type: storePositionSell
id: CP14DyeBlue
special: true
price: 75
factions:
- SpiceStream
service: !type:CP14SellPrototypeService
proto: CP14DyeBlue
count: 5
- type: storePositionSell
id: CP14FoodPieMeat
special: true
price: 100
factions:
- SpiceStream
service: !type:CP14SellPrototypeService
proto: CP14FoodPieMeat
count: 1
- type: storePositionSell
id: CP14FoodPiePumpkin
special: true
price: 100
factions:
- SpiceStream
service: !type:CP14SellPrototypeService
proto: CP14FoodPiePumpkin
count: 1
- type: storePositionSell
id: CP14FoodBreadBun
special: true
price: 20
factions:
- SpiceStream
service: !type:CP14SellPrototypeService
proto: CP14FoodBreadBun
count: 3
- type: storePositionSell
id: CP14FoodCabbage
special: true
price: 80
factions:
- SpiceStream
service: !type:CP14SellPrototypeService
proto: CP14FoodCabbage
count: 10
- type: storePositionSell
id: CP14FoodPumpkin
special: true
price: 80
factions:
- SpiceStream
service: !type:CP14SellPrototypeService
proto: CP14FoodPumpkin
count: 10
- type: storePositionSell
id: CP14FoodPotato
special: true
price: 80
factions:
- SpiceStream
service: !type:CP14SellPrototypeService
proto: CP14FoodPotato
count: 10
- type: storePositionSell
id: CP14FoodCucumber
special: true
price: 80
factions:
- SpiceStream
service: !type:CP14SellPrototypeService
proto: CP14FoodCucumber
count: 10
- type: storePositionSell
id: CP14FoodTomatoes
special: true
price: 80
factions:
- SpiceStream
service: !type:CP14SellPrototypeService
proto: CP14FoodTomatoes
count: 10
- type: storePositionSell
id: CP14FoodPepper
special: true
price: 80
factions:
- SpiceStream
service: !type:CP14SellPrototypeService
proto: CP14FoodPepper
count: 10
- type: storePositionSell
id: CP14FoodOnion
special: true
price: 80
factions:
- SpiceStream
service: !type:CP14SellPrototypeService
proto: CP14FoodOnion
count: 10

View File

@@ -1,68 +0,0 @@
- type: storePositionBuy
id: CP14SpellScrollResurrection
code: SCROLL_RESURRECTION
price: 100
factions:
- Sylphoria
service: !type:CP14BuyItemsService
product: CP14SpellScrollResurrection
- type: storePositionBuy
id: CP14SpellScrollCureWounds
code: CURE_WOUNDS
price: 100
factions:
- Sylphoria
service: !type:CP14BuyItemsService
product: CP14SpellScrollCureWounds
count: 5
- type: storePositionBuy
id: CP14SpellScrollCureBurn
code: CURE_BURN
price: 100
factions:
- Sylphoria
service: !type:CP14BuyItemsService
product: CP14SpellScrollCureBurn
count: 5
- type: storePositionBuy
id: CP14SpellScrollBloodPurification
code: BLOOD_PURE
price: 100
factions:
- Sylphoria
service: !type:CP14BuyItemsService
product: CP14SpellScrollBloodPurification
count: 5
- type: storePositionBuy
id: CP14SpellscrollSignalLightBlue
code: SIGNAL_BLUE
price: 50
factions:
- Sylphoria
service: !type:CP14BuyItemsService
product: CP14SpellscrollSignalLightBlue
count: 5
- type: storePositionBuy
id: CP14SpellscrollSignalLightYellow
code: SIGNAL_YELLOW
price: 50
factions:
- Sylphoria
service: !type:CP14BuyItemsService
product: CP14SpellscrollSignalLightYellow
count: 5
- type: storePositionBuy
id: CP14SpellscrollSignalLightRed
code: SIGNAL_RED
price: 50
factions:
- Sylphoria
service: !type:CP14BuyItemsService
product: CP14SpellscrollSignalLightRed
count: 5

View File

@@ -1,32 +0,0 @@
- type: storePositionSell
id: CP14LucenPlanks
price: 100
factions:
- Sylphoria
service: !type:CP14SellStackService
stackId: CP14LucensWoodenPlanks
count: 10
- type: storePositionSell
id: CP14SpellScroll
price: 50
factions:
- Sylphoria
service: !type:CP14SellWhitelistService
whitelist:
tags:
- CP14SpellScroll
count: 5
name: cp14-entity-group-spell-scrolls
sprite:
sprite: _CP14/Objects/Bureaucracy/paper.rsi
state: scrolls
- type: storePositionSell
id: CP14ClothingCloakAmuletGold
price: 80
factions:
- Sylphoria
service: !type:CP14SellPrototypeService
proto: CP14ClothingCloakAmuletGold
count: 1

View File

@@ -1,139 +0,0 @@
- type: storePositionSell
id: BountyTorch
special: true
price: 20
factions:
- Sylphoria
service: !type:CP14SellPrototypeService
proto: CP14Torch
count: 5
- type: storePositionSell
id: BountyLucenPlanks
special: true
price: 200
factions:
- Sylphoria
service: !type:CP14SellStackService
stackId: CP14LucensWoodenPlanks
count: 20
- type: storePositionSell
id: CP14SpellScrollShadowStep
special: true
price: 80
factions:
- Sylphoria
service: !type:CP14SellPrototypeService
proto: CP14SpellScrollShadowStep
count: 1
- type: storePositionSell
id: CP14SpellScrollFireball
special: true
price: 80
factions:
- Sylphoria
service: !type:CP14SellPrototypeService
proto: CP14SpellScrollFireball
count: 1
- type: storePositionSell
id: CP14SpellScrollBeerCreation
special: true
price: 400
factions:
- Sylphoria
service: !type:CP14SellPrototypeService
proto: CP14SpellScrollBeerCreation
count: 1
- type: storePositionSell
id: CP14ClothingRingIceShards
special: true
price: 150
factions:
- Sylphoria
service: !type:CP14SellPrototypeService
proto: CP14ClothingRingIceShards
count: 1
- type: storePositionSell
id: CP14ClothingRingFlashLight
special: true
price: 150
factions:
- Sylphoria
service: !type:CP14SellPrototypeService
proto: CP14ClothingRingFlashLight
count: 1
- type: storePositionSell
id: CP14BaseLockpick
special: true
price: 100
factions:
- Sylphoria
service: !type:CP14SellPrototypeService
proto: CP14BaseLockpick
count: 10
- type: storePositionSell
id: CP14MobRabbit
special: true
price: 50
factions:
- Sylphoria
service: !type:CP14SellPrototypeService
proto: CP14MobRabbit
count: 5
- type: storePositionSell
id: CP14MobPig
special: true
price: 130
factions:
- Sylphoria
service: !type:CP14SellPrototypeService
proto: CP14MobPig
count: 5
- type: storePositionSell
id: CP14MobBoar
special: true
price: 170
factions:
- Sylphoria
service: !type:CP14SellPrototypeService
proto: CP14MobBoar
count: 5
- type: storePositionSell
id: CP14MobFrog
special: true
price: 10
factions:
- Sylphoria
service: !type:CP14SellPrototypeService
proto: CP14MobFrog
count: 5
- type: storePositionSell
id: CP14MobMonsterMole
special: true
price: 50
factions:
- Sylphoria
service: !type:CP14SellPrototypeService
proto: CP14MobMonsterMole
count: 1
- type: storePositionSell
id: CP14PartsMonsterGlands
special: true
price: 100
factions:
- Sylphoria
service: !type:CP14SellPrototypeService
proto: CP14PartsMonsterGlands
count: 1

View File

@@ -1,19 +0,0 @@
- type: storeFaction
id: HelmirWeapon
name: cp14-faction-name-helmir
desc: cp14-faction-desc-helmir
- type: storeFaction
id: Sylphoria
name: cp14-faction-name-sylphoria
desc: cp14-faction-desc-sylphoria
- type: storeFaction
id: SpiceStream
name: cp14-faction-name-spice-stream
desc: cp14-faction-desc-spice-stream
- type: storeFaction
id: BradFamily
name: cp14-faction-name-brad-family
desc: cp14-faction-desc-brad-family

View File

@@ -23,8 +23,8 @@
- type: CP14ModularCraftPart - type: CP14ModularCraftPart
possibleParts: possibleParts:
- AventailIronChainmail - AventailIronChainmail
- type: CP14Material - type: PhysicalComposition
materials: materialComposition:
CP14Iron: 10 CP14Iron: 10
- type: entity - type: entity
@@ -41,8 +41,8 @@
- type: CP14ModularCraftPart - type: CP14ModularCraftPart
possibleParts: possibleParts:
- AventailGoldChainmail - AventailGoldChainmail
- type: CP14Material - type: PhysicalComposition
materials: materialComposition:
CP14Gold: 10 CP14Gold: 10
- type: entity - type: entity
@@ -59,8 +59,8 @@
- type: CP14ModularCraftPart - type: CP14ModularCraftPart
possibleParts: possibleParts:
- AventailCopperChainmail - AventailCopperChainmail
- type: CP14Material - type: PhysicalComposition
materials: materialComposition:
CP14Copper: 10 CP14Copper: 10
- type: entity - type: entity
@@ -77,6 +77,6 @@
- type: CP14ModularCraftPart - type: CP14ModularCraftPart
possibleParts: possibleParts:
- AventailMithrilChainmail - AventailMithrilChainmail
- type: CP14Material - type: PhysicalComposition
materials: materialComposition:
CP14Mithril: 10 CP14Mithril: 10

View File

@@ -11,8 +11,8 @@
- type: CP14ModularCraftPart - type: CP14ModularCraftPart
possibleParts: possibleParts:
- AventailIronPlate - AventailIronPlate
- type: CP14Material - type: PhysicalComposition
materials: materialComposition:
CP14Iron: 10 CP14Iron: 10
- type: entity - type: entity
@@ -29,8 +29,8 @@
- type: CP14ModularCraftPart - type: CP14ModularCraftPart
possibleParts: possibleParts:
- AventailGoldPlate - AventailGoldPlate
- type: CP14Material - type: PhysicalComposition
materials: materialComposition:
CP14Gold: 10 CP14Gold: 10
- type: entity - type: entity
@@ -47,8 +47,8 @@
- type: CP14ModularCraftPart - type: CP14ModularCraftPart
possibleParts: possibleParts:
- AventailCopperPlate - AventailCopperPlate
- type: CP14Material - type: PhysicalComposition
materials: materialComposition:
CP14Copper: 10 CP14Copper: 10
- type: entity - type: entity
@@ -65,6 +65,6 @@
- type: CP14ModularCraftPart - type: CP14ModularCraftPart
possibleParts: possibleParts:
- AventailMithrilPlate - AventailMithrilPlate
- type: CP14Material - type: PhysicalComposition
materials: materialComposition:
CP14Mithril: 10 CP14Mithril: 10

Some files were not shown because too many files have changed in this diff Show More