Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2ce54df
Complete IPC overhaul (#31)
Day-OS Jun 28, 2024
5f01431
Updated old conventions
Timemaster99 Aug 16, 2024
228df04
Fixed IPC guidebook locale
Timemaster99 Jul 10, 2024
898306e
Fixed color for markings and IPC
Timemaster99 Jul 10, 2024
fee3e9e
IPCs can no longer eject their own battery, in congruence with borgs
Timemaster99 Jul 10, 2024
86ff7b4
IPCs no longer lose charge when SSD or ghosted
Timemaster99 Jul 16, 2024
2dab6e9
Refactored IPC alerts to use borg health and battery instead
Timemaster99 Jul 27, 2024
858d906
Updated markings
Timemaster99 Aug 7, 2024
f5cbe6f
Marked, moved, and commented changes to base files
Timemaster99 Aug 7, 2024
8451c84
IPCs are now alerted when another person tries to toggle their lock
Timemaster99 Aug 7, 2024
1cba5b3
Added missing comment in BatterySlotRequiresLockSystem
Timemaster99 Aug 7, 2024
c9dfe0c
Readded markings locale
Timemaster99 Aug 7, 2024
529fd4f
Removed ChargeBuffer so IPCs can be recharged instantly. Fixed indefi…
Timemaster99 Aug 15, 2024
67ec515
Removed duplicate markings and emotes
Timemaster99 Aug 16, 2024
b6eec41
Merge branch 'master' into dv-ipc
DangerRevolution Aug 17, 2024
138522f
Removed mentions of old charge alert
Timemaster99 Aug 20, 2024
1410bd2
Merge branch 'dv-ipc' of https://github.com/Timemaster99/Einstein-Eng…
Timemaster99 Aug 20, 2024
baca54c
Moved namespaces to generic
Timemaster99 Aug 21, 2024
a05399d
Removed codebase comments
Timemaster99 Aug 21, 2024
f27e27d
Migrated audio files to generic dir, adjusted references
Timemaster99 Aug 21, 2024
9babf74
Migrated ftl files to generic dir
Timemaster99 Aug 21, 2024
f6d001f
Migrate textures to generic dir
Timemaster99 Aug 21, 2024
cbe851a
Migrated yml files to generic dir
Timemaster99 Aug 21, 2024
04528c8
Migrated guidebook to generic dir
Timemaster99 Aug 21, 2024
2c6ef82
Removed unused fields from emote prototype
Timemaster99 Aug 21, 2024
78cd087
Merge branch 'master' into dv-ipc
Timemaster99 Aug 21, 2024
2ed5d93
Removed old head marking
Timemaster99 Aug 21, 2024
277457a
Blacklisted certain traits from IPCs
Timemaster99 Aug 21, 2024
7d1f58f
Fixed species requirements yaml
Timemaster99 Aug 21, 2024
8f7bb68
Added missing if statement to charge update system
Timemaster99 Aug 21, 2024
0cf5275
Added mood to IPCs
Timemaster99 Aug 21, 2024
bc2aeda
Readded nyano comments
Timemaster99 Aug 21, 2024
db4934b
Apply suggestions from code review
Timemaster99 Aug 21, 2024
8f0783a
Update Content.Server/Power/Components/SiliconEmitSoundOnDrainedCompo…
VMSolidus Aug 21, 2024
1ca1df8
Update Content.Server/Power/Components/SiliconEmitSoundOnDrainedCompo…
VMSolidus Aug 21, 2024
c747183
Added extra info on npc silicon state
Timemaster99 Aug 21, 2024
475411d
Apply suggestions from code review
Timemaster99 Aug 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Robust.Shared.Console;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Content.Server.SimpleStation14.Silicon.IPC; // Parkstation - IPCs

namespace Content.Server.Administration.Commands
{
Expand Down Expand Up @@ -126,7 +127,7 @@ public static bool SetOutfit(EntityUid target, string gear, IEntityManager entit
handsSystem.TryPickup(target, inhandEntity, checkActionBlocker: false, handsComp: handsComponent);
}
}

InternalEncryptionKeySpawner.TryInsertEncryptionKey(target, startingGear, entityManager, profile); // Parkstation - IPC
return true;
}
}
Expand Down
3 changes: 2 additions & 1 deletion Content.Server/Bed/BedSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Content.Shared.Emag.Systems;
using Content.Shared.Mobs.Systems;
using Robust.Shared.Timing;
using Content.Shared.SimpleStation14.Silicon.Components; // Parkstation-IPCs // I shouldn't have to modify this.

namespace Content.Server.Bed
{
Expand Down Expand Up @@ -65,7 +66,7 @@ public override void Update(float frameTime)

foreach (var healedEntity in strapComponent.BuckledEntities)
{
if (_mobStateSystem.IsDead(healedEntity))
if (_mobStateSystem.IsDead(healedEntity) || HasComp<SiliconComponent>(healedEntity)) // Parkstation-IPCs // I shouldn't have to modify this.
continue;

var damage = bedComponent.Damage;
Expand Down
12 changes: 7 additions & 5 deletions Content.Server/Electrocution/ElectrocutionSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ 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; // Parkstation-IPC // 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;

Expand Down Expand Up @@ -297,9 +299,9 @@ public override bool TryDoElectrocution(
|| !DoCommonElectrocution(uid, sourceUid, shockDamage, time, refresh, siemensCoefficient, statusEffects))
return false;

RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient), true);
return true;
}
RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient, shockDamage), true); // Parkstation-IPC
return true;
}

private bool TryDoElectrocutionPowered(
EntityUid uid,
Expand Down Expand Up @@ -347,7 +349,7 @@ private bool TryDoElectrocutionPowered(
electrocutionComponent.Electrocuting = uid;
electrocutionComponent.Source = sourceUid;

RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient), true);
RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient, shockDamage), true); // Parkstation-IPC

return true;
}
Expand Down
8 changes: 7 additions & 1 deletion Content.Server/Mobs/DeathgaspComponent.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Content.Shared.Chat.Prototypes;
using Content.Shared.Chat.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;

namespace Content.Server.Mobs;
Expand All @@ -15,4 +15,10 @@ public sealed partial class DeathgaspComponent : Component
/// </summary>
[DataField("prototype", customTypeSerializer:typeof(PrototypeIdSerializer<EmotePrototype>))]
public string Prototype = "DefaultDeathgasp";

/// <summary>
/// Makes sure that the deathgasp is only displayed if the entity went critical before dying - Estacao Pirata
/// </summary>
[DataField("needsCritical")]
public bool NeedsCritical = true;
}
9 changes: 6 additions & 3 deletions Content.Server/Mobs/DeathgaspSystem.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Content.Server.Chat.Systems;
using Content.Server.Chat.Systems;
using Content.Server.Speech.Muting;
using Content.Shared.Mobs;
using Content.Shared.Speech.Muting;
Expand All @@ -20,9 +20,12 @@ public override void Initialize()

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)
// don't deathgasp if they arent going straight from crit to dead - Estacao Pirata
if (component.NeedsCritical && args.OldMobState != MobState.Critical)
return;
if (args.NewMobState != MobState.Dead)
return;
// End of Estacao Pirata code

Deathgasp(uid, component);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace Content.Server.SimpleStation14.Power;

[RegisterComponent]
public sealed partial class BatteryDrinkerComponent : Component
{
/// <summary>
/// Is this drinker allowed to drink batteries not tagged as <see cref="BatteryDrinkSource"/>?
/// </summary>
[DataField("drinkAll"), ViewVariables(VVAccess.ReadWrite)]
public bool DrinkAll = false;

/// <summary>
/// How long it takes to drink from a battery, in seconds.
/// Is multiplied by the source.
/// </summary>
[DataField("drinkSpeed"), ViewVariables(VVAccess.ReadWrite)]
public float DrinkSpeed = 1.5f;

/// <summary>
/// The multiplier for the amount of power to attempt to drink.
/// Default amount is 1000
/// </summary>
[DataField("drinkMultiplier"), ViewVariables(VVAccess.ReadWrite)]
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("drinkAllMultiplier"), ViewVariables(VVAccess.ReadWrite)]
public float DrinkAllMultiplier = 2.5f;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Numerics;

namespace Content.Server.SimpleStation14.Power.Components;

[RegisterComponent]
public sealed partial class RandomBatteryChargeComponent : Component
{
/// <summary>
/// The minimum and maximum max charge the battery can have.
/// </summary>
[DataField("batteryMaxMinMax")]
public Vector2 BatteryMaxMinMax = new(0.85f, 1.15f);

/// <summary>
/// The minimum and maximum current charge the battery can have.
/// </summary>
[DataField("batteryChargeMinMax")]
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("basedOnMaxCharge")]
public bool BasedOnMaxCharge = true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.ComponentModel.DataAnnotations;
using Robust.Shared.Audio;
using Content.Server.Sound.Components;

namespace Content.Server.SimpleStation14.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("sound"), Required]
public SoundSpecifier Sound = default!;

[DataField("minInterval")]
public TimeSpan Interval = TimeSpan.FromSeconds(8);

[DataField("maxInterval")]
public TimeSpan MaxInterval = TimeSpan.FromSeconds(15);

[DataField("playChance")]
public float PlayChance = 1f;

[DataField("popUp")]
public string? PopUp;
}
144 changes: 144 additions & 0 deletions Content.Server/SimpleStation14/Power/Systems/BatteryDrinkerSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
using System.Diagnostics.CodeAnalysis;
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.SimpleStation14.Silicon;
using Content.Shared.Verbs;
using Robust.Shared.Utility;
using Content.Server.SimpleStation14.Silicon.Charge;
using Content.Server.Power.EntitySystems;
using Content.Server.Popups;
using Content.Server.PowerCell;
using Content.Shared.Popups;
using Content.Shared.SimpleStation14.Silicon.Components;
using FastAccessors;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;

namespace Content.Server.SimpleStation14.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,
BreakOnTargetMove = 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);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
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;

namespace Content.Server.SimpleStation14.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 damagePerWatt = ElectrocutionSystem.ElectrifiedDamagePerWatt * 2;

var damage = args.ShockDamage.Value * args.SiemensCoefficient;
var charge = Math.Min(damage / damagePerWatt, 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);
}
}
Loading