ports most IPC code
This commit is contained in:
parent
ee6164793b
commit
021dc93627
|
|
@ -23,6 +23,7 @@ using Content.Shared.Station.Components;
|
|||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Content.Shared._EE.Silicon.Components; // Goobstation
|
||||
|
||||
namespace Content.IntegrationTests.Tests.GameRules;
|
||||
|
||||
|
|
@ -229,7 +230,8 @@ public sealed class NukeOpsTest
|
|||
for (var tick = 0; tick < totalTicks; tick += increment)
|
||||
{
|
||||
await pair.RunTicksSync(increment);
|
||||
Assert.That(resp.SuffocationCycles, Is.LessThanOrEqualTo(resp.SuffocationCycleThreshold));
|
||||
if (!entMan.HasComponent<SiliconComponent>(player)) // Goobstation
|
||||
Assert.That(resp.SuffocationCycles, Is.LessThanOrEqualTo(resp.SuffocationCycleThreshold));
|
||||
Assert.That(damage.TotalDamage, Is.EqualTo(FixedPoint2.Zero));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ using Content.Shared.Station;
|
|||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Server._EE.Silicon.IPC; // Goobstation
|
||||
using Content.Shared.Radio.Components; // Goobstation
|
||||
|
||||
namespace Content.Server.Administration.Commands
|
||||
{
|
||||
|
|
@ -163,7 +165,12 @@ namespace Content.Server.Administration.Commands
|
|||
var stationSpawning = entityManager.System<SharedStationSpawningSystem>();
|
||||
stationSpawning.EquipRoleLoadout(target, roleLoadout, jobProto);
|
||||
}
|
||||
|
||||
|
||||
if (entityManager.HasComponent<EncryptionKeyHolderComponent>(target))
|
||||
{
|
||||
var encryption = new InternalEncryptionKeySpawner();
|
||||
encryption.TryInsertEncryptionKey(target, startingGear, entityManager);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ using Content.Shared.Mobs.Systems;
|
|||
using Content.Shared.Power;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Shared._EE.Silicon.Components;
|
||||
|
||||
namespace Content.Server.Bed
|
||||
{
|
||||
|
|
@ -70,7 +71,8 @@ namespace Content.Server.Bed
|
|||
|
||||
foreach (var healedEntity in strapComponent.BuckledEntities)
|
||||
{
|
||||
if (_mobStateSystem.IsDead(healedEntity))
|
||||
if (_mobStateSystem.IsDead(healedEntity)
|
||||
|| HasComp<SiliconComponent>(healedEntity)) // Goobstation
|
||||
continue;
|
||||
|
||||
var damage = bedComponent.Damage;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ using Content.Shared.Mobs.Systems;
|
|||
using Content.Shared.Popups;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Player;
|
||||
using Content.Shared._EE.Silicon.Components;
|
||||
|
||||
namespace Content.Server.Chat;
|
||||
|
||||
|
|
@ -164,7 +165,10 @@ public sealed class SuicideSystem : EntitySystem
|
|||
return;
|
||||
}
|
||||
|
||||
args.DamageType ??= "Bloodloss";
|
||||
if (HasComp<SiliconComponent>(victim)) // Goobstation
|
||||
args.DamageType ??= "Shock";
|
||||
else
|
||||
args.DamageType ??= "Bloodloss";
|
||||
_suicide.ApplyLethalDamage(victim, args.DamageType);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
|||
[ValidatePrototypeId<DamageTypePrototype>]
|
||||
private const string DamageType = "Shock";
|
||||
|
||||
// Multiply and shift the log scale for shock damage.
|
||||
// Yes, this is absurdly small for a reason.
|
||||
public const float ElectrifiedDamagePerWatt = 0.0015f; // Goobstation - This information is allowed to be public, and was needed in BatteryElectrocuteChargeSystem.cs
|
||||
private const float RecursiveDamageMultiplier = 0.75f;
|
||||
private const float RecursiveTimeMultiplier = 0.8f;
|
||||
|
||||
|
|
@ -300,7 +301,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
|||
|| !DoCommonElectrocution(uid, sourceUid, shockDamage, time, refresh, siemensCoefficient, statusEffects))
|
||||
return false;
|
||||
|
||||
RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient), true);
|
||||
RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient, shockDamage), true); // Goobstation
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -350,7 +351,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
|||
electrocutionComponent.Electrocuting = uid;
|
||||
electrocutionComponent.Source = sourceUid;
|
||||
|
||||
RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient), true);
|
||||
RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient, shockDamage), true); // Goobstation
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,4 +15,10 @@ public sealed partial class DeathgaspComponent : Component
|
|||
/// </summary>
|
||||
[DataField("prototype", customTypeSerializer:typeof(PrototypeIdSerializer<EmotePrototype>))]
|
||||
public string Prototype = "DefaultDeathgasp";
|
||||
|
||||
/// <summary>
|
||||
/// Goobstation: Makes sure that the deathgasp is only displayed if the entity went critical before dying
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool NeedsCritical = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ public sealed class DeathgaspSystem: EntitySystem
|
|||
private void OnMobStateChanged(EntityUid uid, DeathgaspComponent component, MobStateChangedEvent args)
|
||||
{
|
||||
// don't deathgasp if they arent going straight from crit to dead
|
||||
if (args.NewMobState != MobState.Dead || args.OldMobState != MobState.Critical)
|
||||
if (component.NeedsCritical // Goobstation
|
||||
&& args.OldMobState != MobState.Critical
|
||||
|| args.NewMobState != MobState.Dead)
|
||||
return;
|
||||
|
||||
Deathgasp(uid, component);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ using Robust.Shared.Player;
|
|||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Server._EE.Silicon.IPC; // Goobstation
|
||||
|
||||
namespace Content.Server.Station.Systems;
|
||||
|
||||
|
|
@ -50,7 +51,7 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
|
|||
[Dependency] private readonly PdaSystem _pdaSystem = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
[Dependency] private readonly InternalEncryptionKeySpawner _internalEncryption = default!; // Goobstation
|
||||
private bool _randomizeCharacters;
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -178,6 +179,7 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
|
|||
{
|
||||
var startingGear = _prototypeManager.Index<StartingGearPrototype>(prototype.StartingGear);
|
||||
EquipStartingGear(entity.Value, startingGear, raiseEvent: false);
|
||||
_internalEncryption.TryInsertEncryptionKey(entity.Value, startingGear, EntityManager); // Goobstation
|
||||
}
|
||||
|
||||
var gearEquippedEv = new StartingGearEquippedEvent(entity.Value);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
namespace Content.Server._EE.Power.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BatteryDrinkerComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Is this drinker allowed to drink batteries not tagged as <see cref="BatteryDrinkSource"/>?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool DrinkAll;
|
||||
|
||||
/// <summary>
|
||||
/// How long it takes to drink from a battery, in seconds.
|
||||
/// Is multiplied by the source.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float DrinkSpeed = 1.5f;
|
||||
|
||||
/// <summary>
|
||||
/// The multiplier for the amount of power to attempt to drink.
|
||||
/// Default amount is 1000
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float DrinkMultiplier = 5f;
|
||||
|
||||
/// <summary>
|
||||
/// The multiplier for how long it takes to drink a non-source battery, if <see cref="DrinkAll"/> is true.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float DrinkAllMultiplier = 2.5f;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using System.Numerics;
|
||||
|
||||
namespace Content.Server._EE.Power.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class RandomBatteryChargeComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The minimum and maximum max charge the battery can have.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Vector2 BatteryMaxMinMax = new(0.85f, 1.15f);
|
||||
|
||||
/// <summary>
|
||||
/// The minimum and maximum current charge the battery can have.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Vector2 BatteryChargeMinMax = new(1f, 1f);
|
||||
|
||||
/// <summary>
|
||||
/// False if the randomized charge of the battery should be a multiple of the preexisting current charge of the battery.
|
||||
/// True if the randomized charge of the battery should be a multiple of the max charge of the battery post max charge randomization.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool BasedOnMaxCharge = true;
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
using System.Linq;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.PowerCell.Components;
|
||||
using Content.Shared._EE.Silicon;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Server._EE.Silicon.Charge;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.PowerCell;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Containers;
|
||||
using Content.Server._EE.Power.Components;
|
||||
using Content.Server._EE.Silicon;
|
||||
|
||||
namespace Content.Server._EE.Power;
|
||||
|
||||
public sealed class BatteryDrinkerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ItemSlotsSystem _slots = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly BatterySystem _battery = default!;
|
||||
[Dependency] private readonly SiliconChargeSystem _silicon = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly PowerCellSystem _powerCell = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<BatteryComponent, GetVerbsEvent<AlternativeVerb>>(AddAltVerb);
|
||||
|
||||
SubscribeLocalEvent<BatteryDrinkerComponent, BatteryDrinkerDoAfterEvent>(OnDoAfter);
|
||||
}
|
||||
|
||||
private void AddAltVerb(EntityUid uid, BatteryComponent batteryComponent, GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract)
|
||||
return;
|
||||
|
||||
if (!TryComp<BatteryDrinkerComponent>(args.User, out var drinkerComp) ||
|
||||
!TestDrinkableBattery(uid, drinkerComp) ||
|
||||
!_silicon.TryGetSiliconBattery(args.User, out var drinkerBattery))
|
||||
return;
|
||||
|
||||
AlternativeVerb verb = new()
|
||||
{
|
||||
Act = () => DrinkBattery(uid, args.User, drinkerComp),
|
||||
Text = Loc.GetString("battery-drinker-verb-drink"),
|
||||
Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/smite.svg.192dpi.png")),
|
||||
};
|
||||
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
private bool TestDrinkableBattery(EntityUid target, BatteryDrinkerComponent drinkerComp)
|
||||
{
|
||||
if (!drinkerComp.DrinkAll && !HasComp<BatteryDrinkerSourceComponent>(target))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void DrinkBattery(EntityUid target, EntityUid user, BatteryDrinkerComponent drinkerComp)
|
||||
{
|
||||
var doAfterTime = drinkerComp.DrinkSpeed;
|
||||
|
||||
if (TryComp<BatteryDrinkerSourceComponent>(target, out var sourceComp))
|
||||
doAfterTime *= sourceComp.DrinkSpeedMulti;
|
||||
else
|
||||
doAfterTime *= drinkerComp.DrinkAllMultiplier;
|
||||
|
||||
var args = new DoAfterArgs(EntityManager, user, doAfterTime, new BatteryDrinkerDoAfterEvent(), user, target) // TODO: Make this doafter loop, once we merge Upstream.
|
||||
{
|
||||
BreakOnDamage = true,
|
||||
BreakOnMove = true,
|
||||
Broadcast = false,
|
||||
DistanceThreshold = 1.35f,
|
||||
RequireCanInteract = true,
|
||||
CancelDuplicate = false
|
||||
};
|
||||
|
||||
_doAfter.TryStartDoAfter(args);
|
||||
}
|
||||
|
||||
private void OnDoAfter(EntityUid uid, BatteryDrinkerComponent drinkerComp, DoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled || args.Target == null)
|
||||
return;
|
||||
|
||||
var source = args.Target.Value;
|
||||
var drinker = uid;
|
||||
var sourceBattery = Comp<BatteryComponent>(source);
|
||||
|
||||
_silicon.TryGetSiliconBattery(drinker, out var drinkerBatteryComponent);
|
||||
|
||||
if (!TryComp(uid, out PowerCellSlotComponent? batterySlot))
|
||||
return;
|
||||
|
||||
var container = _container.GetContainer(uid, batterySlot.CellSlotId);
|
||||
var drinkerBattery = container.ContainedEntities.First();
|
||||
|
||||
TryComp<BatteryDrinkerSourceComponent>(source, out var sourceComp);
|
||||
|
||||
DebugTools.AssertNotNull(drinkerBattery);
|
||||
|
||||
if (drinkerBattery == null)
|
||||
return;
|
||||
|
||||
var amountToDrink = drinkerComp.DrinkMultiplier * 1000;
|
||||
|
||||
amountToDrink = MathF.Min(amountToDrink, sourceBattery.CurrentCharge);
|
||||
amountToDrink = MathF.Min(amountToDrink, drinkerBatteryComponent!.MaxCharge - drinkerBatteryComponent.CurrentCharge);
|
||||
|
||||
if (sourceComp != null && sourceComp.MaxAmount > 0)
|
||||
amountToDrink = MathF.Min(amountToDrink, (float) sourceComp.MaxAmount);
|
||||
|
||||
if (amountToDrink <= 0)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("battery-drinker-empty", ("target", source)), drinker, drinker);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_battery.TryUseCharge(source, amountToDrink))
|
||||
_battery.SetCharge(drinkerBattery, drinkerBatteryComponent.CurrentCharge + amountToDrink, drinkerBatteryComponent);
|
||||
else
|
||||
{
|
||||
_battery.SetCharge(drinkerBattery, sourceBattery.CurrentCharge + drinkerBatteryComponent.CurrentCharge, drinkerBatteryComponent);
|
||||
_battery.SetCharge(source, 0);
|
||||
}
|
||||
|
||||
if (sourceComp != null && sourceComp.DrinkSound != null){
|
||||
_popup.PopupEntity(Loc.GetString("ipc-recharge-tip"), drinker, drinker, PopupType.SmallCaution);
|
||||
_audio.PlayPvs(sourceComp.DrinkSound, source);
|
||||
Spawn("EffectSparks", Transform(source).Coordinates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
using Content.Server.Electrocution;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Shared.Electrocution;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Content.Server._EE.Power.Components;
|
||||
|
||||
namespace Content.Server._EE.Power.Systems;
|
||||
|
||||
public sealed class BatteryElectrocuteChargeSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly BatterySystem _battery = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<BatteryComponent, ElectrocutedEvent>(OnElectrocuted);
|
||||
}
|
||||
|
||||
private void OnElectrocuted(EntityUid uid, BatteryComponent battery, ElectrocutedEvent args)
|
||||
{
|
||||
if (args.ShockDamage == null || args.ShockDamage <= 0)
|
||||
return;
|
||||
|
||||
var charge = Math.Min(args.ShockDamage.Value * args.SiemensCoefficient
|
||||
/ ElectrocutionSystem.ElectrifiedDamagePerWatt * 2,
|
||||
battery.MaxCharge * 0.25f)
|
||||
* _random.NextFloat(0.75f, 1.25f);
|
||||
|
||||
_battery.SetCharge(uid, battery.CurrentCharge + charge);
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("battery-electrocute-charge"), uid, uid);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
using Content.Server.Radio.Components;
|
||||
using Content.Shared.Radio;
|
||||
using Content.Shared.Radio.Components;
|
||||
|
||||
namespace Content.Server._EE.Radio;
|
||||
|
||||
public sealed class IntrinsicRadioKeySystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<IntrinsicRadioTransmitterComponent, EncryptionChannelsChangedEvent>(OnTransmitterChannelsChanged);
|
||||
SubscribeLocalEvent<ActiveRadioComponent, EncryptionChannelsChangedEvent>(OnReceiverChannelsChanged);
|
||||
}
|
||||
|
||||
private void OnTransmitterChannelsChanged(EntityUid uid, IntrinsicRadioTransmitterComponent component, EncryptionChannelsChangedEvent args)
|
||||
{
|
||||
UpdateChannels(uid, args.Component, ref component.Channels);
|
||||
}
|
||||
|
||||
private void OnReceiverChannelsChanged(EntityUid uid, ActiveRadioComponent component, EncryptionChannelsChangedEvent args)
|
||||
{
|
||||
UpdateChannels(uid, args.Component, ref component.Channels);
|
||||
}
|
||||
|
||||
private void UpdateChannels(EntityUid _, EncryptionKeyHolderComponent keyHolderComp, ref HashSet<string> channels)
|
||||
{
|
||||
channels.Clear();
|
||||
channels.UnionWith(keyHolderComp.Channels);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace Content.Server._EE.Silicons.BatteryLocking;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BatterySlotRequiresLockComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public string ItemSlot = string.Empty;
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.Lock;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared._EE.Silicon.Components;
|
||||
using Content.Shared.IdentityManagement;
|
||||
|
||||
namespace Content.Server._EE.Silicons.BatteryLocking;
|
||||
|
||||
public sealed class BatterySlotRequiresLockSystem : EntitySystem
|
||||
|
||||
{
|
||||
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<BatterySlotRequiresLockComponent, LockToggledEvent>(LockToggled);
|
||||
SubscribeLocalEvent<BatterySlotRequiresLockComponent, LockToggleAttemptEvent>(LockToggleAttempted);
|
||||
|
||||
}
|
||||
private void LockToggled(EntityUid uid, BatterySlotRequiresLockComponent component, LockToggledEvent args)
|
||||
{
|
||||
if (!TryComp<LockComponent>(uid, out var lockComp)
|
||||
|| !TryComp<ItemSlotsComponent>(uid, out var itemslots)
|
||||
|| !_itemSlotsSystem.TryGetSlot(uid, component.ItemSlot, out var slot, itemslots))
|
||||
return;
|
||||
|
||||
_itemSlotsSystem.SetLock(uid, slot, lockComp.Locked, itemslots);
|
||||
}
|
||||
|
||||
private void LockToggleAttempted(EntityUid uid, BatterySlotRequiresLockComponent component, LockToggleAttemptEvent args)
|
||||
{
|
||||
if (args.User == uid || !HasComp<SiliconComponent>(uid))
|
||||
return;
|
||||
|
||||
_popupSystem.PopupEntity(Loc.GetString("batteryslotrequireslock-component-alert-owner", ("user", Identity.Entity(args.User, EntityManager))), uid, uid, PopupType.Large);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
namespace Content.Server._EE.Silicon.BlindHealing;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BlindHealingComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public int DoAfterDelay = 3;
|
||||
|
||||
/// <summary>
|
||||
/// A multiplier that will be applied to the above if an entity is repairing themselves.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float SelfHealPenalty = 3f;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not an entity is allowed to repair itself.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool AllowSelfHeal = true;
|
||||
|
||||
[DataField(required: true)]
|
||||
public List<string> DamageContainers;
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Cargo.Components;
|
||||
using Content.Server.Stack;
|
||||
using Content.Shared._EE.Silicon.BlindHealing;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Eye.Blinding.Components;
|
||||
using Content.Shared.Eye.Blinding.Systems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Stacks;
|
||||
|
||||
namespace Content.Server._EE.Silicon.BlindHealing;
|
||||
|
||||
public sealed class BlindHealingSystem : SharedBlindHealingSystem
|
||||
{
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly BlindableSystem _blindableSystem = default!;
|
||||
[Dependency] private readonly StackSystem _stackSystem = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<BlindHealingComponent, UseInHandEvent>(OnUse);
|
||||
SubscribeLocalEvent<BlindHealingComponent, AfterInteractEvent>(OnInteract);
|
||||
SubscribeLocalEvent<BlindHealingComponent, HealingDoAfterEvent>(OnHealingFinished);
|
||||
}
|
||||
|
||||
private void OnHealingFinished(EntityUid uid, BlindHealingComponent component, HealingDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled || args.Target == null
|
||||
|| !TryComp<BlindableComponent>(args.Target, out var blindComp)
|
||||
|| blindComp is { EyeDamage: 0 })
|
||||
return;
|
||||
|
||||
if (TryComp<StackComponent>(uid, out var stackComponent)
|
||||
&& TryComp<StackPriceComponent>(uid, out var stackPrice))
|
||||
_stackSystem.SetCount(uid, (int) (_stackSystem.GetCount(uid, stackComponent) - stackPrice.Price), stackComponent);
|
||||
|
||||
_blindableSystem.AdjustEyeDamage((args.Target.Value, blindComp), -blindComp.EyeDamage);
|
||||
|
||||
_adminLogger.Add(LogType.Healed, $"{ToPrettyString(args.User):user} repaired {ToPrettyString(uid):target}'s vision");
|
||||
|
||||
var str = Loc.GetString("comp-repairable-repair",
|
||||
("target", uid),
|
||||
("tool", args.Used!));
|
||||
_popup.PopupEntity(str, uid, args.User);
|
||||
|
||||
}
|
||||
|
||||
private bool TryHealBlindness(EntityUid uid, EntityUid user, EntityUid target, float delay)
|
||||
{
|
||||
var doAfterEventArgs =
|
||||
new DoAfterArgs(EntityManager, user, delay, new HealingDoAfterEvent(), uid, target: target, used: uid)
|
||||
{
|
||||
NeedHand = true,
|
||||
BreakOnMove = true,
|
||||
BreakOnWeightlessMove = false,
|
||||
};
|
||||
|
||||
_doAfter.TryStartDoAfter(doAfterEventArgs);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnInteract(EntityUid uid, BlindHealingComponent component, ref AfterInteractEvent args)
|
||||
{
|
||||
|
||||
if (args.Handled
|
||||
|| !TryComp<DamageableComponent>(args.User, out var damageable)
|
||||
|| damageable.DamageContainerID != null && !component.DamageContainers.Contains(damageable.DamageContainerID)
|
||||
|| !TryComp<BlindableComponent>(args.User, out var blindcomp)
|
||||
|| blindcomp.EyeDamage == 0
|
||||
|| args.User == args.Target && !component.AllowSelfHeal)
|
||||
return;
|
||||
|
||||
TryHealBlindness(uid, args.User, args.User,
|
||||
args.User == args.Target
|
||||
? component.DoAfterDelay * component.SelfHealPenalty
|
||||
: component.DoAfterDelay);
|
||||
}
|
||||
|
||||
private void OnUse(EntityUid uid, BlindHealingComponent component, ref UseInHandEvent args)
|
||||
{
|
||||
if (args.Handled
|
||||
|| !TryComp<DamageableComponent>(args.User, out var damageable)
|
||||
|| damageable.DamageContainerID != null && !component.DamageContainers.Contains(damageable.DamageContainerID)
|
||||
|| !TryComp<BlindableComponent>(args.User, out var blindcomp)
|
||||
|| blindcomp.EyeDamage == 0
|
||||
|| !component.AllowSelfHeal)
|
||||
return;
|
||||
|
||||
TryHealBlindness(uid, args.User, args.User,
|
||||
component.DoAfterDelay * component.SelfHealPenalty);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server._EE.Silicon.Charge;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BatteryDrinkerSourceComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The max amount of power this source can provide in one sip.
|
||||
/// No limit if null.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int? MaxAmount = null;
|
||||
|
||||
/// <summary>
|
||||
/// The multiplier for the drink speed.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float DrinkSpeedMulti = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// The sound to play when the battery gets drunk from.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public SoundSpecifier? DrinkSound = new SoundCollectionSpecifier("sparks");
|
||||
}
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
using Robust.Shared.Random;
|
||||
using Content.Shared._EE.Silicon.Components;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Server.Temperature.Components;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared._EE.Silicon.Systems;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Shared.Mind.Components;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.PowerCell;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.PowerCell.Components;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Server._EE.Silicon.Death;
|
||||
using Content.Server._EE.Power.Components;
|
||||
|
||||
namespace Content.Server._EE.Silicon.Charge;
|
||||
|
||||
public sealed class SiliconChargeSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly FlammableSystem _flammable = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _moveMod = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
[Dependency] private readonly PowerCellSystem _powerCell = default!;
|
||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SiliconComponent, ComponentStartup>(OnSiliconStartup);
|
||||
}
|
||||
|
||||
public bool TryGetSiliconBattery(EntityUid silicon, [NotNullWhen(true)] out BatteryComponent? batteryComp)
|
||||
{
|
||||
batteryComp = null;
|
||||
if (!HasComp<SiliconComponent>(silicon))
|
||||
return false;
|
||||
|
||||
|
||||
// try get a battery directly on the inserted entity
|
||||
if (TryComp(silicon, out batteryComp)
|
||||
|| _powerCell.TryGetBatteryFromSlot(silicon, out batteryComp))
|
||||
return true;
|
||||
|
||||
|
||||
//DebugTools.Assert("SiliconComponent does not contain Battery");
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnSiliconStartup(EntityUid uid, SiliconComponent component, ComponentStartup args)
|
||||
{
|
||||
if (!HasComp<PowerCellSlotComponent>(uid))
|
||||
return;
|
||||
|
||||
if (component.EntityType.GetType() != typeof(SiliconType))
|
||||
DebugTools.Assert("SiliconComponent.EntityType is not a SiliconType enum.");
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
// For each siliconComp entity with a battery component, drain their charge.
|
||||
var query = EntityQueryEnumerator<SiliconComponent>();
|
||||
while (query.MoveNext(out var silicon, out var siliconComp))
|
||||
{
|
||||
if (_mobState.IsDead(silicon)
|
||||
|| !siliconComp.BatteryPowered)
|
||||
continue;
|
||||
|
||||
// Check if the Silicon is an NPC, and if so, follow the delay as specified in the CVAR.
|
||||
if (siliconComp.EntityType.Equals(SiliconType.Npc))
|
||||
{
|
||||
var updateTime = _config.GetCVar(CCVars.SiliconNpcUpdateTime);
|
||||
if (_timing.CurTime - siliconComp.LastDrainTime < TimeSpan.FromSeconds(updateTime))
|
||||
continue;
|
||||
|
||||
siliconComp.LastDrainTime = _timing.CurTime;
|
||||
}
|
||||
|
||||
// If you can't find a battery, set the indicator and skip it.
|
||||
if (!TryGetSiliconBattery(silicon, out var batteryComp))
|
||||
{
|
||||
UpdateChargeState(silicon, 0, siliconComp);
|
||||
if (_alerts.IsShowingAlert(silicon, siliconComp.BatteryAlert))
|
||||
{
|
||||
_alerts.ClearAlert(silicon, siliconComp.BatteryAlert);
|
||||
_alerts.ShowAlert(silicon, siliconComp.NoBatteryAlert);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the silicon ghosted or is SSD while still being powered, skip it.
|
||||
if (TryComp<MindContainerComponent>(silicon, out var mindContComp)
|
||||
&& !mindContComp.HasMind)
|
||||
continue;
|
||||
|
||||
var drainRate = siliconComp.DrainPerSecond;
|
||||
|
||||
// All multipliers will be subtracted by 1, and then added together, and then multiplied by the drain rate. This is then added to the base drain rate.
|
||||
// This is to stop exponential increases, while still allowing for less-than-one multipliers.
|
||||
var drainRateFinalAddi = 0f;
|
||||
|
||||
// TODO: Devise a method of adding multis where other systems can alter the drain rate.
|
||||
// Maybe use something similar to refreshmovespeedmodifiers, where it's stored in the component.
|
||||
// Maybe it doesn't matter, and stuff should just use static drain?
|
||||
if (!siliconComp.EntityType.Equals(SiliconType.Npc)) // Don't bother checking heat if it's an NPC. It's a waste of time, and it'd be delayed due to the update time.
|
||||
drainRateFinalAddi += SiliconHeatEffects(silicon, siliconComp, frameTime) - 1; // This will need to be changed at some point if we allow external batteries, since the heat of the Silicon might not be applicable.
|
||||
|
||||
// Ensures that the drain rate is at least 10% of normal,
|
||||
// and would allow at least 4 minutes of life with a max charge, to prevent cheese.
|
||||
drainRate += Math.Clamp(drainRateFinalAddi, drainRate * -0.9f, batteryComp.MaxCharge / 240);
|
||||
|
||||
// Drain the battery.
|
||||
_powerCell.TryUseCharge(silicon, frameTime * drainRate);
|
||||
|
||||
// Figure out the current state of the Silicon.
|
||||
var chargePercent = (short) MathF.Round(batteryComp.CurrentCharge / batteryComp.MaxCharge * 10f);
|
||||
|
||||
UpdateChargeState(silicon, chargePercent, siliconComp);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if anything needs to be updated, and updates it.
|
||||
/// </summary>
|
||||
public void UpdateChargeState(EntityUid uid, short chargePercent, SiliconComponent component)
|
||||
{
|
||||
component.ChargeState = chargePercent;
|
||||
|
||||
RaiseLocalEvent(uid, new SiliconChargeStateUpdateEvent(chargePercent));
|
||||
|
||||
_moveMod.RefreshMovementSpeedModifiers(uid);
|
||||
|
||||
// If the battery was replaced and the no battery indicator is showing, replace the indicator
|
||||
if (_alerts.IsShowingAlert(uid, component.NoBatteryAlert) && chargePercent != 0)
|
||||
{
|
||||
_alerts.ClearAlert(uid, component.NoBatteryAlert);
|
||||
_alerts.ShowAlert(uid, component.BatteryAlert, chargePercent);
|
||||
}
|
||||
}
|
||||
|
||||
private float SiliconHeatEffects(EntityUid silicon, SiliconComponent siliconComp, float frameTime)
|
||||
{
|
||||
if (!TryComp<TemperatureComponent>(silicon, out var temperComp)
|
||||
|| !TryComp<ThermalRegulatorComponent>(silicon, out var thermalComp))
|
||||
return 0;
|
||||
|
||||
// If the Silicon is hot, drain the battery faster, if it's cold, drain it slower, capped.
|
||||
var upperThresh = thermalComp.NormalBodyTemperature + thermalComp.ThermalRegulationTemperatureThreshold;
|
||||
var upperThreshHalf = thermalComp.NormalBodyTemperature + thermalComp.ThermalRegulationTemperatureThreshold * 0.5f;
|
||||
|
||||
// Check if the silicon is in a hot environment.
|
||||
if (temperComp.CurrentTemperature > upperThreshHalf)
|
||||
{
|
||||
// Divide the current temp by the max comfortable temp capped to 4, then add that to the multiplier.
|
||||
var hotTempMulti = Math.Min(temperComp.CurrentTemperature / upperThreshHalf, 4);
|
||||
|
||||
// If the silicon is hot enough, it has a chance to catch fire.
|
||||
|
||||
siliconComp.OverheatAccumulator += frameTime;
|
||||
if (!(siliconComp.OverheatAccumulator >= 5))
|
||||
return hotTempMulti;
|
||||
|
||||
siliconComp.OverheatAccumulator -= 5;
|
||||
|
||||
if (!EntityManager.TryGetComponent<FlammableComponent>(silicon, out var flamComp)
|
||||
|| flamComp is { OnFire: true }
|
||||
|| !(temperComp.CurrentTemperature > temperComp.HeatDamageThreshold))
|
||||
return hotTempMulti;
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("silicon-overheating"), silicon, silicon, PopupType.MediumCaution);
|
||||
if (!_random.Prob(Math.Clamp(temperComp.CurrentTemperature / (upperThresh * 5), 0.001f, 0.9f)))
|
||||
return hotTempMulti;
|
||||
|
||||
_flammable.AdjustFireStacks(silicon, Math.Clamp(siliconComp.FireStackMultiplier, -10, 10), flamComp);
|
||||
_flammable.Ignite(silicon, silicon, flamComp);
|
||||
return hotTempMulti;
|
||||
}
|
||||
|
||||
// Check if the silicon is in a cold environment.
|
||||
if (temperComp.CurrentTemperature < thermalComp.NormalBodyTemperature)
|
||||
return 0.5f + temperComp.CurrentTemperature / thermalComp.NormalBodyTemperature * 0.5f;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Lightning;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.PowerCell;
|
||||
using Content.Server._EE.Silicon.Charge;
|
||||
using Content.Shared._EE.Silicon.DeadStartupButton;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Electrocution;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._EE.Silicon.DeadStartupButton;
|
||||
|
||||
public sealed class DeadStartupButtonSystem : SharedDeadStartupButtonSystem
|
||||
{
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||
[Dependency] private readonly LightningSystem _lightning = default!;
|
||||
[Dependency] private readonly SiliconChargeSystem _siliconChargeSystem = default!;
|
||||
[Dependency] private readonly PowerCellSystem _powerCell = default!;
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<DeadStartupButtonComponent, OnDoAfterButtonPressedEvent>(OnDoAfter);
|
||||
SubscribeLocalEvent<DeadStartupButtonComponent, ElectrocutedEvent>(OnElectrocuted);
|
||||
SubscribeLocalEvent<DeadStartupButtonComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||
|
||||
}
|
||||
|
||||
private void OnDoAfter(EntityUid uid, DeadStartupButtonComponent comp, OnDoAfterButtonPressedEvent args)
|
||||
{
|
||||
if (args.Handled || args.Cancelled
|
||||
|| !TryComp<MobStateComponent>(uid, out var mobStateComponent)
|
||||
|| !_mobState.IsDead(uid, mobStateComponent)
|
||||
|| !TryComp<MobThresholdsComponent>(uid, out var mobThresholdsComponent)
|
||||
|| !TryComp<DamageableComponent>(uid, out var damageable)
|
||||
|| !_mobThreshold.TryGetThresholdForState(uid, MobState.Critical, out var criticalThreshold, mobThresholdsComponent))
|
||||
return;
|
||||
|
||||
if (damageable.TotalDamage < criticalThreshold)
|
||||
_mobState.ChangeMobState(uid, MobState.Alive, mobStateComponent);
|
||||
else
|
||||
{
|
||||
_audio.PlayPvs(comp.BuzzSound, uid, AudioHelpers.WithVariation(0.05f, _robustRandom));
|
||||
_popup.PopupEntity(Loc.GetString("dead-startup-system-reboot-failed", ("target", MetaData(uid).EntityName)), uid);
|
||||
Spawn("EffectSparks", Transform(uid).Coordinates);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnElectrocuted(EntityUid uid, DeadStartupButtonComponent comp, ElectrocutedEvent args)
|
||||
{
|
||||
if (!TryComp<MobStateComponent>(uid, out var mobStateComponent)
|
||||
|| !_mobState.IsDead(uid, mobStateComponent)
|
||||
|| !_siliconChargeSystem.TryGetSiliconBattery(uid, out var bateria)
|
||||
|| bateria.CurrentCharge <= 0)
|
||||
return;
|
||||
|
||||
_lightning.ShootRandomLightnings(uid, 2, 4);
|
||||
_powerCell.TryUseCharge(uid, bateria.CurrentCharge);
|
||||
|
||||
}
|
||||
|
||||
private void OnMobStateChanged(EntityUid uid, DeadStartupButtonComponent comp, MobStateChangedEvent args)
|
||||
{
|
||||
if (args.NewMobState != MobState.Alive)
|
||||
return;
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("dead-startup-system-reboot-success", ("target", MetaData(uid).EntityName)), uid);
|
||||
_audio.PlayPvs(comp.Sound, uid);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
namespace Content.Server._EE.Silicon.Death;
|
||||
|
||||
/// <summary>
|
||||
/// Marks a Silicon as becoming incapacitated when they run out of battery charge.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Uses the Silicon System's charge states to do so, so make sure they're a battery powered Silicon.
|
||||
/// </remarks>
|
||||
[RegisterComponent]
|
||||
public sealed partial class SiliconDownOnDeadComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Is this Silicon currently dead?
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public bool Dead;
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
using Content.Server.Power.Components;
|
||||
using Content.Shared._EE.Silicon.Systems;
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Server._EE.Silicon.Charge;
|
||||
using Content.Server._EE.Power.Components;
|
||||
using Content.Server.Humanoid;
|
||||
using Content.Shared.Humanoid;
|
||||
|
||||
namespace Content.Server._EE.Silicon.Death;
|
||||
|
||||
public sealed class SiliconDeathSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SleepingSystem _sleep = default!;
|
||||
[Dependency] private readonly SiliconChargeSystem _silicon = default!;
|
||||
[Dependency] private readonly HumanoidAppearanceSystem _humanoidAppearanceSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SiliconDownOnDeadComponent, SiliconChargeStateUpdateEvent>(OnSiliconChargeStateUpdate);
|
||||
}
|
||||
|
||||
private void OnSiliconChargeStateUpdate(EntityUid uid, SiliconDownOnDeadComponent siliconDeadComp, SiliconChargeStateUpdateEvent args)
|
||||
{
|
||||
if (!_silicon.TryGetSiliconBattery(uid, out var batteryComp))
|
||||
{
|
||||
SiliconDead(uid, siliconDeadComp, batteryComp, uid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.ChargePercent == 0 && siliconDeadComp.Dead)
|
||||
return;
|
||||
|
||||
if (args.ChargePercent == 0 && !siliconDeadComp.Dead)
|
||||
SiliconDead(uid, siliconDeadComp, batteryComp, uid);
|
||||
else if (args.ChargePercent != 0 && siliconDeadComp.Dead)
|
||||
SiliconUnDead(uid, siliconDeadComp, batteryComp, uid);
|
||||
}
|
||||
|
||||
private void SiliconDead(EntityUid uid, SiliconDownOnDeadComponent siliconDeadComp, BatteryComponent? batteryComp, EntityUid batteryUid)
|
||||
{
|
||||
var deadEvent = new SiliconChargeDyingEvent(uid, batteryComp, batteryUid);
|
||||
RaiseLocalEvent(uid, deadEvent);
|
||||
|
||||
if (deadEvent.Cancelled)
|
||||
return;
|
||||
|
||||
EntityManager.EnsureComponent<SleepingComponent>(uid);
|
||||
EntityManager.EnsureComponent<ForcedSleepingComponent>(uid);
|
||||
|
||||
if (TryComp(uid, out HumanoidAppearanceComponent? humanoidAppearanceComponent))
|
||||
{
|
||||
var layers = HumanoidVisualLayersExtension.Sublayers(HumanoidVisualLayers.HeadSide);
|
||||
_humanoidAppearanceSystem.SetLayersVisibility(uid, layers, false, true, humanoidAppearanceComponent);
|
||||
}
|
||||
|
||||
siliconDeadComp.Dead = true;
|
||||
|
||||
RaiseLocalEvent(uid, new SiliconChargeDeathEvent(uid, batteryComp, batteryUid));
|
||||
}
|
||||
|
||||
private void SiliconUnDead(EntityUid uid, SiliconDownOnDeadComponent siliconDeadComp, BatteryComponent? batteryComp, EntityUid batteryUid)
|
||||
{
|
||||
RemComp<ForcedSleepingComponent>(uid);
|
||||
_sleep.TryWaking(uid, true, null);
|
||||
|
||||
siliconDeadComp.Dead = false;
|
||||
|
||||
RaiseLocalEvent(uid, new SiliconChargeAliveEvent(uid, batteryComp, batteryUid));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A cancellable event raised when a Silicon is about to go down due to charge.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This probably shouldn't be modified unless you intend to fill the Silicon's battery,
|
||||
/// as otherwise it'll just be triggered again next frame.
|
||||
/// </remarks>
|
||||
public sealed class SiliconChargeDyingEvent : CancellableEntityEventArgs
|
||||
{
|
||||
public EntityUid SiliconUid { get; }
|
||||
public BatteryComponent? BatteryComp { get; }
|
||||
public EntityUid BatteryUid { get; }
|
||||
|
||||
public SiliconChargeDyingEvent(EntityUid siliconUid, BatteryComponent? batteryComp, EntityUid batteryUid)
|
||||
{
|
||||
SiliconUid = siliconUid;
|
||||
BatteryComp = batteryComp;
|
||||
BatteryUid = batteryUid;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An event raised after a Silicon has gone down due to charge.
|
||||
/// </summary>
|
||||
public sealed class SiliconChargeDeathEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid SiliconUid { get; }
|
||||
public BatteryComponent? BatteryComp { get; }
|
||||
public EntityUid BatteryUid { get; }
|
||||
|
||||
public SiliconChargeDeathEvent(EntityUid siliconUid, BatteryComponent? batteryComp, EntityUid batteryUid)
|
||||
{
|
||||
SiliconUid = siliconUid;
|
||||
BatteryComp = batteryComp;
|
||||
BatteryUid = batteryUid;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An event raised after a Silicon has reawoken due to an increase in charge.
|
||||
/// </summary>
|
||||
public sealed class SiliconChargeAliveEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid SiliconUid { get; }
|
||||
public BatteryComponent? BatteryComp { get; }
|
||||
public EntityUid BatteryUid { get; }
|
||||
|
||||
public SiliconChargeAliveEvent(EntityUid siliconUid, BatteryComponent? batteryComp, EntityUid batteryUid)
|
||||
{
|
||||
SiliconUid = siliconUid;
|
||||
BatteryComp = batteryComp;
|
||||
BatteryUid = batteryUid;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
using Content.Server.Popups;
|
||||
using Content.Shared._EE.Silicon.EmitBuzzWhileDamaged;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Content.Shared.Mobs.Components;
|
||||
|
||||
namespace Content.Server._EE.Silicon.EmitBuzzOnCrit;
|
||||
|
||||
/// <summary>
|
||||
/// This handles the buzzing popup and sound of a silicon based race when it is pretty damaged.
|
||||
/// </summary>
|
||||
public sealed class EmitBuzzWhileDamagedSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<EmitBuzzWhileDamagedComponent, MobStateComponent, MobThresholdsComponent, DamageableComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var emitBuzzOnCritComponent, out var mobStateComponent, out var thresholdsComponent, out var damageableComponent))
|
||||
{
|
||||
|
||||
if (_mobState.IsDead(uid, mobStateComponent)
|
||||
|| !_mobThreshold.TryGetThresholdForState(uid, MobState.Critical, out var threshold, thresholdsComponent)
|
||||
|| damageableComponent.TotalDamage < threshold / 2)
|
||||
continue;
|
||||
|
||||
emitBuzzOnCritComponent.AccumulatedFrametime += frameTime;
|
||||
|
||||
if (emitBuzzOnCritComponent.AccumulatedFrametime < emitBuzzOnCritComponent.CycleDelay)
|
||||
continue;
|
||||
|
||||
emitBuzzOnCritComponent.AccumulatedFrametime -= emitBuzzOnCritComponent.CycleDelay;
|
||||
|
||||
if (_gameTiming.CurTime <= emitBuzzOnCritComponent.LastBuzzPopupTime + emitBuzzOnCritComponent.BuzzPopupCooldown)
|
||||
continue;
|
||||
|
||||
// Start buzzing
|
||||
emitBuzzOnCritComponent.LastBuzzPopupTime = _gameTiming.CurTime;
|
||||
_popupSystem.PopupEntity(Loc.GetString("silicon-behavior-buzz"), uid);
|
||||
Spawn("EffectSparks", Transform(uid).Coordinates);
|
||||
_audio.PlayPvs(emitBuzzOnCritComponent.Sound, uid, AudioHelpers.WithVariation(0.05f, _robustRandom));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
namespace Content.Server._EE.Silicon.EncryptionHolderRequiresLock;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class EncryptionHolderRequiresLockComponent : Component
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
using Content.Shared.Lock;
|
||||
using Content.Shared.Radio.Components;
|
||||
using Content.Shared.Radio.EntitySystems;
|
||||
|
||||
namespace Content.Server._EE.Silicon.EncryptionHolderRequiresLock;
|
||||
|
||||
public sealed class EncryptionHolderRequiresLockSystem : EntitySystem
|
||||
|
||||
{
|
||||
[Dependency] private readonly EncryptionKeySystem _encryptionKeySystem = default!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<EncryptionHolderRequiresLockComponent, LockToggledEvent>(LockToggled);
|
||||
|
||||
}
|
||||
private void LockToggled(EntityUid uid, EncryptionHolderRequiresLockComponent component, LockToggledEvent args)
|
||||
{
|
||||
if (!TryComp<LockComponent>(uid, out var lockComp)
|
||||
|| !TryComp<EncryptionKeyHolderComponent>(uid, out var keyHolder))
|
||||
return;
|
||||
|
||||
keyHolder.KeysUnlocked = !lockComp.Locked;
|
||||
_encryptionKeySystem.UpdateChannels(uid, keyHolder);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
using Content.Shared.Roles;
|
||||
using Content.Shared.Radio.Components;
|
||||
using Content.Shared.Containers;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
namespace Content.Server._EE.Silicon.IPC;
|
||||
public sealed partial class InternalEncryptionKeySpawner : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
public void TryInsertEncryptionKey(EntityUid target, StartingGearPrototype startingGear, IEntityManager entityManager)
|
||||
{
|
||||
if (!TryComp<EncryptionKeyHolderComponent>(target, out var keyHolderComp)
|
||||
|| !startingGear.Equipment.TryGetValue("ears", out var earEquipString)
|
||||
|| string.IsNullOrEmpty(earEquipString))
|
||||
return;
|
||||
|
||||
var earEntity = entityManager.SpawnEntity(earEquipString, entityManager.GetComponent<TransformComponent>(target).Coordinates);
|
||||
if (!entityManager.HasComponent<EncryptionKeyHolderComponent>(earEntity)
|
||||
|| !entityManager.TryGetComponent<ContainerFillComponent>(earEntity, out var fillComp)
|
||||
|| !fillComp.Containers.TryGetValue(EncryptionKeyHolderComponent.KeyContainerName, out var defaultKeys))
|
||||
return;
|
||||
|
||||
_container.CleanContainer(keyHolderComp.KeyContainer);
|
||||
|
||||
foreach (var key in defaultKeys)
|
||||
entityManager.SpawnInContainerOrDrop(key, target, keyHolderComp.KeyContainer.ID, out _);
|
||||
|
||||
entityManager.QueueDeleteEntity(earEntity);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server._EE.Silicon;
|
||||
|
||||
/// <summary>
|
||||
/// Applies a <see cref="SpamEmitSoundComponent"/> to a Silicon when its battery is drained, and removes it when it's not.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class SiliconEmitSoundOnDrainedComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public SoundSpecifier Sound = default!;
|
||||
|
||||
[DataField]
|
||||
public TimeSpan MinInterval = TimeSpan.FromSeconds(8);
|
||||
|
||||
[DataField]
|
||||
public TimeSpan MaxInterval = TimeSpan.FromSeconds(15);
|
||||
|
||||
[DataField]
|
||||
public float PlayChance = 1f;
|
||||
|
||||
[DataField]
|
||||
public string? PopUp;
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
using Content.Server._EE.Silicon.Death;
|
||||
using Content.Shared.Sound.Components;
|
||||
using Content.Server.Sound;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared._EE.Silicon.Systems;
|
||||
|
||||
namespace Content.Server._EE.Silicon;
|
||||
|
||||
public sealed class EmitSoundOnCritSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly EmitSoundSystem _emitSound = default!;
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<SiliconEmitSoundOnDrainedComponent, SiliconChargeDeathEvent>(OnDeath);
|
||||
SubscribeLocalEvent<SiliconEmitSoundOnDrainedComponent, SiliconChargeAliveEvent>(OnAlive);
|
||||
SubscribeLocalEvent<SiliconEmitSoundOnDrainedComponent, MobStateChangedEvent>(OnStateChange);
|
||||
}
|
||||
|
||||
private void OnDeath(EntityUid uid, SiliconEmitSoundOnDrainedComponent component, SiliconChargeDeathEvent args)
|
||||
{
|
||||
var spamComp = EnsureComp<SpamEmitSoundComponent>(uid);
|
||||
|
||||
spamComp.MinInterval = component.MinInterval;
|
||||
spamComp.MaxInterval = component.MaxInterval;
|
||||
spamComp.PopUp = component.PopUp;
|
||||
spamComp.Sound = component.Sound;
|
||||
_emitSound.SetEnabled((uid, spamComp), true);
|
||||
}
|
||||
|
||||
private void OnAlive(EntityUid uid, SiliconEmitSoundOnDrainedComponent component, SiliconChargeAliveEvent args)
|
||||
{
|
||||
RemComp<SpamEmitSoundComponent>(uid); // This component is bad and I don't feel like making a janky work around because of it.
|
||||
// If you give something the SiliconEmitSoundOnDrainedComponent, know that it can't have the SpamEmitSoundComponent, and any other systems that play with it will just be broken.
|
||||
}
|
||||
|
||||
public void OnStateChange(EntityUid uid, SiliconEmitSoundOnDrainedComponent component, MobStateChangedEvent args)
|
||||
{
|
||||
if (args.NewMobState != MobState.Dead)
|
||||
return;
|
||||
|
||||
RemComp<SpamEmitSoundComponent>(uid);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
using Content.Shared.Damage;
|
||||
using Content.Shared.Tools;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server._EE.Silicon.WeldingHealable
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed partial class WeldingHealableComponent : Component { }
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
using Content.Server._EE.Silicon.WeldingHealing;
|
||||
using Content.Shared.Tools.Components;
|
||||
using Content.Shared._EE.Silicon.WeldingHealing;
|
||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Tools;
|
||||
using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem;
|
||||
|
||||
namespace Content.Server._EE.Silicon.WeldingHealable;
|
||||
|
||||
public sealed class WeldingHealableSystem : SharedWeldingHealableSystem
|
||||
{
|
||||
[Dependency] private readonly SharedToolSystem _toolSystem = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<WeldingHealableComponent, InteractUsingEvent>(Repair);
|
||||
SubscribeLocalEvent<WeldingHealableComponent, SiliconRepairFinishedEvent>(OnRepairFinished);
|
||||
}
|
||||
|
||||
private void OnRepairFinished(EntityUid uid, WeldingHealableComponent healableComponent, SiliconRepairFinishedEvent args)
|
||||
{
|
||||
if (args.Cancelled || args.Used == null
|
||||
|| !TryComp<DamageableComponent>(args.Target, out var damageable)
|
||||
|| !TryComp<WeldingHealingComponent>(args.Used, out var component)
|
||||
|| damageable.DamageContainerID is null
|
||||
|| !component.DamageContainers.Contains(damageable.DamageContainerID)
|
||||
|| !HasDamage(damageable, component)
|
||||
|| !TryComp<WelderComponent>(args.Used, out var welder)
|
||||
|| !TryComp<SolutionContainerManagerComponent>(args.Used, out var solutionContainer)
|
||||
|| !_solutionContainer.TryGetSolution(((EntityUid) args.Used, solutionContainer), welder.FuelSolutionName, out var solution))
|
||||
return;
|
||||
|
||||
_damageableSystem.TryChangeDamage(uid, component.Damage, true, false, origin: args.User);
|
||||
|
||||
_solutionContainer.RemoveReagent(solution.Value, welder.FuelReagent, component.FuelCost);
|
||||
|
||||
var str = Loc.GetString("comp-repairable-repair",
|
||||
("target", uid),
|
||||
("tool", args.Used!));
|
||||
_popup.PopupEntity(str, uid, args.User);
|
||||
|
||||
if (!args.Used.HasValue)
|
||||
return;
|
||||
|
||||
args.Handled = _toolSystem.UseTool
|
||||
(args.Used.Value,
|
||||
args.User,
|
||||
uid,
|
||||
args.Delay,
|
||||
component.QualityNeeded,
|
||||
new SiliconRepairFinishedEvent
|
||||
{
|
||||
Delay = args.Delay
|
||||
});
|
||||
}
|
||||
private async void Repair(EntityUid uid, WeldingHealableComponent healableComponent, InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled
|
||||
|| !EntityManager.TryGetComponent(args.Used, out WeldingHealingComponent? component)
|
||||
|| !EntityManager.TryGetComponent(args.Target, out DamageableComponent? damageable)
|
||||
|| damageable.DamageContainerID is null
|
||||
|| !component.DamageContainers.Contains(damageable.DamageContainerID)
|
||||
|| !HasDamage(damageable, component)
|
||||
|| !_toolSystem.HasQuality(args.Used, component.QualityNeeded)
|
||||
|| args.User == args.Target && !component.AllowSelfHeal)
|
||||
return;
|
||||
|
||||
float delay = args.User == args.Target
|
||||
? component.DoAfterDelay * component.SelfHealPenalty
|
||||
: component.DoAfterDelay;
|
||||
|
||||
args.Handled = _toolSystem.UseTool
|
||||
(args.Used,
|
||||
args.User,
|
||||
args.Target,
|
||||
delay,
|
||||
component.QualityNeeded,
|
||||
new SiliconRepairFinishedEvent
|
||||
{
|
||||
Delay = delay,
|
||||
});
|
||||
}
|
||||
|
||||
private bool HasDamage(DamageableComponent component, WeldingHealingComponent healable)
|
||||
{
|
||||
if (healable.Damage.DamageDict is null)
|
||||
return false;
|
||||
|
||||
foreach (var type in healable.Damage.DamageDict)
|
||||
if (component.Damage.DamageDict[type.Key].Value > 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
using Content.Shared.Damage;
|
||||
using Content.Shared.Tools;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server._EE.Silicon.WeldingHealing
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed partial class WeldingHealingComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// All the damage to change information is stored in this <see cref="DamageSpecifier"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If this data-field is specified, it will change damage by this amount instead of setting all damage to 0.
|
||||
/// in order to heal/repair the damage values have to be negative.
|
||||
/// </remarks>
|
||||
|
||||
[DataField(required: true)]
|
||||
public DamageSpecifier Damage;
|
||||
|
||||
[DataField(customTypeSerializer:typeof(PrototypeIdSerializer<ToolQualityPrototype>))]
|
||||
public string QualityNeeded = "Welding";
|
||||
|
||||
/// <summary>
|
||||
/// The fuel amount needed to repair physical related damage
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int FuelCost = 5;
|
||||
|
||||
[DataField]
|
||||
public int DoAfterDelay = 3;
|
||||
|
||||
/// <summary>
|
||||
/// A multiplier that will be applied to the above if an entity is repairing themselves.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float SelfHealPenalty = 3f;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not an entity is allowed to repair itself.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool AllowSelfHeal = true;
|
||||
|
||||
[DataField(required: true)]
|
||||
public List<string> DamageContainers;
|
||||
}
|
||||
}
|
||||
|
|
@ -188,7 +188,7 @@ public partial class SharedBodySystem
|
|||
cameFromEntities[connection] = childPart;
|
||||
|
||||
var childPartComponent = Comp<BodyPartComponent>(childPart);
|
||||
var partSlot = CreatePartSlot(parentEntity, connection, childPartComponent.PartType, parentPartComponent);
|
||||
TryCreatePartSlot(parentEntity, connection, childPartComponent.PartType, out var partSlot, parentPartComponent);
|
||||
// Shitmed Change Start
|
||||
childPartComponent.ParentSlot = partSlot;
|
||||
Dirty(childPart, childPartComponent);
|
||||
|
|
@ -215,7 +215,7 @@ public partial class SharedBodySystem
|
|||
{
|
||||
foreach (var (organSlotId, organProto) in organs)
|
||||
{
|
||||
var slot = CreateOrganSlot((ent, ent), organSlotId);
|
||||
TryCreateOrganSlot(ent, organSlotId, out var slot); // Shitmed Change
|
||||
SpawnInContainerOrDrop(organProto, ent, GetOrganContainerId(organSlotId));
|
||||
|
||||
if (slot is null)
|
||||
|
|
|
|||
|
|
@ -115,7 +115,13 @@ public partial class SharedBodySystem
|
|||
|
||||
Containers.EnsureContainer<ContainerSlot>(parent.Value, GetOrganContainerId(slotId));
|
||||
slot = new OrganSlot(slotId);
|
||||
return part.Organs.TryAdd(slotId, slot.Value);
|
||||
// Shitmed Change Start
|
||||
if (!part.Organs.ContainsKey(slotId)
|
||||
&& !part.Organs.TryAdd(slotId, slot.Value))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
// Shitmed Change End
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -502,7 +502,8 @@ public partial class SharedBodySystem
|
|||
Containers.EnsureContainer<ContainerSlot>(partId.Value, GetPartSlotContainerId(slotId));
|
||||
slot = new BodyPartSlot(slotId, partType);
|
||||
|
||||
if (!part.Children.TryAdd(slotId, slot.Value))
|
||||
if (!part.Children.ContainsKey(slotId) // Shitmed Change
|
||||
&& !part.Children.TryAdd(slotId, slot.Value))
|
||||
return false;
|
||||
|
||||
Dirty(partId.Value, part);
|
||||
|
|
|
|||
|
|
@ -25,4 +25,10 @@ public sealed partial class CCVars : CVars
|
|||
/// </summary>
|
||||
public static readonly CVarDef<bool> DebugPow3rDisableParallel =
|
||||
CVarDef.Create("debug.pow3r_disable_parallel", true, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// Goobstation: The amount of time between NPC Silicons draining their battery in seconds.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float> SiliconNpcUpdateTime =
|
||||
CVarDef.Create("silicon.npcupdatetime", 1.5f, CVar.SERVERONLY);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,12 +24,14 @@ namespace Content.Shared.Electrocution
|
|||
public readonly EntityUid TargetUid;
|
||||
public readonly EntityUid? SourceUid;
|
||||
public readonly float SiemensCoefficient;
|
||||
public readonly float? ShockDamage = null; // Goobstation
|
||||
|
||||
public ElectrocutedEvent(EntityUid targetUid, EntityUid? sourceUid, float siemensCoefficient)
|
||||
public ElectrocutedEvent(EntityUid targetUid, EntityUid? sourceUid, float siemensCoefficient, float shockDamage) // Goobstation
|
||||
{
|
||||
TargetUid = targetUid;
|
||||
SourceUid = sourceUid;
|
||||
SiemensCoefficient = siemensCoefficient;
|
||||
ShockDamage = shockDamage; // Goobstation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ namespace Content.Shared.Humanoid
|
|||
case SpeciesNaming.FirstDashFirst:
|
||||
return Loc.GetString("namepreset-firstdashfirst",
|
||||
("first1", GetFirstName(speciesProto, gender)), ("first2", GetFirstName(speciesProto, gender)));
|
||||
case SpeciesNaming.FirstDashLast: // Goobstation
|
||||
return Loc.GetString("namepreset-firstdashlast",
|
||||
("first", GetFirstName(speciesProto, gender)), ("last", GetLastName(speciesProto)));
|
||||
case SpeciesNaming.LastFirst: // DeltaV: Rodentia name scheme
|
||||
return Loc.GetString("namepreset-lastfirst",
|
||||
("last", GetLastName(speciesProto)), ("first", GetFirstName(speciesProto, gender)));
|
||||
|
|
|
|||
|
|
@ -132,4 +132,5 @@ public enum SpeciesNaming : byte
|
|||
//End of Nyano - Summary: for Oni naming
|
||||
TheFirstofLast,
|
||||
LastFirst, // DeltaV
|
||||
FirstDashLast, // Goobstation
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,4 +53,11 @@ public sealed partial class EncryptionKeyHolderComponent : Component
|
|||
/// </summary>
|
||||
[ViewVariables]
|
||||
public string? DefaultChannel;
|
||||
|
||||
/// <summary>
|
||||
/// Goobstation: Whether or not the headset can be examined to see the encryption keys while the keys aren't accessible.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("examineWhileLocked")]
|
||||
public bool ExamineWhileLocked = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -174,7 +174,9 @@ public sealed partial class EncryptionKeySystem : EntitySystem
|
|||
|
||||
private void OnHolderExamined(EntityUid uid, EncryptionKeyHolderComponent component, ExaminedEvent args)
|
||||
{
|
||||
if (!args.IsInDetailsRange)
|
||||
if (!args.IsInDetailsRange
|
||||
|| !component.ExamineWhileLocked && !component.KeysUnlocked // Goobstation
|
||||
|| !component.ExamineWhileLocked && TryComp<WiresPanelComponent>(uid, out var panel) && !panel.Open) // Goobstation
|
||||
return;
|
||||
|
||||
if (component.KeyContainer.ContainedEntities.Count == 0)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._EE.Silicon;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class BatteryDrinkerDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
public BatteryDrinkerDoAfterEvent()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._EE.Silicon.BlindHealing;
|
||||
|
||||
public abstract partial class SharedBlindHealingSystem : EntitySystem
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
protected sealed partial class HealingDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
using Robust.Shared.GameStates;
|
||||
using Content.Shared._EE.Silicon.Systems;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Alert;
|
||||
|
||||
namespace Content.Shared._EE.Silicon.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Component for defining a mob as a robot.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class SiliconComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public short ChargeState = 10;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float OverheatAccumulator = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The last time the Silicon was drained.
|
||||
/// Used for NPC Silicons to avoid over updating.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Time between drains can be specified in
|
||||
/// <see cref="SimpleStationCcvars.SiliconNpc"/>
|
||||
/// </remarks>
|
||||
public TimeSpan LastDrainTime = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// The Silicon's battery slot, if it has one.
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// Is the Silicon currently dead?
|
||||
/// </summary>
|
||||
public bool Dead = false;
|
||||
|
||||
// BatterySystem took issue with how this was used, so I'm coming back to it at a later date, when more foundational Silicon stuff is implemented.
|
||||
// /// <summary>
|
||||
// /// The entity to get the battery from.
|
||||
// /// </summary>
|
||||
// public EntityUid BatteryOverride? = EntityUid.Invalid;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The type of silicon this is.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Any new types of Silicons should be added to the enum.
|
||||
/// Setting this to Npc will delay charge state updates by LastDrainTime and skip battery heat calculations
|
||||
/// </remarks>
|
||||
[DataField(customTypeSerializer: typeof(EnumSerializer))]
|
||||
public Enum EntityType = SiliconType.Npc;
|
||||
|
||||
/// <summary>
|
||||
/// Is this silicon battery powered?
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If true, should go along with a battery component. One will not be added automatically.
|
||||
/// </remarks>
|
||||
[DataField]
|
||||
public bool BatteryPowered = false;
|
||||
|
||||
/// <summary>
|
||||
/// How much power is drained by this Silicon every second by default.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float DrainPerSecond = 50f;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The percentages at which the silicon will enter each state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Silicon will always be Full at 100%.
|
||||
/// Setting a value to null will disable that state.
|
||||
/// Setting Critical to 0 will cause the Silicon to never enter the dead state.
|
||||
/// </remarks>
|
||||
[DataField]
|
||||
public float? ChargeThresholdMid = 0.5f;
|
||||
|
||||
/// <inheritdoc cref="ChargeThresholdMid"/>
|
||||
[DataField]
|
||||
public float? ChargeThresholdLow = 0.25f;
|
||||
|
||||
/// <inheritdoc cref="ChargeThresholdMid"/>
|
||||
[DataField]
|
||||
public float? ChargeThresholdCritical = 0.1f;
|
||||
|
||||
[DataField]
|
||||
public ProtoId<AlertPrototype> BatteryAlert = "BorgBattery";
|
||||
|
||||
[DataField]
|
||||
public ProtoId<AlertPrototype> NoBatteryAlert = "BorgBatteryNone";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The amount the Silicon will be slowed at each charge state.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public Dictionary<int, float> SpeedModifierThresholds = default!;
|
||||
|
||||
[DataField]
|
||||
public float FireStackMultiplier = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not a Silicon will cancel all sleep events.
|
||||
/// Maybe you want an android that can sleep as well as drink APCs? I'm not going to judge.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool DoSiliconsDreamOfElectricSheep;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Shared._EE.Silicon.DeadStartupButton;
|
||||
|
||||
/// <summary>
|
||||
/// This is used for...
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class DeadStartupButtonComponent : Component
|
||||
{
|
||||
[DataField("verbText")]
|
||||
public string VerbText = "dead-startup-button-verb";
|
||||
|
||||
[DataField("sound")]
|
||||
public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Effects/Arcade/newgame.ogg");
|
||||
|
||||
[DataField("buttonSound")]
|
||||
public SoundSpecifier ButtonSound = new SoundPathSpecifier("/Audio/Machines/button.ogg");
|
||||
|
||||
[DataField("doAfterInterval"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public float DoAfterInterval = 1f;
|
||||
|
||||
[DataField("buzzSound")]
|
||||
public SoundSpecifier BuzzSound = new SoundCollectionSpecifier("buzzes");
|
||||
|
||||
[DataField("verbPriority"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public int VerbPriority = 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared._EE.Silicon.DeadStartupButton;
|
||||
|
||||
/// <summary>
|
||||
/// This creates a Button that can be activated after an entity, usually a silicon or an IPC, died.
|
||||
/// This will activate a doAfter and then revive the entity, playing a custom afterward sound.
|
||||
/// </summary>
|
||||
public abstract partial class SharedDeadStartupButtonSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<DeadStartupButtonComponent, GetVerbsEvent<AlternativeVerb>>(AddTurnOnVerb);
|
||||
}
|
||||
|
||||
private void AddTurnOnVerb(EntityUid uid, DeadStartupButtonComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!_mobState.IsDead(uid)
|
||||
|| !args.CanAccess || !args.CanInteract || args.Hands == null)
|
||||
return;
|
||||
|
||||
if (!TryComp(uid, out MobStateComponent? mobStateComponent) || !_mobState.IsDead(uid, mobStateComponent))
|
||||
return;
|
||||
|
||||
args.Verbs.Add(new AlternativeVerb()
|
||||
{
|
||||
Act = () => TryStartup(args.User, uid, component),
|
||||
Text = Loc.GetString(component.VerbText),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/Spare/poweronoff.svg.192dpi.png")),
|
||||
Priority = component.VerbPriority
|
||||
});
|
||||
}
|
||||
|
||||
private void TryStartup(EntityUid user, EntityUid target, DeadStartupButtonComponent comp)
|
||||
{
|
||||
if (!_net.IsServer)
|
||||
return;
|
||||
_audio.PlayPvs(comp.ButtonSound, target);
|
||||
var args = new DoAfterArgs(EntityManager, user, comp.DoAfterInterval, new OnDoAfterButtonPressedEvent(), target, target:target)
|
||||
{
|
||||
BreakOnDamage = true,
|
||||
BreakOnMove = true,
|
||||
};
|
||||
_doAfterSystem.TryStartDoAfter(args);
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class OnDoAfterButtonPressedEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Shared._EE.Silicon.EmitBuzzWhileDamaged;
|
||||
|
||||
/// <summary>
|
||||
/// This is used for controlling the cadence of the buzzing emitted by EmitBuzzOnCritSystem.
|
||||
/// This component is used by mechanical species that can get to critical health.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class EmitBuzzWhileDamagedComponent : Component
|
||||
{
|
||||
[DataField("buzzPopupCooldown")]
|
||||
public TimeSpan BuzzPopupCooldown { get; private set; } = TimeSpan.FromSeconds(8);
|
||||
|
||||
[ViewVariables]
|
||||
public TimeSpan LastBuzzPopupTime;
|
||||
|
||||
[DataField("cycleDelay")]
|
||||
public float CycleDelay = 2.0f;
|
||||
|
||||
public float AccumulatedFrametime;
|
||||
|
||||
[DataField("sound")]
|
||||
public SoundSpecifier Sound = new SoundCollectionSpecifier("buzzes");
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
using Content.Shared._EE.Silicon.Components;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Robust.Shared.Serialization;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.PowerCell.Components;
|
||||
|
||||
namespace Content.Shared._EE.Silicon.Systems;
|
||||
|
||||
|
||||
public sealed class SharedSiliconChargeSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SiliconComponent, ComponentInit>(OnSiliconInit);
|
||||
SubscribeLocalEvent<SiliconComponent, SiliconChargeStateUpdateEvent>(OnSiliconChargeStateUpdate);
|
||||
SubscribeLocalEvent<SiliconComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
||||
SubscribeLocalEvent<SiliconComponent, ItemSlotInsertAttemptEvent>(OnItemSlotInsertAttempt);
|
||||
SubscribeLocalEvent<SiliconComponent, ItemSlotEjectAttemptEvent>(OnItemSlotEjectAttempt);
|
||||
SubscribeLocalEvent<SiliconComponent, TryingToSleepEvent>(OnTryingToSleep);
|
||||
}
|
||||
|
||||
private void OnItemSlotInsertAttempt(EntityUid uid, SiliconComponent component, ref ItemSlotInsertAttemptEvent args)
|
||||
{
|
||||
if (args.Cancelled
|
||||
|| !TryComp<PowerCellSlotComponent>(uid, out var cellSlotComp)
|
||||
|| !_itemSlots.TryGetSlot(uid, cellSlotComp.CellSlotId, out var cellSlot)
|
||||
|| cellSlot != args.Slot || args.User != uid)
|
||||
return;
|
||||
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnItemSlotEjectAttempt(EntityUid uid, SiliconComponent component, ref ItemSlotEjectAttemptEvent args)
|
||||
{
|
||||
if (args.Cancelled
|
||||
|| !TryComp<PowerCellSlotComponent>(uid, out var cellSlotComp)
|
||||
|| !_itemSlots.TryGetSlot(uid, cellSlotComp.CellSlotId, out var cellSlot)
|
||||
|| cellSlot != args.Slot || args.User != uid)
|
||||
return;
|
||||
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnSiliconInit(EntityUid uid, SiliconComponent component, ComponentInit args)
|
||||
{
|
||||
if (!component.BatteryPowered)
|
||||
return;
|
||||
|
||||
_alertsSystem.ShowAlert(uid, component.BatteryAlert, component.ChargeState);
|
||||
}
|
||||
|
||||
private void OnSiliconChargeStateUpdate(EntityUid uid, SiliconComponent component, SiliconChargeStateUpdateEvent ev)
|
||||
{
|
||||
_alertsSystem.ShowAlert(uid, component.BatteryAlert, ev.ChargePercent);
|
||||
}
|
||||
|
||||
private void OnRefreshMovespeed(EntityUid uid, SiliconComponent component, RefreshMovementSpeedModifiersEvent args)
|
||||
{
|
||||
if (!component.BatteryPowered)
|
||||
return;
|
||||
|
||||
var closest = 0;
|
||||
|
||||
foreach (var state in component.SpeedModifierThresholds)
|
||||
if (component.ChargeState >= state.Key && state.Key > closest)
|
||||
closest = state.Key;
|
||||
|
||||
var speedMod = component.SpeedModifierThresholds[closest];
|
||||
|
||||
args.ModifySpeed(speedMod, speedMod);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Silicon entities can now also be Living player entities. We may want to prevent them from sleeping if they can't sleep.
|
||||
/// </summary>
|
||||
private void OnTryingToSleep(EntityUid uid, SiliconComponent component, ref TryingToSleepEvent args)
|
||||
{
|
||||
args.Cancelled = !component.DoSiliconsDreamOfElectricSheep;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum SiliconType
|
||||
{
|
||||
Player,
|
||||
GhostRole,
|
||||
Npc,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when a Silicon's charge state needs to be updated.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SiliconChargeStateUpdateEvent : EntityEventArgs
|
||||
{
|
||||
public short ChargePercent { get; }
|
||||
|
||||
public SiliconChargeStateUpdateEvent(short chargePercent)
|
||||
{
|
||||
ChargePercent = chargePercent;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._EE.Silicon.WeldingHealing;
|
||||
|
||||
public abstract partial class SharedWeldingHealableSystem : EntitySystem
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
protected sealed partial class SiliconRepairFinishedEvent : SimpleDoAfterEvent
|
||||
{
|
||||
public float Delay;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,14 @@
|
|||
- files: ["beep_500.ogg", "beep_2000.ogg"]
|
||||
license: "CC0-1.0"
|
||||
copyright: "Synthesized in Audacity by BasedUser."
|
||||
source: "https://github.com/ekrixi-14/ekrixi"
|
||||
|
||||
- files: ["pai_whistle.ogg"]
|
||||
license: "CC-BY-4.0"
|
||||
copyright: "Source sound by hubismal@GitHub, modified in Audacity by BasedUser."
|
||||
source: "https://github.com/space-wizards/space-station-14/commit/3421e4f4de2613df1e92a4169a778335bc9faac4"
|
||||
|
||||
- files: ["whirr1.ogg", "whirr2.ogg", "whirr3.ogg"]
|
||||
license: "CC0-1.0"
|
||||
copyright: "Taken from source, spectrally modified and clipped"
|
||||
source: "https://freesound.org/people/sad3d/sounds/500168/"
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
silicon-behavior-buzz = Bzzzzt...
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
silicon-emote-deathgasp = seizes up and falls limp, {POSS-ADJ($entity)} lights sputtering into darkness...
|
||||
chat-emote-msg-deathgasp-silicon = suddenly goes silent, with a hiss of grinding servos and a screech of dying myomers.
|
||||
|
|
@ -0,0 +1 @@
|
|||
batteryslotrequireslock-component-alert-owner = {$user} is messing with your maintenance panel!
|
||||
|
|
@ -0,0 +1 @@
|
|||
battery-electrocute-charge = The battery surges with energy!
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
battery-drinker-verb-drink = Drain
|
||||
battery-drinker-empty = {CAPATALIZE(THE($target))} is already empty!
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
ipc-recharge-tip = You charged a litte of your battery.
|
||||
dead-startup-button-verb = Reboot
|
||||
dead-startup-system-reboot-success = {$target}'s system was rebooted.
|
||||
dead-startup-system-reboot-failed = {$target}'s chassis is way too damaged.
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
marking-RobotAntennaTv = Tv
|
||||
marking-RobotAntennaTesla = Tesla
|
||||
marking-RobotAntennaLightb = Light (alt)
|
||||
marking-RobotAntennaLight = Light
|
||||
marking-RobotAntennaCyberhead = Cyberhead
|
||||
marking-RobotAntennaSidelights = Sidelights
|
||||
marking-RobotAntennaAntlers = Antlers
|
||||
marking-RobotAntennaDroneeyes = Drone Eyes
|
||||
marking-RobotAntennaCrowned = Crowned
|
||||
marking-RobotAntennaTowers = Towers
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
marking-ScreenStatic = Static
|
||||
marking-ScreenBlue = Blue
|
||||
marking-ScreenBreakout = Breakout
|
||||
marking-ScreenEight = Eight
|
||||
marking-ScreenGoggles = Goggles
|
||||
marking-ScreenExclaim = Exclaim
|
||||
marking-ScreenHeart = Heart
|
||||
marking-ScreenMonoeye = Cyclops
|
||||
marking-ScreenNature = Naturalist
|
||||
marking-ScreenOrange = Orange
|
||||
marking-ScreenPink = Pink
|
||||
marking-ScreenQuestion = Question
|
||||
marking-ScreenShower = Shower
|
||||
marking-ScreenYellow = Yellow
|
||||
marking-ScreenScroll = Scroll
|
||||
marking-ScreenConsole = Console
|
||||
marking-ScreenRgb = RGB
|
||||
marking-ScreenGlider = Glider
|
||||
marking-ScreenRainbowhoriz = Horizontal Rainbow
|
||||
marking-ScreenBsod = BSOD
|
||||
marking-ScreenRedtext = Red Text
|
||||
marking-ScreenSinewave = Sinewave
|
||||
marking-ScreenSquarewave = Squarewave
|
||||
marking-ScreenEcgwave = ECG wave
|
||||
marking-ScreenEyes = Eyes
|
||||
marking-ScreenEyestall = Tall Eyes
|
||||
marking-ScreenEyesangry = Angry Eyes
|
||||
marking-ScreenLoading = Loading...
|
||||
marking-ScreenWindowsxp = Experience
|
||||
marking-ScreenTetris = NT Block Game
|
||||
marking-ScreenTv = Tv
|
||||
marking-ScreenTextdrop = Textdrop
|
||||
marking-ScreenStars = Stars
|
||||
marking-ScreenRainbowdiag = Diagonal Rainbow
|
||||
marking-ScreenBlank = Dead Pixel
|
||||
marking-ScreenSmile = Smiley
|
||||
marking-ScreenFrown = Frowny
|
||||
marking-ScreenRing = Ring
|
||||
marking-ScreenL = L
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
marking-MobIPCHeadDefault = Standard Operational Monitor
|
||||
marking-MobIPCTorsoDefault = Standard Robotic Chassis
|
||||
marking-MobIPCTorsoFemaleDefault = Standard Robotic Chassis
|
||||
marking-MobIPCLArmDefault = Standard Left Robotic Arm
|
||||
marking-MobIPCLHandDefault = Standard Left Robotic Hand
|
||||
marking-MobIPCLLegDefault = Standard Left Robotic Leg
|
||||
marking-MobIPCLFootDefault = Standard Left Robotic Foot
|
||||
marking-MobIPCRArmDefault = Standard Right Robotic Arm
|
||||
marking-MobIPCRHandDefault = Standard Right Robotic Hand
|
||||
marking-MobIPCRLegDefault = Standard Right Robotic Leg
|
||||
marking-MobIPCRFootDefault = Standard Right Robotic Foot
|
||||
|
||||
marking-CyberLimbsMarkingBishopHead = Operational Monitor from Bishop Cybernetics
|
||||
marking-CyberLimbsMarkingBishopHeadAlt = Head from Bishop Cybernetics
|
||||
marking-CyberLimbsMarkingBishopHeadAlt1 = Alternate Head from Bishop Cybernetics
|
||||
marking-CyberLimbsMarkingBishopChest = Robotic Chassis from Bishop Cybernetics
|
||||
marking-CyberLimbsMarkingBishopLArm = Left Robotic Arm from Bishop Cybernetics
|
||||
marking-CyberLimbsMarkingBishopLHand = Left Robotic Hand from Bishop Cybernetics
|
||||
marking-CyberLimbsMarkingBishopLLeg = Left Robotic Leg from Bishop Cybernetics
|
||||
marking-CyberLimbsMarkingBishopLFoot = Left Robotic Foot from Bishop Cybernetics
|
||||
marking-CyberLimbsMarkingBishopRArm = Right Robotic Arm from Bishop Cybernetics
|
||||
marking-CyberLimbsMarkingBishopRHand = Right Robotic Hand from Bishop Cybernetics
|
||||
marking-CyberLimbsMarkingBishopRLeg = Right Robotic Leg from Bishop Cybernetics
|
||||
marking-CyberLimbsMarkingBishopRFoot = Right Robotic Foot from Bishop Cybernetics
|
||||
|
||||
marking-CyberLimbsMarkingHesphiastosHead = Operational Monitor from Hesphiastos Industries
|
||||
marking-CyberLimbsMarkingHesphiastosHeadAlt = Head from Hesphiastos Industries
|
||||
marking-CyberLimbsMarkingHesphiastosChest = Robotic Chassis from Hesphiastos Industries
|
||||
marking-CyberLimbsMarkingHesphiastosLArm = Left Robotic Arm from Hesphiastos Industries
|
||||
marking-CyberLimbsMarkingHesphiastosLHand = Left Robotic Hand from Hesphiastos Industries
|
||||
marking-CyberLimbsMarkingHesphiastosLLeg = Left Robotic Leg from Hesphiastos Industries
|
||||
marking-CyberLimbsMarkingHesphiastosLFoot = Left Robotic Foot from Hesphiastos Industries
|
||||
marking-CyberLimbsMarkingHesphiastosRArm = Right Robotic Arm from Hesphiastos Industries
|
||||
marking-CyberLimbsMarkingHesphiastosRHand = Right Robotic Hand from Hesphiastos Industries
|
||||
marking-CyberLimbsMarkingHesphiastosRLeg = Right Robotic Leg from Hesphiastos Industries
|
||||
marking-CyberLimbsMarkingHesphiastosRFoot = Right Robotic Foot from Hesphiastos Industries
|
||||
|
||||
marking-CyberLimbsMarkingWardtakahashiHead = Operational Monitor from Ward-Takahashi
|
||||
marking-CyberLimbsMarkingWardtakahashiHeadAlt = Head from Ward-Takahashi
|
||||
marking-CyberLimbsMarkingWardtakahashiHeadAlt1 = Alternate Head from Ward-Takahashi
|
||||
marking-CyberLimbsMarkingWardtakahashiChest = Robotic Chassis from Ward-Takahashi
|
||||
marking-CyberLimbsMarkingWardtakahashiLArm = Left Robotic Arm from Ward-Takahashi
|
||||
marking-CyberLimbsMarkingWardtakahashiLHand = Left Robotic Hand from Ward-Takahashi
|
||||
marking-CyberLimbsMarkingWardtakahashiLLeg = Left Robotic Leg from Ward-Takahashi
|
||||
marking-CyberLimbsMarkingWardtakahashiLFoot = Left Robotic Foot from Ward-Takahashi
|
||||
marking-CyberLimbsMarkingWardtakahashiRArm = Right Robotic Arm from Ward-Takahashi
|
||||
marking-CyberLimbsMarkingWardtakahashiRHand = Right Robotic Hand from Ward-Takahashi
|
||||
marking-CyberLimbsMarkingWardtakahashiRLeg = Right Robotic Leg from Ward-Takahashi
|
||||
marking-CyberLimbsMarkingWardtakahashiRFoot = Right Robotic Foot from Ward-Takahashi
|
||||
|
||||
marking-CyberLimbsMarkingXionHead = Operational Monitor from Xion Manufacturing Group
|
||||
marking-CyberLimbsMarkingXionHeadAlt = Head from Xion Manufacturing Group
|
||||
marking-CyberLimbsMarkingXionChest = Robotic Chassis from Xion Manufacturing Group
|
||||
marking-CyberLimbsMarkingXionLArm = Left Robotic Arm from Xion Manufacturing Group
|
||||
marking-CyberLimbsMarkingXionLHand = Left Robotic Hand from Xion Manufacturing Group
|
||||
marking-CyberLimbsMarkingXionLLeg = Left Robotic Leg from Xion Manufacturing Group
|
||||
marking-CyberLimbsMarkingXionLFoot = Left Robotic Foot from Xion Manufacturing Group
|
||||
marking-CyberLimbsMarkingXionRArm = Right Robotic Arm from Xion Manufacturing Group
|
||||
marking-CyberLimbsMarkingXionRHand = Right Robotic Hand from Xion Manufacturing Group
|
||||
marking-CyberLimbsMarkingXionRLeg = Right Robotic Leg from Xion Manufacturing Group
|
||||
marking-CyberLimbsMarkingXionRFoot = Right Robotic Foot from Xion Manufacturing Group
|
||||
|
||||
marking-CyberLimbsMarkingShellguardHead = Operational Monitor from Shellguard Munitions
|
||||
marking-CyberLimbsMarkingShellguardHeadAlt = Head from Shellguard Munitions
|
||||
marking-CyberLimbsMarkingShellguardChest = Robotic Chassis from Shellguard Munitions
|
||||
marking-CyberLimbsMarkingShellguardLArm = Left Robotic Arm from Shellguard Munitions
|
||||
marking-CyberLimbsMarkingShellguardLHand = Left Robotic Hand from Shellguard Munitions
|
||||
marking-CyberLimbsMarkingShellguardLLeg = Left Robotic Leg from Shellguard Munitions
|
||||
marking-CyberLimbsMarkingShellguardLFoot = Left Robotic Foot from Shellguard Munitions
|
||||
marking-CyberLimbsMarkingShellguardRArm = Right Robotic Arm from Shellguard Munitions
|
||||
marking-CyberLimbsMarkingShellguardRHand = Right Robotic Hand from Shellguard Munitions
|
||||
marking-CyberLimbsMarkingShellguardRLeg = Right Robotic Leg from Shellguard Munitions
|
||||
marking-CyberLimbsMarkingShellguardRFoot = Right Robotic Foot from Shellguard Munitions
|
||||
|
||||
marking-CyberLimbsMarkingMorpheusHead = Operational Monitor from Morpheus Cyberkinetics
|
||||
marking-CyberLimbsMarkingMorpheusHeadAlt = Head from Morpheus Cyberkinetics
|
||||
marking-CyberLimbsMarkingMorpheusChest = Robotic Chassis from Morpheus Cyberkinetics
|
||||
marking-CyberLimbsMarkingMorpheusLArm = Left Robotic Arm from Morpheus Cyberkinetics
|
||||
marking-CyberLimbsMarkingMorpheusLHand = Left Robotic Hand from Morpheus Cyberkinetics
|
||||
marking-CyberLimbsMarkingMorpheusLLeg = Left Robotic Leg from Morpheus Cyberkinetics
|
||||
marking-CyberLimbsMarkingMorpheusLFoot = Left Robotic Foot from Morpheus Cyberkinetics
|
||||
marking-CyberLimbsMarkingMorpheusRArm = Right Robotic Arm from Morpheus Cyberkinetics
|
||||
marking-CyberLimbsMarkingMorpheusRHand = Right Robotic Hand from Morpheus Cyberkinetics
|
||||
marking-CyberLimbsMarkingMorpheusRLeg = Right Robotic Leg from Morpheus Cyberkinetics
|
||||
marking-CyberLimbsMarkingMorpheusRFoot = Right Robotic Foot from Morpheus Cyberkinetics
|
||||
|
||||
marking-CyberLimbsMarkingZenghuHead = Head from Zenghu Pharmaceuticals
|
||||
marking-CyberLimbsMarkingZenghuChest = Robotic Chassis from Zenghu Pharmaceuticals
|
||||
marking-CyberLimbsMarkingZenghuRHand = Right Robotic Hand from Zenghu Pharmaceuticals
|
||||
marking-CyberLimbsMarkingZenghuRArm = Right Robotic Arm from Zenghu Pharmaceuticals
|
||||
marking-CyberLimbsMarkingZenghuLHand = Left Robotic Hand from Zenghu Pharmaceuticals
|
||||
marking-CyberLimbsMarkingZenghuLArm = Left Robotic Arm from Zenghu Pharmaceuticals
|
||||
marking-CyberLimbsMarkingZenghuRLeg = Right Robotic Leg from Zenghu Pharmaceuticals
|
||||
marking-CyberLimbsMarkingZenghuRFoot = Right Robotic Foot from Zenghu Pharmaceuticals
|
||||
marking-CyberLimbsMarkingZenghuLLeg = Left Robotic Leg from Zenghu Pharmaceuticals
|
||||
marking-CyberLimbsMarkingZenghuLFoot = Left Robotic Foot from Zenghu Pharmaceuticals
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
silicon-charger-overheatwarning = You feel like you're in a microwave!
|
||||
silicon-charger-chargerate-string = Charge rate
|
||||
silicon-charger-efficiency-string = Efficiency
|
||||
silicon-charger-list-full = {CAPITALIZE(THE($charger))} can only accommodate so many targets!
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
silicon-overheating = You feel your circuits overheating!
|
||||
silicon-crit = Structural integrity critical!
|
||||
silicon-power-low = Power low!
|
||||
|
|
@ -0,0 +1 @@
|
|||
namepreset-firstdashlast = {$first}-{$last}
|
||||
|
|
@ -0,0 +1 @@
|
|||
species-name-ipc = IPC
|
||||
|
|
@ -200,6 +200,7 @@
|
|||
tags:
|
||||
- ClownMask
|
||||
- WhitelistChameleon
|
||||
- IPCMaskWearable # EE - IPCs
|
||||
- type: HideLayerClothing
|
||||
slots:
|
||||
- Snout
|
||||
|
|
@ -263,6 +264,9 @@
|
|||
- type: HideLayerClothing
|
||||
slots:
|
||||
- Snout
|
||||
- type: Tag
|
||||
tags:
|
||||
- IPCMaskWearable # EE - IPCs
|
||||
|
||||
- type: entity
|
||||
parent: ClothingMaskBase
|
||||
|
|
@ -280,6 +284,7 @@
|
|||
tags:
|
||||
- HamsterWearable
|
||||
- WhitelistChameleon
|
||||
- IPCMaskWearable # EE - IPCs
|
||||
- type: HideLayerClothing
|
||||
slots:
|
||||
- Snout
|
||||
|
|
@ -461,6 +466,7 @@
|
|||
tags:
|
||||
- HamsterWearable
|
||||
- WhitelistChameleon
|
||||
- IPCMaskWearable # EE - IPCs
|
||||
- type: HideLayerClothing
|
||||
slots:
|
||||
- Snout
|
||||
|
|
@ -481,6 +487,9 @@
|
|||
- type: HideLayerClothing
|
||||
slots:
|
||||
- Snout
|
||||
- type: Tag
|
||||
tags:
|
||||
- IPCMaskWearable # EE - IPCs
|
||||
|
||||
- type: entity
|
||||
parent: ClothingMaskBase
|
||||
|
|
@ -497,6 +506,9 @@
|
|||
- type: HideLayerClothing
|
||||
slots:
|
||||
- Snout
|
||||
- type: Tag
|
||||
tags:
|
||||
- IPCMaskWearable # EE - IPCs
|
||||
|
||||
- type: entity
|
||||
parent: ClothingMaskBase
|
||||
|
|
@ -513,6 +525,9 @@
|
|||
- type: HideLayerClothing
|
||||
slots:
|
||||
- Snout
|
||||
- type: Tag
|
||||
tags:
|
||||
- IPCMaskWearable # EE - IPCs
|
||||
|
||||
- type: entity
|
||||
parent: ClothingMaskBase
|
||||
|
|
@ -529,6 +544,9 @@
|
|||
- type: HideLayerClothing
|
||||
slots:
|
||||
- Snout
|
||||
- type: Tag
|
||||
tags:
|
||||
- IPCMaskWearable # EE - IPCs
|
||||
|
||||
- type: entity
|
||||
parent: ClothingMaskBase
|
||||
|
|
@ -545,6 +563,9 @@
|
|||
- type: HideLayerClothing
|
||||
slots:
|
||||
- Snout
|
||||
- type: Tag
|
||||
tags:
|
||||
- IPCMaskWearable # EE - IPCs
|
||||
|
||||
- type: entity
|
||||
parent: ClothingMaskBase
|
||||
|
|
@ -561,6 +582,9 @@
|
|||
- type: HideLayerClothing
|
||||
slots:
|
||||
- Snout
|
||||
- type: Tag
|
||||
tags:
|
||||
- IPCMaskWearable # EE - IPCs
|
||||
|
||||
- type: entity
|
||||
parent: ClothingMaskBase
|
||||
|
|
@ -577,6 +601,7 @@
|
|||
- type: Tag
|
||||
tags:
|
||||
- WhitelistChameleon
|
||||
- IPCMaskWearable # EE - IPCs
|
||||
|
||||
- type: entity
|
||||
parent: ClothingMaskNeckGaiter
|
||||
|
|
@ -663,3 +688,6 @@
|
|||
- type: EyeProtection
|
||||
- type: BreathMask
|
||||
- type: IdentityBlocker
|
||||
- type: Tag
|
||||
tags:
|
||||
- IPCMaskWearable # EE - IPCs
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@
|
|||
type: ChameleonBoundUserInterface
|
||||
enum.VoiceMaskUIKey.Key:
|
||||
type: VoiceMaskBoundUserInterface
|
||||
- type: Tag
|
||||
tags:
|
||||
- IPCMaskWearable # EE - IPCs
|
||||
|
||||
- type: entity
|
||||
parent: ClothingMaskBase
|
||||
|
|
|
|||
|
|
@ -48,6 +48,12 @@
|
|||
solutions:
|
||||
glass:
|
||||
canReact: false
|
||||
# EE - IPC Healing
|
||||
- type: BlindHealing
|
||||
damageContainers:
|
||||
- Silicon
|
||||
- type: StackPrice
|
||||
price: 2
|
||||
|
||||
- type: entity
|
||||
parent: SheetGlassBase
|
||||
|
|
|
|||
|
|
@ -99,6 +99,9 @@
|
|||
stopSearchVerbText: positronic-brain-stop-searching-verb-text
|
||||
stopSearchVerbPopup: positronic-brain-stopped-searching
|
||||
job: Borg
|
||||
- type: Organ
|
||||
slotId: posbrain
|
||||
- type: Brain
|
||||
- type: BlockMovement
|
||||
- type: Examiner
|
||||
- type: BorgBrain
|
||||
|
|
|
|||
|
|
@ -29,6 +29,19 @@
|
|||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 15
|
||||
# EE Change Start
|
||||
#Same as Ointment but divided by 5 and 3 because StackPrice needs to be 1 - Estacao Pirata IPCs
|
||||
#1 Ointment = -50 damage of those types
|
||||
#1 Cable ~= -50 (-49.8) damage of those types
|
||||
- type: Healing
|
||||
delay: 0.6
|
||||
damageContainers:
|
||||
- Silicon
|
||||
damage:
|
||||
types: # these are all split across multiple types
|
||||
Heat: -1.66
|
||||
Shock: -1.66
|
||||
# EE Change End
|
||||
# FIXME: Used isnt actually implemented so its still unlimited.
|
||||
# Uncomment this when its implemented, and make sure it handles StackComponent right
|
||||
#- type: Hemostat # Shitmed
|
||||
|
|
|
|||
|
|
@ -105,6 +105,15 @@
|
|||
price: 40
|
||||
- type: IgnitionSource
|
||||
temperature: 700
|
||||
- type: WeldingHealing # Same as Brutepack - EE IPCs
|
||||
damageContainers:
|
||||
- Silicon
|
||||
fuelCost: 5
|
||||
damage:
|
||||
types:
|
||||
Blunt: -15
|
||||
Piercing: -15
|
||||
Slash: -15
|
||||
- type: Cautery # Shitmed
|
||||
speed: 0.7
|
||||
- type: SurgeryTool # Shitmed
|
||||
|
|
|
|||
|
|
@ -657,6 +657,20 @@
|
|||
- LightHeadBorg
|
||||
- TorsoBorg
|
||||
- BorgModuleSurgery # Shitmed Change
|
||||
# Shitmed Change
|
||||
- BorgModuleSurgery
|
||||
- TorsoIPC
|
||||
- LeftArmIPC
|
||||
- RightArmIPC
|
||||
- LeftLegIPC
|
||||
- RightLegIPC
|
||||
- HeadIPC
|
||||
- LeftHandIPC
|
||||
- RightHandIPC
|
||||
- LeftFootIPC
|
||||
- RightFootIPC
|
||||
- OrganIPCEyes
|
||||
- OrganIPCPump
|
||||
dynamicRecipes:
|
||||
- ProximitySensor
|
||||
- ClothingEyesHudDiagnostic
|
||||
|
|
|
|||
|
|
@ -143,6 +143,8 @@
|
|||
priority: 1
|
||||
- type: StaticPrice
|
||||
price: 500
|
||||
- type: BatteryDrinkerSource # EE IPCs
|
||||
maxAmount: 10000
|
||||
|
||||
# APC under construction
|
||||
- type: entity
|
||||
|
|
@ -209,6 +211,8 @@
|
|||
- type: Battery
|
||||
maxCharge: 50000
|
||||
startingCharge: 50000
|
||||
- type: BatteryDrinkerSource # EE IPCs
|
||||
maxAmount: 5000
|
||||
|
||||
- type: entity
|
||||
parent: BaseAPC
|
||||
|
|
@ -218,6 +222,8 @@
|
|||
- type: Battery
|
||||
maxCharge: 100000
|
||||
startingCharge: 100000
|
||||
- type: BatteryDrinkerSource # EE IPCs
|
||||
maxAmount: 12000
|
||||
|
||||
- type: entity
|
||||
parent: BaseAPC
|
||||
|
|
@ -227,6 +233,8 @@
|
|||
- type: Battery
|
||||
maxCharge: 150000
|
||||
startingCharge: 150000
|
||||
- type: BatteryDrinkerSource # EE IPCs
|
||||
maxAmount: 18000
|
||||
|
||||
- type: entity
|
||||
parent: BaseAPC
|
||||
|
|
@ -236,3 +244,5 @@
|
|||
- type: Battery
|
||||
maxCharge: 200000
|
||||
startingCharge: 200000
|
||||
- type: BatteryDrinkerSource # EE IPCs
|
||||
maxAmount: 26000
|
||||
|
|
@ -247,6 +247,7 @@
|
|||
whitelist:
|
||||
components:
|
||||
- BorgChassis
|
||||
- Silicon # EE IPCs
|
||||
- type: Construction
|
||||
containers:
|
||||
- machine_parts
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
- Oni
|
||||
- Rodentia
|
||||
- Chitinid
|
||||
- IPC
|
||||
|
||||
- type: guideEntry
|
||||
id: Arachnid
|
||||
|
|
@ -58,3 +59,8 @@
|
|||
id: Vox
|
||||
name: species-name-vox
|
||||
text: "/ServerInfo/Guidebook/Mobs/Vox.xml"
|
||||
|
||||
- type: guideEntry
|
||||
id: IPC
|
||||
name: species-name-ipc
|
||||
text: "/ServerInfo/Guidebook/Mobs/IPCs.xml"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
- type: entity
|
||||
id: BaseIPCOrgan
|
||||
parent: BaseItem
|
||||
abstract: true
|
||||
components:
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
sprite: _EE/Mobs/Species/IPC/organs.rsi
|
||||
- type: Organ
|
||||
# - type: Food
|
||||
# - type: Extractable
|
||||
# grindableSolutionName: organ
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
organ:
|
||||
reagents:
|
||||
- ReagentId: Oil
|
||||
Quantity: 10
|
||||
|
||||
- type: entity
|
||||
id: OrganIPCEyes
|
||||
parent: BaseIPCOrgan
|
||||
name: robotic eyes
|
||||
description: "01001001 00100000 01110011 01100101 01100101 00100000 01111001 01101111 01110101 00100001"
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: eyeball-l
|
||||
- state: eyeball-r
|
||||
- type: Organ
|
||||
slotId: eyes
|
||||
- type: Eyes
|
||||
|
||||
- type: entity
|
||||
id: OrganIPCTongue
|
||||
parent: BaseIPCOrgan
|
||||
name: vocal modulator
|
||||
description: "A vocal modulator, used to produce speech."
|
||||
components:
|
||||
- type: Sprite
|
||||
state: tongue
|
||||
- type: Organ
|
||||
|
||||
- type: entity
|
||||
id: OrganIPCEars
|
||||
parent: BaseIPCOrgan
|
||||
name: "sonic receptors"
|
||||
description:
|
||||
components:
|
||||
- type: Sprite
|
||||
state: ears
|
||||
- type: Organ
|
||||
|
||||
- type: entity
|
||||
id: OrganIPCPump
|
||||
parent: BaseIPCOrgan
|
||||
name: micro pump
|
||||
description: "A micro pump, used to circulate coolant."
|
||||
components:
|
||||
- type: Sprite
|
||||
state: heart-on
|
||||
- type: Organ
|
||||
slotId: pump
|
||||
- type: Heart
|
||||
# The heart 'metabolizes' medicines and poisons that aren't filtered out by other organs.
|
||||
# This is done because these chemicals need to have some effect even if they aren't being filtered out of your body.
|
||||
# You're technically 'immune to poison' without a heart, but.. uhh, you'll have bigger problems on your hands.
|
||||
|
||||
# This is fine?
|
||||
# - type: Metabolizer
|
||||
# maxReagents: 2
|
||||
# metabolizerTypes: [Human]
|
||||
# groups:
|
||||
# - id: Medicine
|
||||
# - id: Poison
|
||||
# - id: Narcotic
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
- type: entity
|
||||
id: PartIPC
|
||||
parent: BaseItem
|
||||
name: "ipc body part"
|
||||
abstract: true
|
||||
components:
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic # Shitmed Change
|
||||
- type: BodyPart
|
||||
- type: Gibbable
|
||||
- type: ContainerContainer
|
||||
containers:
|
||||
bodypart: !type:Container
|
||||
ents: []
|
||||
- type: SurgeryTool
|
||||
startSound:
|
||||
path: /Audio/_Shitmed/Medical/Surgery/organ1.ogg
|
||||
endSound:
|
||||
path: /Audio/_Shitmed/Medical/Surgery/organ2.ogg
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTypeTrigger
|
||||
damageType: Blunt
|
||||
damage: 110
|
||||
behaviors:
|
||||
- !type:GibPartBehavior { }
|
||||
- trigger:
|
||||
!type:DamageTypeTrigger
|
||||
damageType: Slash
|
||||
damage: 150
|
||||
behaviors:
|
||||
- !type:GibPartBehavior { }
|
||||
- type: StaticPrice
|
||||
price: 100
|
||||
|
||||
- type: entity
|
||||
id: TorsoIPC
|
||||
name: "ipc torso"
|
||||
parent: PartIPC
|
||||
components:
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "torso_m"
|
||||
- type: Icon
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "torso_m"
|
||||
- type: BodyPart
|
||||
partType: Torso
|
||||
children: # I hate this so much I want to kill it AAAAAAAAAAAAAAAAAAAAAAAA
|
||||
head:
|
||||
id: "head"
|
||||
type: Head
|
||||
left arm:
|
||||
id: "left arm"
|
||||
type: Arm
|
||||
right arm:
|
||||
id: "right arm"
|
||||
type: Arm
|
||||
left leg:
|
||||
id: "left leg"
|
||||
type: Leg
|
||||
right leg:
|
||||
id: "right leg"
|
||||
type: Leg
|
||||
organs:
|
||||
posbrain:
|
||||
id: "posbrain"
|
||||
pump:
|
||||
id: "pump"
|
||||
- type: ContainerContainer
|
||||
containers:
|
||||
torso_slot: !type:ContainerSlot {}
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTypeTrigger
|
||||
damageType: Blunt
|
||||
damage: 400
|
||||
behaviors:
|
||||
- !type:GibPartBehavior { }
|
||||
- trigger:
|
||||
!type:DamageTypeTrigger
|
||||
damageType: Slash
|
||||
damage: 400
|
||||
behaviors:
|
||||
- !type:GibPartBehavior { }
|
||||
|
||||
- type: entity
|
||||
id: HeadIPC
|
||||
name: "ipc head"
|
||||
parent: PartIPC
|
||||
components:
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "head_m"
|
||||
- type: Icon
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "head_m"
|
||||
- type: BodyPart
|
||||
partType: Head
|
||||
organs:
|
||||
eyes:
|
||||
id: "eyes"
|
||||
vital: true
|
||||
- type: Input
|
||||
context: "ghost"
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed: 0
|
||||
baseSprintSpeed: 0
|
||||
- type: InputMover
|
||||
- type: GhostOnMove
|
||||
- type: Tag
|
||||
tags:
|
||||
- Head
|
||||
|
||||
- type: entity
|
||||
id: LeftArmIPC
|
||||
name: "left ipc arm"
|
||||
parent: PartIPC
|
||||
components:
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "l_arm"
|
||||
- type: Icon
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "l_arm"
|
||||
- type: BodyPart
|
||||
partType: Arm
|
||||
symmetry: Left
|
||||
children:
|
||||
left hand:
|
||||
id: "left hand"
|
||||
type: Hand
|
||||
|
||||
- type: entity
|
||||
id: RightArmIPC
|
||||
name: "right ipc arm"
|
||||
parent: PartIPC
|
||||
components:
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "r_arm"
|
||||
- type: Icon
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "r_arm"
|
||||
- type: BodyPart
|
||||
partType: Arm
|
||||
symmetry: Right
|
||||
children:
|
||||
right hand:
|
||||
id: "right hand"
|
||||
type: Hand
|
||||
|
||||
- type: entity
|
||||
id: LeftHandIPC
|
||||
name: "left ipc hand"
|
||||
parent: PartIPC
|
||||
components:
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "l_hand"
|
||||
- type: Icon
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "l_hand"
|
||||
- type: BodyPart
|
||||
partType: Hand
|
||||
symmetry: Left
|
||||
|
||||
- type: entity
|
||||
id: RightHandIPC
|
||||
name: "right ipc hand"
|
||||
parent: PartIPC
|
||||
components:
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "r_hand"
|
||||
- type: Icon
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "r_hand"
|
||||
- type: BodyPart
|
||||
partType: Hand
|
||||
symmetry: Right
|
||||
|
||||
- type: entity
|
||||
id: LeftLegIPC
|
||||
name: "left ipc leg"
|
||||
parent: PartIPC
|
||||
components:
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "l_leg"
|
||||
- type: Icon
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "l_leg"
|
||||
- type: BodyPart
|
||||
partType: Leg
|
||||
symmetry: Left
|
||||
children:
|
||||
left foot:
|
||||
id: "left foot"
|
||||
type: Foot
|
||||
- type: MovementBodyPart
|
||||
|
||||
- type: entity
|
||||
id: RightLegIPC
|
||||
name: "right ipc leg"
|
||||
parent: PartIPC
|
||||
components:
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "r_leg"
|
||||
- type: Icon
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "r_leg"
|
||||
- type: BodyPart
|
||||
partType: Leg
|
||||
symmetry: Right
|
||||
children:
|
||||
right foot:
|
||||
id: "right foot"
|
||||
type: Foot
|
||||
- type: MovementBodyPart
|
||||
|
||||
- type: entity
|
||||
id: LeftFootIPC
|
||||
name: "left ipc foot"
|
||||
parent: PartIPC
|
||||
components:
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "l_foot"
|
||||
- type: Icon
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "l_foot"
|
||||
- type: BodyPart
|
||||
partType: Foot
|
||||
symmetry: Left
|
||||
|
||||
- type: entity
|
||||
id: RightFootIPC
|
||||
name: "right ipc foot"
|
||||
parent: PartIPC
|
||||
components:
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "r_foot"
|
||||
- type: Icon
|
||||
sprite: _EE/Mobs/Species/IPC/parts.rsi
|
||||
state: "r_foot"
|
||||
- type: BodyPart
|
||||
partType: Foot
|
||||
symmetry: Right
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
- type: body
|
||||
id: IPC
|
||||
name: "ipc"
|
||||
root: torso
|
||||
slots:
|
||||
head:
|
||||
part: HeadIPC
|
||||
connections:
|
||||
- torso
|
||||
organs:
|
||||
eyes: OrganIPCEyes
|
||||
torso:
|
||||
part: TorsoIPC
|
||||
connections:
|
||||
- right arm
|
||||
- left arm
|
||||
- right leg
|
||||
- left leg
|
||||
organs:
|
||||
posbrain: PositronicBrain
|
||||
pump: OrganIPCPump
|
||||
right arm:
|
||||
part: RightArmIPC
|
||||
connections:
|
||||
- right hand
|
||||
left arm:
|
||||
part: LeftArmIPC
|
||||
connections:
|
||||
- left hand
|
||||
right hand:
|
||||
part: RightHandIPC
|
||||
left hand:
|
||||
part: LeftHandIPC
|
||||
right leg:
|
||||
part: RightLegIPC
|
||||
connections:
|
||||
- right foot
|
||||
left leg:
|
||||
part: LeftLegIPC
|
||||
connections:
|
||||
- left foot
|
||||
right foot:
|
||||
part: RightFootIPC
|
||||
left foot:
|
||||
part: LeftFootIPC
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
- type: damageModifierSet
|
||||
id: IPC
|
||||
coefficients:
|
||||
Poison: 0
|
||||
Cold: 0.2
|
||||
Heat: 2
|
||||
Shock: 2.5
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,318 @@
|
|||
# All the Harpy customization
|
||||
|
||||
# Ears Markings
|
||||
- type: marking
|
||||
id: HarpyWingDefaultHuescale
|
||||
bodyPart: RArm
|
||||
markingCategory: Arms
|
||||
speciesRestriction: [Harpy]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:CategoryColoring
|
||||
category: Hair
|
||||
fallbackTypes:
|
||||
- !type:SimpleColoring
|
||||
color: "#964b00"
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: huescale_harpy
|
||||
|
||||
- type: marking
|
||||
id: HarpyWingDefaultWhitescale
|
||||
bodyPart: RArm
|
||||
markingCategory: Arms
|
||||
speciesRestriction: [Harpy]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:CategoryColoring
|
||||
category: Hair
|
||||
fallbackTypes:
|
||||
- !type:SimpleColoring
|
||||
color: "#964b00"
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: whitescale_harpy
|
||||
|
||||
- type: marking
|
||||
id: HarpyWingClassic
|
||||
bodyPart: RArm
|
||||
markingCategory: Arms
|
||||
speciesRestriction: [Harpy]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:CategoryColoring
|
||||
category: Hair
|
||||
fallbackTypes:
|
||||
- !type:SimpleColoring
|
||||
color: "#964b00"
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: classic_harpy
|
||||
|
||||
- type: marking
|
||||
id: HarpyWingFoldedHuescale
|
||||
bodyPart: RArm
|
||||
markingCategory: Arms
|
||||
speciesRestriction: [Harpy]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:CategoryColoring
|
||||
category: Hair
|
||||
fallbackTypes:
|
||||
- !type:SimpleColoring
|
||||
color: "#964b00"
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: huescale_harpy_folded
|
||||
|
||||
- type: marking
|
||||
id: HarpyWingFoldedWhitescale
|
||||
bodyPart: RArm
|
||||
markingCategory: Arms
|
||||
speciesRestriction: [Harpy]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:CategoryColoring
|
||||
category: Hair
|
||||
fallbackTypes:
|
||||
- !type:SimpleColoring
|
||||
color: "#964b00"
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: whitescale_harpy_folded
|
||||
|
||||
- type: marking
|
||||
id: HarpyWingOwlHuescale
|
||||
bodyPart: RArm
|
||||
markingCategory: Arms
|
||||
speciesRestriction: [Harpy]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:CategoryColoring
|
||||
category: Hair
|
||||
fallbackTypes:
|
||||
- !type:SimpleColoring
|
||||
color: "#964b00"
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: huescale_harpy_wing_owl
|
||||
|
||||
- type: marking
|
||||
id: HarpyWingOwlWhitescale
|
||||
bodyPart: RArm
|
||||
markingCategory: Arms
|
||||
speciesRestriction: [Harpy]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:CategoryColoring
|
||||
category: Hair
|
||||
fallbackTypes:
|
||||
- !type:SimpleColoring
|
||||
color: "#964b00"
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: whitescale_harpy_wing_owl
|
||||
|
||||
- type: marking
|
||||
id: HarpyEarsLarge
|
||||
bodyPart: Head
|
||||
markingCategory: HeadTop
|
||||
speciesRestriction: [Harpy]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:CategoryColoring
|
||||
category: Hair
|
||||
fallbackTypes:
|
||||
- !type:SimpleColoring
|
||||
color: "#964b00"
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_ears.rsi
|
||||
state: harpy_ears_large
|
||||
|
||||
- type: marking
|
||||
id: HarpyTailForkedWhitescale
|
||||
bodyPart: Tail
|
||||
markingCategory: Tail
|
||||
speciesRestriction: [Harpy]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:CategoryColoring
|
||||
category: Hair
|
||||
fallbackTypes:
|
||||
- !type:SimpleColoring
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_tails.rsi
|
||||
state: whitescale_forked_tailfin
|
||||
|
||||
- type: marking
|
||||
id: HarpyTailForkedHuescale
|
||||
bodyPart: Tail
|
||||
markingCategory: Tail
|
||||
speciesRestriction: [Harpy]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:CategoryColoring
|
||||
category: Hair
|
||||
fallbackTypes:
|
||||
- !type:SimpleColoring
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_tails.rsi
|
||||
state: huescale_forked_tailfin
|
||||
|
||||
- type: marking
|
||||
id: HarpyTailPeacock
|
||||
bodyPart: Tail
|
||||
markingCategory: Tail
|
||||
speciesRestriction: [Harpy]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:CategoryColoring
|
||||
category: Hair
|
||||
fallbackTypes:
|
||||
- !type:SimpleColoring
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_tails48x48.rsi
|
||||
state: peacock_tail_feathers
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_tails48x48.rsi
|
||||
state: peacock_tail_eyes
|
||||
|
||||
- type: marking
|
||||
id: HarpyTailHaven
|
||||
bodyPart: Tail
|
||||
markingCategory: Tail
|
||||
speciesRestriction: [Harpy]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:CategoryColoring
|
||||
category: Hair
|
||||
fallbackTypes:
|
||||
- !type:SimpleColoring
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_tails.rsi
|
||||
state: haven_tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_tails.rsi
|
||||
state: haven_tone_2
|
||||
|
||||
- type: marking
|
||||
id: HarpyTailForkedLong
|
||||
bodyPart: Tail
|
||||
markingCategory: Tail
|
||||
speciesRestriction: [Harpy]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:CategoryColoring
|
||||
category: Hair
|
||||
fallbackTypes:
|
||||
- !type:SimpleColoring
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_tails.rsi
|
||||
state: forked_long
|
||||
|
||||
- type: marking
|
||||
id: HarpyTailSwallow
|
||||
bodyPart: Tail
|
||||
markingCategory: Tail
|
||||
speciesRestriction: [Harpy]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:CategoryColoring
|
||||
category: Hair
|
||||
fallbackTypes:
|
||||
- !type:SimpleColoring
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_tails.rsi
|
||||
state: swallow_tail
|
||||
|
||||
- type: marking
|
||||
id: HarpyWing2ToneClassic
|
||||
bodyPart: RArm
|
||||
markingCategory: Arms
|
||||
speciesRestriction: [Harpy]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: harpy_2tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: harpy_2tone_2
|
||||
|
||||
- type: marking
|
||||
id: HarpyWing3ToneClassic
|
||||
bodyPart: RArm
|
||||
markingCategory: Arms
|
||||
speciesRestriction: [Harpy]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: harpy_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: harpy_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: harpy_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: HarpyWingSpeckledClassic
|
||||
bodyPart: RArm
|
||||
markingCategory: Arms
|
||||
speciesRestriction: [Harpy]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: harpy_speckled_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: harpy_speckled_2
|
||||
|
||||
- type: marking
|
||||
id: HarpyWingUndertoneClassic
|
||||
bodyPart: RArm
|
||||
markingCategory: Arms
|
||||
speciesRestriction: [Harpy]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: harpy_undertone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: harpy_undertone_2
|
||||
|
||||
- type: marking
|
||||
id: HarpyWingTipsClassic
|
||||
bodyPart: RArm
|
||||
markingCategory: Arms
|
||||
speciesRestriction: [Harpy]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: harpy_wingtip_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: harpy_wingtip_2
|
||||
|
||||
- type: marking
|
||||
id: HarpyWingBat
|
||||
bodyPart: RArm
|
||||
markingCategory: Arms
|
||||
speciesRestriction: [Harpy]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: bat_wings_tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: bat_wings_tone_2
|
||||
|
||||
- type: marking
|
||||
id: HarpyWingBionic
|
||||
bodyPart: RArm
|
||||
markingCategory: Arms
|
||||
speciesRestriction: [Harpy]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: bionic_wings_tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Harpy/harpy_wings.rsi
|
||||
state: bionic_wings_tone_2
|
||||
shader: unshaded
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
- type: marking
|
||||
id: OniTwoToedFeet
|
||||
bodyPart: RFoot # Can't be LFoot to avoid visual glitches
|
||||
markingCategory: Legs
|
||||
speciesRestriction: [Oni]
|
||||
coloring:
|
||||
default:
|
||||
type:
|
||||
!type:SimpleColoring
|
||||
color: "#454545"
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/oni_feet.rsi
|
||||
state: two_toes
|
||||
|
|
@ -0,0 +1,525 @@
|
|||
- type: marking
|
||||
id: OniHornTallCurved
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns48x48.rsi
|
||||
state: tall_curved
|
||||
- type: marking
|
||||
id: OniHornTallCurved3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns48x48.rsi
|
||||
state: tall_curved_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns48x48.rsi
|
||||
state: tall_curved_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns48x48.rsi
|
||||
state: tall_curved_3tone_3
|
||||
- type: marking
|
||||
id: OniHornTallBull
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns48x48.rsi
|
||||
state: tall_bull
|
||||
- type: marking
|
||||
id: OniHornTallBull3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns48x48.rsi
|
||||
state: tall_bull_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns48x48.rsi
|
||||
state: tall_bull_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns48x48.rsi
|
||||
state: tall_bull_3tone_3
|
||||
- type: marking
|
||||
id: OniHornCrowned
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: crowned
|
||||
|
||||
- type: marking
|
||||
id: OniHornSerket
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: serket
|
||||
|
||||
- type: marking
|
||||
id: OniHornSerket3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: serket_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: serket_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: serket_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornPisces
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: pisces
|
||||
|
||||
- type: marking
|
||||
id: OniHornPisces2Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: pisces_2tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: pisces_2tone_2
|
||||
|
||||
- type: marking
|
||||
id: OniHornPisces3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: pisces_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: pisces_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: pisces_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornVirgo
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: virgo
|
||||
|
||||
- type: marking
|
||||
id: OniHornVirgo3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: virgo_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: virgo_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: virgo_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornSagittarius
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: sagittarius
|
||||
|
||||
- type: marking
|
||||
id: OniHornSagittarius3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: sagittarius_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: sagittarius_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: sagittarius_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornVantas
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: vantas
|
||||
|
||||
- type: marking
|
||||
id: OniHornVantas3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: vantas_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: vantas_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: vantas_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornMakara
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns48x48.rsi
|
||||
state: makara
|
||||
|
||||
- type: marking
|
||||
id: OniHornMakara2Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns48x48.rsi
|
||||
state: makara_2tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns48x48.rsi
|
||||
state: makara_2tone_2
|
||||
|
||||
- type: marking
|
||||
id: OniHornMakara3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns48x48.rsi
|
||||
state: makara_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns48x48.rsi
|
||||
state: makara_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns48x48.rsi
|
||||
state: makara_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornNepeta
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: nepeta
|
||||
|
||||
- type: marking
|
||||
id: OniHornNepeta3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: nepeta_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: nepeta_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: nepeta_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornTaurus
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: taurus
|
||||
|
||||
- type: marking
|
||||
id: OniHornTaurus2Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: taurus_2tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: taurus_2tone_2
|
||||
|
||||
- type: marking
|
||||
id: OniHornTaurus3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: taurus_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: taurus_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: taurus_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornAries
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: aries
|
||||
|
||||
- type: marking
|
||||
id: OniHornAries3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: aries_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: aries_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: aries_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornTavris
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: tavris
|
||||
|
||||
- type: marking
|
||||
id: OniHornTavris3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: tavris_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: tavris_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: tavris_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornInclined
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: inclined
|
||||
|
||||
- type: marking
|
||||
id: OniHornInclined3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: inclined_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: inclined_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: inclined_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornWavy
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: wavy
|
||||
|
||||
- type: marking
|
||||
id: OniHornWavy2Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: wavy_2tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: wavy_2tone_2
|
||||
|
||||
- type: marking
|
||||
id: OniHornWavy3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: wavy_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: wavy_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: wavy_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornAntlers
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: antlers_2tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: antlers_2tone_2
|
||||
|
||||
- type: marking
|
||||
id: OniHornAntlers3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: antlers_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: antlers_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: antlers_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornUnicorn
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: unicorn
|
||||
|
||||
- type: marking
|
||||
id: OniHornErebia
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: erebia
|
||||
|
||||
- type: marking
|
||||
id: OniHornErebia3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: erebia_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: erebia_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: erebia_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornErebiaRings
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: erebia
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: erebia_rings
|
||||
|
||||
- type: marking
|
||||
id: OniHornDoubleThick
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: double_thick
|
||||
|
||||
- type: marking
|
||||
id: OniHornDoubleThick2Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: double_thick_2tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: double_thick_2tone_2
|
||||
|
||||
- type: marking
|
||||
id: OniHornDoubleThick3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: double_thick_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: double_thick_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: double_thick_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornDoubleCurved3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: double_curved_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: double_curved_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: double_curved_3tone_3
|
||||
|
||||
- type: marking
|
||||
id: OniHornDoubleCurvedOutwards3Tone
|
||||
bodyPart: HeadTop
|
||||
markingCategory: HeadTop
|
||||
forcedColoring: false
|
||||
speciesRestriction: [Oni]
|
||||
sprites:
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: double_curved_outwards_3tone_1
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: double_curved_outwards_3tone_2
|
||||
- sprite: _EinsteinEngines/Mobs/Customization/Oni/oni_horns.rsi
|
||||
state: double_curved_outwards_3tone_3
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue