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;
|
2025-06-23 12:19:02 +03:00
|
|
|
using Content.Shared.Cargo.Components;
|
2024-11-29 01:31:42 +03:00
|
|
|
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-06-23 12:19:02 +03:00
|
|
|
var detailEnt = Spawn(detail);
|
|
|
|
|
if (!TryComp<CP14ModularCraftPartComponent>(detailEnt, out var partComp))
|
|
|
|
|
{
|
|
|
|
|
QueueDel(detailEnt);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
TryAddPartToFirstSlot(ent, (detailEnt, partComp));
|
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 TryAddPartToSlot(Entity<CP14ModularCraftStartPointComponent> start,
|
2025-06-23 12:19:02 +03:00
|
|
|
Entity<CP14ModularCraftPartComponent> part,
|
2024-11-29 01:31:42 +03:00
|
|
|
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,
|
2025-06-23 12:19:02 +03:00
|
|
|
Entity<CP14ModularCraftPartComponent> part,
|
2024-11-29 01:31:42 +03:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-23 12:19:02 +03:00
|
|
|
var startStaticPrice = EnsureComp<StaticPriceComponent>(start);
|
|
|
|
|
startStaticPrice.Price += part.Comp.AddPrice;
|
|
|
|
|
|
|
|
|
|
if (TryComp<StaticPriceComponent>(part, out var partStaticPrice))
|
2025-05-29 00:22:47 +03:00
|
|
|
{
|
|
|
|
|
|
2025-06-23 12:19:02 +03:00
|
|
|
startStaticPrice.Price += partStaticPrice.Price;
|
2025-05-29 00:22:47 +03:00
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|