Skip to content

Commit 5d4ff27

Browse files
ShadesMarsBigfootBravocoderabbitai[bot]walksanatora
authored
IPC Patch (#3998)
<!-- IT'S NOT WIZDENS REPO, IF YOU WANT TO ADD YOUR CHANGES ON ALL SERVERS, CREATE PR TO WIZDENS REPO --> ## Short description <!-- What do you propose to change with your PR? --> Port: Far-Horizons-SS14/Far-Horizons-SS14#1039, Far-Horizons-SS14/Far-Horizons-SS14#1044 Also replace IPCSuit Tag with a Cooling Unit instead, making it more unique and intresting, these uses powercells and will need to be charged, Non-IPC can still use it to slowly cool their bodies. (its will try to lower temperature to the preferred body temp. ## Why we need to add this <!-- What is the reason for adding these changes? Please post links to Discussions as well as Bug Reports here. Please describe how this will change the game balance. --> Fixes and Patch to release IPC into the world. ## Media (Video/Screenshots) <!-- If your PR contains in-game changes you must provide screenshots/videos of the changes. --> <img width="1125" height="874" alt="image" src="https://github.com/user-attachments/assets/ca08efca-bd6d-4f84-9cb4-804f5fcb62cc" /> <img width="443" height="213" alt="image" src="https://github.com/user-attachments/assets/b7fc69a8-faa9-430f-a4d0-3054ec6c3b84" /> ## Checks <!-- check boxes for faster reviewing of your PR --> - [x] I do not require assistance to complete the PR. - [x] Before posting/requesting review of a PR, I have verified that the changes work. - [x] I have added screenshots/videos of the changes, or this PR does not change in-game mechanics. - [x] I affirm that my changes are licensed under the [MIT License](https://github.com/ss14Starlight/space-station-14/blob/Starlight/LICENSE.TXT) and grant permission for use in this repository under its conditions. **Changelog** :cl: Shades, princess_gurchi - add: Cooling Units, IPC will need those if they wish to regulate their temperature. - tweak: dead IPC body will now cool down much faster if it reached high temperatures. - tweak: IPCs will burn for less time than organics. - fix: Preventing silicons from having glitched visuals for longer than they are supposed to. - fix: Fix a bug where IPC could use MechReactor. - add: IPC Survival Kit. - fix: Fix a bug where you can use an AIInterface on the IPC. - fix: Fix where IPC get Airloss/Toxins/Genetic Damage. - tweak: Enable IPC Again. --------- Co-authored-by: Qerd <73325910+BigfootBravo@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Walker Fowlkes <47339836+walksanatora@users.noreply.github.com>
1 parent 1fee5c9 commit 5d4ff27

72 files changed

Lines changed: 851 additions & 242 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Content.Client/Humanoid/MarkingPicker.xaml.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,8 @@ private void OnUsedMarkingSelected(ItemList.ItemListSelectedEventArgs item)
412412
_selectedMarking = CMarkingsUsed[item.ItemIndex];
413413
var prototype = (MarkingPrototype)_selectedMarking.Metadata!;
414414

415+
Glowing.Visible = !prototype.ForcedGlowing;
416+
415417
if (prototype.ForcedColoring)
416418
{
417419
CMarkingColors.Visible = false;

Content.Client/_FarHorizons/Silicons/IPC/IPCBoundUserInterface.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,7 @@ protected override void Open()
2020
SendMessage(new IPCEjectBrainBuiMessage());
2121
};
2222

23-
/* The eject battery button is currently bugged and freezes the individual who uses it. Uncomment this when a fix is applied!
24-
_menu.EjectBatteryButtonPressed += () =>
25-
{
26-
SendMessage(new IPCEjectBatteryBuiMessage());
27-
};
28-
23+
/* Unsure why this thing is commented but... Lets keep it commented.
2924
_menu.NameChanged += name =>
3025
{
3126
SendMessage(new IPCSetNameBuiMessage(name));

Content.Server/Ghost/GhostSystem.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Content.Server.Ghost.Components;
77
using Content.Server.Ghost.Roles;
88
using Content.Server.Mind;
9+
using Content.Server.Mobs;
910
using Content.Server.Roles.Jobs;
1011
using Content.Shared.Actions;
1112
using Content.Shared.CCVar;
@@ -581,6 +582,8 @@ public bool OnGhostAttempt(EntityUid mindId, bool canReturnGlobal, bool viaComma
581582
//todo: what if they dont breathe lol
582583
//cry deeply
583584

585+
// ! THIS IS A STARLIGHT MOMENT... I NEED MY SHADEKIN AND IPC TO DIIIIIE!
586+
584587
FixedPoint2 dealtDamage = 200;
585588

586589
if (TryComp<DamageableComponent>(playerEntity, out var damageable)
@@ -590,7 +593,13 @@ public bool OnGhostAttempt(EntityUid mindId, bool canReturnGlobal, bool viaComma
590593
dealtDamage = playerDeadThreshold - damageable.TotalDamage;
591594
}
592595

593-
DamageSpecifier damage = new(_prototypeManager.Index(AsphyxiationDamageType), dealtDamage);
596+
// Starlight - Start
597+
var damageType = _prototypeManager.Index(AsphyxiationDamageType);
598+
if (TryComp<DeathgaspComponent>(playerEntity, out var deathgasp))
599+
damageType = _prototypeManager.Index(deathgasp.DamageType);
600+
601+
DamageSpecifier damage = new(damageType, dealtDamage);
602+
// Starlight - End
594603

595604
_damageable.ChangeDamage(playerEntity.Value, damage, true);
596605
}

Content.Server/Mobs/DeathgaspComponent.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using Content.Shared.Chat.Prototypes;
2+
using Content.Shared.Damage.Prototypes;
3+
using Robust.Shared.Prototypes;
24
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
35

46
namespace Content.Server.Mobs;
@@ -15,4 +17,8 @@ public sealed partial class DeathgaspComponent : Component
1517
/// </summary>
1618
[DataField("prototype", customTypeSerializer:typeof(PrototypeIdSerializer<EmotePrototype>))]
1719
public string Prototype = "DefaultDeathgasp";
20+
21+
// Starlight
22+
[DataField]
23+
public ProtoId<DamageTypePrototype> DamageType = "Asphyxiation";
1824
}

Content.Server/_FarHorizons/Silicons/Glitching/GlitchingSystem.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ public sealed class GlitchingSystem : EntitySystem
1212
[Dependency] private readonly IGameTiming _timing = default!;
1313
[Dependency] private readonly PopupSystem _popup = default!;
1414

15+
private TimeSpan _nextUpdate = TimeSpan.Zero;
16+
private TimeSpan _refreshRate = TimeSpan.FromSeconds(5);
17+
1518
public override void Initialize()
1619
{
1720
base.Initialize();
@@ -20,6 +23,21 @@ public override void Initialize()
2023
ApplyGlitch(ent.Owner, ent.Comp.Duration, ent.Comp.Ramp));
2124
}
2225

26+
public override void Update(float frameTime)
27+
{
28+
base.Update(frameTime);
29+
30+
if (_timing.CurTime < _nextUpdate) return;
31+
_nextUpdate = _timing.CurTime + _refreshRate;
32+
33+
var query = EntityQueryEnumerator<GlitchingEffectComponent>();
34+
while (query.MoveNext(out var uid, out var comp))
35+
{
36+
if (_timing.CurTime >= comp.FinishAt)
37+
RemCompDeferred<GlitchingEffectComponent>(uid);
38+
}
39+
}
40+
2341
public void ApplyGlitch(EntityUid uid, TimeSpan effectDuration, TimeSpan effectRamp)
2442
{
2543
var comp = EnsureComp<GlitchingEffectComponent>(uid);

Content.Server/_FarHorizons/Silicons/IPC/IPCSystem.Battery.cs

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Content.Shared.PowerCell;
1010
using Content.Shared.Power;
1111
using Content.Shared.Power.Components;
12+
using Content.Shared.PowerCell.Components;
1213

1314
namespace Content.Server._FarHorizons.Silicons.IPC;
1415

@@ -32,8 +33,15 @@ protected override void SetupBattery()
3233
SubscribeLocalEvent<IPCBatteryComponent, BeingGibbedEvent>(OnBatteryGibbed);
3334
}
3435

35-
private void OnBatteryGibbed(Entity<IPCBatteryComponent> ent, ref BeingGibbedEvent args) =>
36-
_container.EmptyContainer(ent.Comp.BatteryContainerSlot);
36+
private void OnBatteryGibbed(Entity<IPCBatteryComponent> ent, ref BeingGibbedEvent args)
37+
{
38+
if (!TryComp<PowerCellSlotComponent>(ent, out var slot)
39+
|| !_container.TryGetContainer(ent, slot.CellSlotId, out var container))
40+
return;
41+
42+
_container.EmptyContainer(container);
43+
}
44+
3745
private void OnBatteryTimerStart(Entity<IPCBatteryComponent> ent, ref IPCBatteryDeathTimerStart args)
3846
{
3947
if (!TryComp<IPCReviveComponent>(ent, out var revive) || revive.DamageSoundEnt == null)
@@ -47,15 +55,15 @@ private void OnBatteryTimerEnd(Entity<IPCBatteryComponent> ent, ref IPCBatteryDe
4755
_audio.Stop(ent.Comp.Playing, ent.Comp.Playing?.Comp);
4856
ent.Comp.Playing = null;
4957

50-
if(!args.Interrupted && TryComp<MobStateComponent>(ent, out var mobState))
58+
if (!args.Interrupted && TryComp<MobStateComponent>(ent, out var mobState))
5159
{
5260
_chat.TryEmoteWithChat(ent, ent.Comp.NoPowerDeathEmote);
5361
_state.ChangeMobState(ent, MobState.Dead, mobState);
5462
}
5563
}
5664
private void OnBatteryTimerUpdate(Entity<IPCBatteryComponent> ent, ref IPCBatteryDeathTimerUpdate args)
5765
{
58-
if(ent.Comp.WarningText != null)
66+
if (ent.Comp.WarningText != null)
5967
_popup.PopupEntity(Loc.GetString(ent.Comp.WarningText), ent, PopupType.LargeCaution);
6068
}
6169

@@ -102,7 +110,7 @@ private void OnPowerCellSlotEmpty(Entity<IPCBatteryComponent> ent, ref PowerCell
102110

103111
private void UpdateDeathTimer(Entity<IPCBatteryComponent> ent, PowerCellChangedEvent? slotChangedEv = null)
104112
{
105-
if(!_powerCell.HasDrawCharge(ent.Owner))
113+
if (!_powerCell.HasDrawCharge(ent.Owner))
106114
StartDeathTimer(ent);
107115
else
108116
StopDeathTimer(ent);
@@ -111,7 +119,8 @@ private void UpdateDeathTimer(Entity<IPCBatteryComponent> ent, PowerCellChangedE
111119
_drainer.SetBattery(ent.Owner, battery);
112120
}
113121

114-
public void StartDeathTimer(Entity<IPCBatteryComponent> ent){
122+
public void StartDeathTimer(Entity<IPCBatteryComponent> ent)
123+
{
115124
if (ent.Comp.TimerActive)
116125
return;
117126

@@ -125,7 +134,8 @@ public void StartDeathTimer(Entity<IPCBatteryComponent> ent){
125134
RaiseLocalEvent(ent, new IPCBatteryDeathTimerStart());
126135
}
127136

128-
public void StopDeathTimer(Entity<IPCBatteryComponent> ent){
137+
public void StopDeathTimer(Entity<IPCBatteryComponent> ent)
138+
{
129139
if (!ent.Comp.TimerActive)
130140
return;
131141

@@ -150,26 +160,4 @@ protected override void StartDrain(Entity<IPCBatteryComponent> user, EntityUid t
150160

151161
_doAfter.TryStartDoAfter(doAfterArgs);
152162
}
153-
154-
public void DrainBattery(Entity<IPCBatteryComponent?> ent)
155-
{
156-
if (!Resolve(ent, ref ent.Comp) ||
157-
ent.Comp.BatteryContainerSlot.ContainedEntity == null)
158-
return;
159-
160-
_battery.SetCharge(ent.Comp.BatteryContainerSlot.ContainedEntity.Value, 0);
161-
}
162-
163-
public void EjectBattery(Entity<IPCBatteryComponent?> ent, EntityUid user)
164-
{
165-
166-
if (!Resolve(ent, ref ent.Comp) ||
167-
ent.Comp.BatteryContainerSlot.ContainedEntity == null)
168-
return;
169-
170-
var battery = ent.Comp.BatteryContainerSlot.ContainedEntity.Value;
171-
_container.EmptyContainer(ent.Comp.BatteryContainerSlot);
172-
173-
_hands.PickupOrDrop(user, battery, dropNear: true);
174-
}
175163
}

Content.Server/_FarHorizons/Silicons/IPC/IPCSystem.Brain.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Content.Shared._FarHorizons.Silicons.IPC.Components;
2+
using Content.Shared._Starlight.Silicons.Borgs;
23
using Content.Shared.Body.Events;
34
using Content.Shared.Database;
45
using Content.Shared.Gibbing;
@@ -62,7 +63,8 @@ private void OnBrainMindAdded(Entity<IPCBrainComponent> ent, ref MindAddedMessag
6263
private void OnBrainInteractUsing(Entity<IPCBrainHolderComponent> ent, ref AfterInteractUsingEvent args)
6364
{
6465
if (!args.CanReach || args.Handled ||
65-
!TryComp(args.Used, out BorgBrainComponent? brain))
66+
!TryComp(args.Used, out BorgBrainComponent? brain)
67+
|| HasComp<StationAIShuntComponent>(args.Used)) // Yeah, No "AI" IPC...
6668
return;
6769

6870
if (TryComp<WiresPanelComponent>(ent, out var panel) && !panel.Open)

Content.Server/_FarHorizons/Silicons/IPC/IPCSystem.Revive.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
using Content.Shared.DoAfter;
66
using Content.Shared.Medical;
77
using Content.Shared.Mobs;
8+
using Content.Shared.Power.Components;
9+
using Content.Shared.PowerCell.Components;
810
using Content.Shared.Traits.Assorted;
911
using Content.Shared.Verbs;
1012
using Robust.Shared.Utility;
@@ -40,8 +42,11 @@ private void OnBeforeZap(Entity<IPCReviveComponent> ent, ref TargetBeforeDefibri
4042
if (ent.Comp.DefibDamage != null)
4143
_damageable.TryChangeDamage(ent.Owner, ent.Comp.DefibDamage);
4244

43-
if (ent.Comp.DefibBatteryDrain)
44-
DrainBattery((ent, null));
45+
if (ent.Comp.DefibBatteryDrain && _powerCell.TryGetBatteryFromEntityOrSlot(ent.Owner, out var battery) && TryComp<BatteryComponent>(battery, out var batterycomp))
46+
{
47+
_electrocution.TryDoElectrocution(args.EntityUsingDefib, ent, defib.ZapDamage, defib.WritheDuration, true, ignoreInsulation: true);
48+
_battery.SetCharge((battery.Value, batterycomp), 0);
49+
}
4550

4651
_audio.PlayPvs(defib.ZapSound, args.Defib);
4752
args.Cancel();

Content.Server/_FarHorizons/Silicons/IPC/IPCSystem.ThermalRegulation.cs

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
using Content.Shared.Alert;
44
using Content.Shared.Atmos;
55
using Robust.Shared.Prototypes;
6+
using Content.Shared.Inventory;
7+
using Content.Shared._Starlight.CoolingUnit;
8+
using Content.Shared.Item.ItemToggle.Components;
69

710
namespace Content.Server._FarHorizons.Silicons.IPC;
811

@@ -13,7 +16,7 @@ protected override void UpdateThermals(float deltaTime)
1316
var query = EntityQueryEnumerator<IPCThermalRegulationComponent>();
1417
while (query.MoveNext(out var uid, out var comp))
1518
{
16-
if(_timing.CurTime < comp.NextUpdate ||
19+
if (_timing.CurTime < comp.NextUpdate ||
1720
!TryComp<TemperatureComponent>(uid, out var temp) ||
1821
temp.CurrentTemperature == 0)
1922
continue;
@@ -27,16 +30,11 @@ public void HandleTemperature(Entity<IPCThermalRegulationComponent, TemperatureC
2730
{
2831
if (!Resolve(ent, ref ent.Comp2) ||
2932
ExternalCooling(ent, ent.Comp2) ||
30-
_atmos.GetContainingMixture(ent.Owner) is not GasMixture gas)
33+
_atmos.GetContainingMixture(ent.Owner) is not { } gas)
3134
return;
3235

33-
var passiveHeat = 0f;
34-
if (ent.Comp2.CurrentTemperature > gas.Temperature)
35-
passiveHeat -= ent.Comp1.RadiateHeat;
36-
if (!_state.IsDead(ent))
37-
passiveHeat += ent.Comp1.ProduceHeat;
36+
RadiateHeat(ent, ent.Comp2, gas.Temperature, _state.IsDead(ent) ? 0 : ent.Comp1.ProduceHeat);
3837

39-
_tempSys.ChangeHeat(ent, passiveHeat, ignoreHeatResistance: true, ent);
4038
ent.Comp1.FansCurrentlyOff = FanShutOff(ent, gas);
4139

4240
ent.Comp1.CurrentTemp = ent.Comp2.CurrentTemperature;
@@ -56,22 +54,31 @@ public void HandleTemperature(Entity<IPCThermalRegulationComponent, TemperatureC
5654

5755
private bool ExternalCooling(Entity<IPCThermalRegulationComponent> ent, TemperatureComponent temp)
5856
{
59-
if (ent.Comp.ExternalCoolingCheckSlots.Count == 0)
60-
return false;
61-
62-
foreach (var slotID in ent.Comp.ExternalCoolingCheckSlots)
63-
if (!_container.TryGetContainer(ent, slotID, out var container) ||
64-
container.ContainedEntities.Count != 1 ||
65-
!_tag.HasTag(container.ContainedEntities[0], ent.Comp.ExternalCoolingTag))
66-
return false;
67-
68-
ent.Comp.FansCurrentlyOff = false;
69-
ent.Comp.CanSwitchModeIn = TimeSpan.Zero;
70-
ent.Comp.CurrentTemp = temp.CurrentTemperature;
71-
HandleFans(ent, temp, null, true, true);
72-
UpdateThermalsAlert(ent);
73-
Dirty(ent);
74-
return true;
57+
if (HasComp<InventoryComponent>(ent) && _inventorySystem.TryGetSlots(ent, out var slots))
58+
foreach (var slot in slots)
59+
if (_inventorySystem.TryGetSlotEntity(ent, slot.Name, out var slotent) && HasComp<CoolingUnitComponent>(slotent)
60+
&& TryComp<ItemToggleComponent>(slotent, out var itemtoggle) && itemtoggle.Activated)
61+
{
62+
ent.Comp.FansCurrentlyOff = false;
63+
ent.Comp.CanSwitchModeIn = TimeSpan.Zero;
64+
ent.Comp.CurrentTemp = temp.CurrentTemperature;
65+
HandleFans(ent, temp, null, true, true);
66+
UpdateThermalsAlert(ent);
67+
Dirty(ent);
68+
return true;
69+
}
70+
71+
return false;
72+
}
73+
74+
private void RadiateHeat(Entity<IPCThermalRegulationComponent> ent, TemperatureComponent temp, float externalTemp, float produceHeat = 0)
75+
{
76+
var tempDelta = temp.CurrentTemperature - externalTemp;
77+
78+
if (tempDelta > 0)
79+
_tempSys.ChangeHeat(ent, produceHeat - (tempDelta * ent.Comp.RadiateHeatEfficiency), ignoreHeatResistance: true, temp);
80+
else if (produceHeat > 0)
81+
_tempSys.ChangeHeat(ent, produceHeat, ignoreHeatResistance: true, temp);
7582
}
7683

7784
private bool FanShutOff(Entity<IPCThermalRegulationComponent> ent, GasMixture gas) =>
@@ -82,7 +89,7 @@ private bool FanShutOff(Entity<IPCThermalRegulationComponent> ent, GasMixture ga
8289

8390
private static bool CanSwitchFan(Entity<IPCThermalRegulationComponent> ent)
8491
{
85-
if(ent.Comp.CanSwitchModeIn <= TimeSpan.Zero)
92+
if (ent.Comp.CanSwitchModeIn <= TimeSpan.Zero)
8693
return true;
8794

8895
ent.Comp.CanSwitchModeIn -= ent.Comp.RefreshRate;

Content.Server/_FarHorizons/Silicons/IPC/IPCSystem.Ui.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ public sealed partial class IPCSystem
1313
private void InitializeUI()
1414
{
1515
SubscribeLocalEvent<IPCUserInterfaceComponent, IPCEjectBrainBuiMessage>(OnEjectBrainBuiMessage);
16-
SubscribeLocalEvent<IPCUserInterfaceComponent, IPCEjectBatteryBuiMessage>(OnEjectBatteryBuiMessage);
1716
SubscribeLocalEvent<IPCUserInterfaceComponent, IPCSetNameBuiMessage>(OnSetNameBuiMessage);
1817
SubscribeLocalEvent<IPCUserInterfaceComponent, BoundUIOpenedEvent>(OnUIOpened);
1918

@@ -59,19 +58,6 @@ private void OnEjectBrainBuiMessage(Entity<IPCUserInterfaceComponent> ent, ref I
5958
EjectBrain(ent.Owner, args.Actor);
6059
}
6160

62-
private void OnEjectBatteryBuiMessage(Entity<IPCUserInterfaceComponent> ent, ref IPCEjectBatteryBuiMessage args)
63-
{
64-
if (!TryComp<IPCLockComponent>(ent.Owner, out var lockComp)) return;
65-
66-
if (lockComp.Lock.Locked || !lockComp.WiresPanel.Open)
67-
{
68-
_popup.PopupEntity(Loc.GetString(lockComp.LockedPopupMessage), ent);
69-
_audio.PlayPvs(lockComp.LockedSound, ent);
70-
return;
71-
}
72-
73-
EjectBattery(ent.Owner, args.Actor);
74-
}
7561
private void OnSetNameBuiMessage(Entity<IPCUserInterfaceComponent> ent, ref IPCSetNameBuiMessage args)
7662
{
7763
if (args.Name.Length > _maxNameLength ||

0 commit comments

Comments
 (0)