2025-05-29 00:22:47 +03:00
|
|
|
using Content.Server.Cargo.Components;
|
2024-11-29 01:31:42 +03:00
|
|
|
using Content.Server.Item;
|
|
|
|
|
using Content.Shared._CP14.ModularCraft;
|
|
|
|
|
using Content.Shared._CP14.ModularCraft.Components;
|
|
|
|
|
using Content.Shared._CP14.ModularCraft.Prototypes;
|
|
|
|
|
using Content.Shared.Throwing;
|
2025-01-05 00:43:51 +04:00
|
|
|
using Content.Shared.Examine;
|
2025-05-29 00:22:47 +03:00
|
|
|
using Content.Shared.Materials;
|
2025-01-05 00:43:51 +04:00
|
|
|
using Content.Shared.Verbs;
|
2024-11-29 01:31:42 +03:00
|
|
|
using Robust.Server.GameObjects;
|
|
|
|
|
using Robust.Shared.Prototypes;
|
|
|
|
|
using Robust.Shared.Random;
|
2025-01-05 00:43:51 +04:00
|
|
|
using Robust.Shared.Utility;
|
2024-11-29 01:31:42 +03:00
|
|
|
|
|
|
|
|
namespace Content.Server._CP14.ModularCraft;
|
|
|
|
|
|
|
|
|
|
public sealed class CP14ModularCraftSystem : CP14SharedModularCraftSystem
|
|
|
|
|
{
|
|
|
|
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
|
|
|
|
[Dependency] private readonly TransformSystem _transform = default!;
|
|
|
|
|
[Dependency] private readonly ThrowingSystem _throwing = default!;
|
|
|
|
|
[Dependency] private readonly IRobustRandom _random = default!;
|
|
|
|
|
[Dependency] private readonly ItemSystem _item = default!;
|
|
|
|
|
|
2025-01-05 00:43:51 +04:00
|
|
|
[Dependency] private readonly ExamineSystemShared _examine = default!;
|
|
|
|
|
|
2024-11-29 01:31:42 +03:00
|
|
|
public override void Initialize()
|
|
|
|
|
{
|
|
|
|
|
base.Initialize();
|
|
|
|
|
|
|
|
|
|
SubscribeLocalEvent<CP14ModularCraftStartPointComponent, MapInitEvent>(OnStartPointMapInit);
|
2025-01-22 23:53:36 +03:00
|
|
|
SubscribeLocalEvent<CP14ModularCraftStartPointComponent, CP14ModularCraftAddPartDoAfter>(OnAddedToStart);
|
|
|
|
|
SubscribeLocalEvent<CP14ModularCraftPartComponent, CP14ModularCraftAddPartDoAfter>(OnAddedToPart);
|
2025-01-05 00:43:51 +04:00
|
|
|
SubscribeLocalEvent<CP14ModularCraftStartPointComponent, GetVerbsEvent<ExamineVerb>>(OnVerbExamine);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnVerbExamine(Entity<CP14ModularCraftStartPointComponent> ent, ref GetVerbsEvent<ExamineVerb> args)
|
|
|
|
|
{
|
|
|
|
|
if (!args.CanInteract || !args.CanAccess)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var markup = GetExamine(ent.Comp);
|
|
|
|
|
_examine.AddDetailedExamineVerb(
|
|
|
|
|
args,
|
|
|
|
|
ent.Comp,
|
|
|
|
|
markup,
|
|
|
|
|
Loc.GetString("cp14-modular-craft-examine"),
|
|
|
|
|
"/Textures/Interface/VerbIcons/settings.svg.192dpi.png");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private FormattedMessage GetExamine(CP14ModularCraftStartPointComponent comp)
|
|
|
|
|
{
|
|
|
|
|
var msg = new FormattedMessage();
|
|
|
|
|
|
|
|
|
|
msg.AddMarkupOrThrow(Loc.GetString("cp14-modular-craft-examine-freeslots"));
|
|
|
|
|
|
|
|
|
|
foreach (var slot in comp.FreeSlots)
|
|
|
|
|
{
|
|
|
|
|
if (!_proto.TryIndex(slot, out var slotProto))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
msg.AddMarkupOrThrow("\n - " + Loc.GetString(slotProto.Name));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return msg;
|
2024-11-29 01:31:42 +03:00
|
|
|
}
|
|
|
|
|
|
2025-01-22 23:53:36 +03:00
|
|
|
private void OnAddedToStart(Entity<CP14ModularCraftStartPointComponent> start, ref CP14ModularCraftAddPartDoAfter args)
|
2024-11-29 01:31:42 +03:00
|
|
|
{
|
|
|
|
|
if (args.Cancelled || args.Handled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!TryComp<CP14ModularCraftPartComponent>(args.Used, out var partComp))
|
|
|
|
|
return;
|
|
|
|
|
|
2025-01-22 23:53:36 +03:00
|
|
|
if (!TryAddPartToFirstSlot(start, (args.Used.Value, partComp)))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
//TODO: Sound
|
|
|
|
|
|
|
|
|
|
args.Handled = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnAddedToPart(Entity<CP14ModularCraftPartComponent> part, ref CP14ModularCraftAddPartDoAfter args)
|
|
|
|
|
{
|
|
|
|
|
if (args.Cancelled || args.Handled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!TryComp<CP14ModularCraftStartPointComponent>(args.Used, out var startComp))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!TryAddPartToFirstSlot((args.Used.Value, startComp), part))
|
2024-11-29 01:31:42 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
//TODO: Sound
|
|
|
|
|
|
|
|
|
|
args.Handled = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnStartPointMapInit(Entity<CP14ModularCraftStartPointComponent> ent, ref MapInitEvent args)
|
|
|
|
|
{
|
|
|
|
|
foreach (var startSlot in ent.Comp.StartSlots)
|
|
|
|
|
{
|
|
|
|
|
ent.Comp.FreeSlots.Add(startSlot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TryComp<CP14ModularCraftAutoAssembleComponent>(ent, out var autoAssemble))
|
|
|
|
|
{
|
|
|
|
|
foreach (var detail in autoAssemble.Details)
|
|
|
|
|
{
|
2025-01-22 23:53:36 +03:00
|
|
|
TryAddPartToFirstSlot(ent, detail);
|
2024-11-29 01:31:42 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool TryAddPartToFirstSlot(Entity<CP14ModularCraftStartPointComponent> start,
|
|
|
|
|
Entity<CP14ModularCraftPartComponent> part)
|
|
|
|
|
{
|
|
|
|
|
foreach (var partProto in part.Comp.PossibleParts)
|
|
|
|
|
{
|
|
|
|
|
if (!_proto.TryIndex(partProto, out var partIndexed))
|
|
|
|
|
continue;
|
|
|
|
|
|
2025-02-16 11:41:43 +03:00
|
|
|
if (partIndexed.Slots.Count == 0)
|
2024-11-29 01:31:42 +03:00
|
|
|
continue;
|
|
|
|
|
|
2025-02-16 11:41:43 +03:00
|
|
|
foreach (var slot in partIndexed.Slots)
|
2024-11-29 01:31:42 +03:00
|
|
|
{
|
2025-02-16 11:41:43 +03:00
|
|
|
if (!start.Comp.FreeSlots.Contains(slot))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (TryAddPartToSlot(start, part, partProto, slot))
|
|
|
|
|
{
|
|
|
|
|
QueueDel(part);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-11-29 01:31:42 +03:00
|
|
|
}
|
|
|
|
|
}
|
2024-11-30 14:16:48 +03:00
|
|
|
|
2024-11-29 01:31:42 +03:00
|
|
|
return false;
|
|
|
|
|
}
|
2024-11-30 14:16:48 +03:00
|
|
|
|
2024-11-29 01:31:42 +03:00
|
|
|
private bool TryAddPartToFirstSlot(Entity<CP14ModularCraftStartPointComponent> start,
|
2025-01-22 23:53:36 +03:00
|
|
|
ProtoId<CP14ModularCraftPartPrototype> partProto)
|
2024-11-29 01:31:42 +03:00
|
|
|
{
|
|
|
|
|
if (!_proto.TryIndex(partProto, out var partIndexed))
|
|
|
|
|
return false;
|
|
|
|
|
|
2025-02-16 11:41:43 +03:00
|
|
|
if (partIndexed.Slots.Count == 0)
|
2024-11-29 01:31:42 +03:00
|
|
|
return false;
|
|
|
|
|
|
2025-02-16 11:41:43 +03:00
|
|
|
foreach (var slot in partIndexed.Slots)
|
|
|
|
|
{
|
|
|
|
|
if (!start.Comp.FreeSlots.Contains(slot))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
return TryAddPartToSlot(start, null, partProto, slot);
|
|
|
|
|
}
|
2024-11-29 01:31:42 +03:00
|
|
|
|
2025-02-16 11:41:43 +03:00
|
|
|
return false;
|
2024-11-29 01:31:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool TryAddPartToSlot(Entity<CP14ModularCraftStartPointComponent> start,
|
|
|
|
|
Entity<CP14ModularCraftPartComponent>? part,
|
|
|
|
|
ProtoId<CP14ModularCraftPartPrototype> partProto,
|
2025-01-22 23:53:36 +03:00
|
|
|
ProtoId<CP14ModularCraftSlotPrototype> slot)
|
2024-11-29 01:31:42 +03:00
|
|
|
{
|
|
|
|
|
if (!start.Comp.FreeSlots.Contains(slot))
|
|
|
|
|
return false;
|
|
|
|
|
|
2025-01-22 23:53:36 +03:00
|
|
|
//TODO: Size changing broken in gridstorage
|
2024-11-29 01:31:42 +03:00
|
|
|
|
|
|
|
|
AddPartToSlot(start, part, partProto, slot);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AddPartToSlot(Entity<CP14ModularCraftStartPointComponent> start,
|
|
|
|
|
Entity<CP14ModularCraftPartComponent>? part,
|
|
|
|
|
ProtoId<CP14ModularCraftPartPrototype> partProto,
|
|
|
|
|
ProtoId<CP14ModularCraftSlotPrototype> slot)
|
|
|
|
|
{
|
|
|
|
|
start.Comp.FreeSlots.Remove(slot);
|
|
|
|
|
start.Comp.InstalledParts.Add(partProto);
|
|
|
|
|
|
|
|
|
|
var indexedPart = _proto.Index(partProto);
|
|
|
|
|
|
2025-05-29 00:22:47 +03:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Trading request system (#1460)
* mapping public stores update
* base selling platform update
* basic UI setup
* Update coin icon textures
Refreshed the c, g, p, and s coin images in the interface textures. This likely improves their appearance or corrects previous visual issues.
* parse requests data into UI
* selling platform UI state now include price
Updated the selling platform UI to display the calculated price of placed items. Moved the UpdateSellingUIState logic from the shared system to the server system, and modified the CP14SellingPlatformUiState to include a price field. The client window now uses the state-provided price instead of a hardcoded value.
* Update selling UI state on item placed or removed
Added event subscriptions for ItemPlacedEvent and ItemRemovedEvent to update the selling UI state when items are placed or removed from the selling platform. Refactored UpdateSellingUIState to remove the user parameter, as it is no longer needed.
* sell button works now
Replaces the previous sell request mechanism with a new CP14TradingSellAttempt message for selling items on the platform. Updates client and server logic to use this new message, adds a CanSell helper for item validation, and refactors related UI and event handling code for improved clarity and maintainability.
* auto pricing requirements
* Refactor reputation reward to use cashback rate
Reputation rewards for selling requests are now calculated as a percentage (cashback) of the sale price, rather than a fixed value. Updated the relevant UI, server logic, and prototype fields to reflect this change. Also cleaned up the brad_potions.yml prototype file by removing a duplicate entry and correcting an ID.
* request rerolling
2025-06-23 01:21:25 +03:00
|
|
|
if (TryComp<Shared.Cargo.Components.StaticPriceComponent>(part, out var staticPartPrice))
|
2025-05-29 00:22:47 +03:00
|
|
|
{
|
Trading request system (#1460)
* mapping public stores update
* base selling platform update
* basic UI setup
* Update coin icon textures
Refreshed the c, g, p, and s coin images in the interface textures. This likely improves their appearance or corrects previous visual issues.
* parse requests data into UI
* selling platform UI state now include price
Updated the selling platform UI to display the calculated price of placed items. Moved the UpdateSellingUIState logic from the shared system to the server system, and modified the CP14SellingPlatformUiState to include a price field. The client window now uses the state-provided price instead of a hardcoded value.
* Update selling UI state on item placed or removed
Added event subscriptions for ItemPlacedEvent and ItemRemovedEvent to update the selling UI state when items are placed or removed from the selling platform. Refactored UpdateSellingUIState to remove the user parameter, as it is no longer needed.
* sell button works now
Replaces the previous sell request mechanism with a new CP14TradingSellAttempt message for selling items on the platform. Updates client and server logic to use this new message, adds a CanSell helper for item validation, and refactors related UI and event handling code for improved clarity and maintainability.
* auto pricing requirements
* Refactor reputation reward to use cashback rate
Reputation rewards for selling requests are now calculated as a percentage (cashback) of the sale price, rather than a fixed value. Updated the relevant UI, server logic, and prototype fields to reflect this change. Also cleaned up the brad_potions.yml prototype file by removing a duplicate entry and correcting an ID.
* request rerolling
2025-06-23 01:21:25 +03:00
|
|
|
var startStaticPrice = EnsureComp<Shared.Cargo.Components.StaticPriceComponent>(start);
|
2025-05-29 00:22:47 +03:00
|
|
|
|
|
|
|
|
startStaticPrice.Price += staticPartPrice.Price;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-29 01:31:42 +03:00
|
|
|
foreach (var modifier in indexedPart.Modifiers)
|
|
|
|
|
{
|
|
|
|
|
modifier.Effect(EntityManager, start, part);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_item.VisualsChanged(start);
|
|
|
|
|
Dirty(start);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DisassembleModular(EntityUid target)
|
|
|
|
|
{
|
|
|
|
|
if (!TryComp<CP14ModularCraftStartPointComponent>(target, out var modular))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var sourceCoord = _transform.GetMapCoordinates(target);
|
|
|
|
|
|
|
|
|
|
//Spawn start part
|
|
|
|
|
if (modular.StartProtoPart is not null)
|
|
|
|
|
{
|
|
|
|
|
if (_random.Prob(0.5f)) //TODO: Dehardcode
|
|
|
|
|
{
|
|
|
|
|
var spawned = Spawn(modular.StartProtoPart, sourceCoord);
|
|
|
|
|
_throwing.TryThrow(spawned, _random.NextAngle().ToWorldVec(), 1f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Spawn parts
|
|
|
|
|
foreach (var part in modular.InstalledParts)
|
|
|
|
|
{
|
|
|
|
|
if (!_proto.TryIndex(part, out var indexedPart))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (_random.Prob(indexedPart.DestroyProb))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (indexedPart.SourcePart is null)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
var spawned = Spawn(indexedPart.SourcePart, sourceCoord);
|
|
|
|
|
_throwing.TryThrow(spawned, _random.NextAngle().ToWorldVec(), 1f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Delete
|
|
|
|
|
QueueDel(target);
|
|
|
|
|
}
|
|
|
|
|
}
|