Skip to content

Commit

Permalink
update code to allow lawset updating
Browse files Browse the repository at this point in the history
  • Loading branch information
deltanedas committed Nov 27, 2024
1 parent 74d7a6c commit ae025b8
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Content.Server.Silicons.Laws;
using Content.Shared.Emag.Components;
using Content.Shared.Emag.Systems;
using Content.Shared.Silicons.Laws;
using Content.Shared.Silicons.Laws.Components;
using Robust.Shared.Prototypes;

namespace Content.Server.Silicons.Borgs;

/// <summary>
/// Handles lawset patching when switching type.
/// If a borg is made emagged it needs its emag laws carried over.
/// </summary>
public sealed partial class BorgSwitchableTypeSystem
{
[Dependency] private readonly SiliconLawSystem _law = default!;

private void ConfigureLawset(EntityUid uid, ProtoId<SiliconLawsetPrototype> id)
{
var laws = _law.GetLawset(id);
_law.SetLaws(laws.Laws, uid);

// re-add law 0 and final law based on new lawset
if (CompOrNull<EmagSiliconLawComponent>(uid)?.OwnerName != null)
{
// raising the event manually to bypass re-emagging checks
var ev = new GotEmaggedEvent(uid); // user wont be used since OwnerName isnt null, safe to pass itself
RaiseLocalEvent(uid, ref ev);
}

// ion storms don't get mirrored because thats basically impossible to track
}
}
87 changes: 87 additions & 0 deletions Content.Server/Silicons/Borgs/BorgSwitchableTypeSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using Content.Server.Inventory;
using Content.Server.Radio.Components;
using Content.Shared.Inventory;
using Content.Shared.Silicons.Borgs;
using Content.Shared.Silicons.Borgs.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;

namespace Content.Server.Silicons.Borgs;

/// <summary>
/// Server-side logic for borg type switching. Handles more heavyweight and server-specific switching logic.
/// </summary>
public sealed partial class BorgSwitchableTypeSystem : SharedBorgSwitchableTypeSystem // DeltaV: Made partial
{
[Dependency] private readonly BorgSystem _borgSystem = default!;
[Dependency] private readonly ServerInventorySystem _inventorySystem = default!;

protected override void SelectBorgModule(Entity<BorgSwitchableTypeComponent> ent, ProtoId<BorgTypePrototype> borgType)
{
var prototype = Prototypes.Index(borgType);

// Assign radio channels
string[] radioChannels = [.. ent.Comp.InherentRadioChannels, .. prototype.RadioChannels];
if (TryComp(ent, out IntrinsicRadioTransmitterComponent? transmitter))
transmitter.Channels = [.. radioChannels];

if (TryComp(ent, out ActiveRadioComponent? activeRadio))
activeRadio.Channels = [.. radioChannels];

// Borg transponder for the robotics console
if (TryComp(ent, out BorgTransponderComponent? transponder))
{
_borgSystem.SetTransponderSprite(
(ent.Owner, transponder),
new SpriteSpecifier.Rsi(new ResPath("Mobs/Silicon/chassis.rsi"), prototype.SpriteBodyState));

_borgSystem.SetTransponderName(
(ent.Owner, transponder),
Loc.GetString($"borg-type-{borgType}-transponder"));
}

// Configure modules
if (TryComp(ent, out BorgChassisComponent? chassis))
{
var chassisEnt = (ent.Owner, chassis);
_borgSystem.SetMaxModules(
chassisEnt,
prototype.ExtraModuleCount + prototype.DefaultModules.Length);

_borgSystem.SetModuleWhitelist(chassisEnt, prototype.ModuleWhitelist);

foreach (var module in prototype.DefaultModules)
{
var moduleEntity = Spawn(module);
var borgModule = Comp<BorgModuleComponent>(moduleEntity);
_borgSystem.SetBorgModuleDefault((moduleEntity, borgModule), true);
_borgSystem.InsertModule(chassisEnt, moduleEntity);
}
}

// Begin DeltaV Code: Custom lawset patching
if (prototype.Lawset is {} lawset)
ConfigureLawset(ent, lawset);
// End DeltaV Code

// Configure special components
if (Prototypes.TryIndex(ent.Comp.SelectedBorgType, out var previousPrototype))
{
if (previousPrototype.AddComponents is { } removeComponents)
EntityManager.RemoveComponents(ent, removeComponents);
}

if (prototype.AddComponents is { } addComponents)
{
EntityManager.AddComponents(ent, addComponents);
}

// Configure inventory template (used for hat spacing)
if (TryComp(ent, out InventoryComponent? inventory))
{
_inventorySystem.SetTemplateId((ent.Owner, inventory), prototype.InventoryTemplateId);
}

base.SelectBorgModule(ent, borgType);
}
}
3 changes: 2 additions & 1 deletion Content.Server/Silicons/Laws/SiliconLawSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,10 @@ private void OnEmagLawsAdded(EntityUid uid, SiliconLawProviderComponent componen
component.Lawset = GetLawset(component.Laws);

// Add the first emag law before the others
var name = CompOrNull<EmagSiliconLawComponent>(uid)?.OwnerName ?? Name(args.UserUid); // DeltaV: Reuse emagger name if possible
component.Lawset?.Laws.Insert(0, new SiliconLaw
{
LawString = Loc.GetString("law-emag-custom", ("name", Name(args.UserUid)), ("title", Loc.GetString(component.Lawset.ObeysTo))),
LawString = Loc.GetString("law-emag-custom", ("name", name), ("title", Loc.GetString(component.Lawset.ObeysTo))), // DeltaV: pass name from variable
Order = 0
});

Expand Down
169 changes: 169 additions & 0 deletions Content.Shared/Silicons/Borgs/BorgTypePrototype.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
using Content.Shared.Interaction.Components;
using Content.Shared.Inventory;
using Content.Shared.Radio;
using Content.Shared.Silicons.Borgs.Components;
using Content.Shared.Silicons.Laws; // DeltaV
using Content.Shared.Whitelist;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;

namespace Content.Shared.Silicons.Borgs;

/// <summary>
/// Information for a borg type that can be selected by <see cref="BorgSwitchableTypeComponent"/>.
/// </summary>
/// <seealso cref="SharedBorgSwitchableTypeSystem"/>
[Prototype]
public sealed partial class BorgTypePrototype : IPrototype
{
[ValidatePrototypeId<SoundCollectionPrototype>]
private static readonly ProtoId<SoundCollectionPrototype> DefaultFootsteps = new("FootstepBorg");

[IdDataField]
public required string ID { get; init; }

//
// Description info (name/desc) is configured via localization strings directly.
//

/// <summary>
/// The prototype displayed in the selection menu for this type.
/// </summary>
[DataField]
public required EntProtoId DummyPrototype { get; init; }

//
// Functional information
//

/// <summary>
/// The amount of free module slots this borg type has.
/// </summary>
/// <remarks>
/// This count is on top of the modules specified in <see cref="DefaultModules"/>.
/// </remarks>
/// <seealso cref="BorgChassisComponent.ModuleCount"/>
[DataField]
public int ExtraModuleCount { get; set; } = 0;

/// <summary>
/// The whitelist for borg modules that can be inserted into this borg type.
/// </summary>
/// <seealso cref="BorgChassisComponent.ModuleWhitelist"/>
[DataField]
public EntityWhitelist? ModuleWhitelist { get; set; }

/// <summary>
/// Inventory template used by this borg.
/// </summary>
/// <remarks>
/// This template must be compatible with the normal borg templates,
/// so in practice it can only be used to differentiate the visual position of the slots on the character sprites.
/// </remarks>
/// <seealso cref="InventorySystem.SetTemplateId"/>
[DataField]
public ProtoId<InventoryTemplatePrototype> InventoryTemplateId { get; set; } = "borgShort";

/// <summary>
/// Radio channels that this borg will gain access to from this module.
/// </summary>
/// <remarks>
/// These channels are provided on top of the ones specified in
/// <see cref="BorgSwitchableTypeComponent.InherentRadioChannels"/>.
/// </remarks>
[DataField]
public ProtoId<RadioChannelPrototype>[] RadioChannels = [];

/// <summary>
/// Borg module types that are always available to borgs of this type.
/// </summary>
/// <remarks>
/// These modules still work like modules, although they cannot be removed from the borg.
/// </remarks>
/// <seealso cref="BorgModuleComponent.DefaultModule"/>
[DataField]
public EntProtoId[] DefaultModules = [];

/// <summary>
/// DeltaV: Lawset to use instead of crewsimov.
/// If the chassis is emagged or ion stormed this is ignored.
/// </summary>
[DataField]
public ProtoId<SiliconLawsetPrototype>? Lawset;

/// <summary>
/// Additional components to add to the borg entity when this type is selected.
/// </summary>
[DataField]
public ComponentRegistry? AddComponents { get; set; }

//
// Visual information
//

/// <summary>
/// DeltaV: Components only added on the client.
/// </summary>
[DataField]
public ComponentRegistry? ClientComponents;

/// <summary>
/// The sprite state for the main borg body.
/// </summary>
[DataField]
public string SpriteBodyState { get; set; } = "robot";

/// <summary>
/// An optional movement sprite state for the main borg body.
/// </summary>
[DataField]
public string? SpriteBodyMovementState { get; set; }

/// <summary>
/// Sprite state used to indicate that the borg has a mind in it.
/// </summary>
/// <seealso cref="BorgChassisComponent.HasMindState"/>
[DataField]
public string SpriteHasMindState { get; set; } = "robot_e";

/// <summary>
/// Sprite state used to indicate that the borg has no mind in it.
/// </summary>
/// <seealso cref="BorgChassisComponent.NoMindState"/>
[DataField]
public string SpriteNoMindState { get; set; } = "robot_e_r";

/// <summary>
/// Sprite state used when the borg's flashlight is on.
/// </summary>
[DataField]
public string SpriteToggleLightState { get; set; } = "robot_l";

//
// Minor information
//

/// <summary>
/// String to use on petting success.
/// </summary>
/// <seealso cref="InteractionPopupComponent"/>
[DataField]
public string PetSuccessString { get; set; } = "petting-success-generic-cyborg";

/// <summary>
/// String to use on petting failure.
/// </summary>
/// <seealso cref="InteractionPopupComponent"/>
[DataField]
public string PetFailureString { get; set; } = "petting-failure-generic-cyborg";

//
// Sounds
//

/// <summary>
/// Sound specifier for footstep sounds created by this borg.
/// </summary>
[DataField]
public SoundSpecifier FootstepCollection { get; set; } = new SoundCollectionSpecifier(DefaultFootsteps);
}

0 comments on commit ae025b8

Please sign in to comment.