Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixes #887

Merged
merged 2 commits into from
Nov 2, 2024
Merged

fixes #887

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 30 additions & 25 deletions Content.Server/Backmen/Soul/GolemSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Robust.Server.GameObjects;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;

namespace Content.Server.Backmen.Soul;

Expand Down Expand Up @@ -49,8 +50,8 @@ public override void Initialize()
SubscribeLocalEvent<SoulCrystalComponent, MindRemovedMessage>(OnRemMind);
SubscribeLocalEvent<SoulCrystalComponent, MapInitEvent>(OnSoulInit);

SubscribeLocalEvent<SoulCrystalComponent, EntInsertedIntoContainerMessage>(OnEntInserted);
SubscribeLocalEvent<SoulCrystalComponent, EntRemovedFromContainerMessage>(OnEntRemoved);
SubscribeLocalEvent<SoulCrystalComponent, EntGotInsertedIntoContainerMessage>(OnEntInserted);
SubscribeLocalEvent<SoulCrystalComponent, EntGotRemovedFromContainerMessage>(OnEntRemoved);

SubscribeLocalEvent<SoulCrystalComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<GolemComponent, DispelledEvent>(OnDispelled);
Expand Down Expand Up @@ -98,17 +99,17 @@ private void OnGetLaws(EntityUid uid, GolemComponent component, ref GetSiliconLa
args.Handled = true;
}

private void OnEntInserted(EntityUid uid, SoulCrystalComponent component, EntInsertedIntoContainerMessage args)
private void OnEntInserted(EntityUid uid, SoulCrystalComponent component, EntGotInsertedIntoContainerMessage args)
{
if(!TryComp<GolemComponent>(args.Entity, out var golemComponent))
if(args.Container.ID != CrystalSlot)
return;

RemCompDeferred<GhostTakeoverAvailableComponent>(uid);
}

private void OnEntRemoved(EntityUid uid, SoulCrystalComponent component, EntRemovedFromContainerMessage args)
private void OnEntRemoved(EntityUid uid, SoulCrystalComponent component, EntGotRemovedFromContainerMessage args)
{
if(!TryComp<GolemComponent>(args.Entity, out var golemComponent))
if(args.Container.ID != CrystalSlot)
return;

EnsureComp<GhostTakeoverAvailableComponent>(uid);
Expand Down Expand Up @@ -146,30 +147,35 @@ private void OnAfterInteract(EntityUid uid, SoulCrystalComponent component, Afte
_userInterfaceSystem.SetUiState(args.Target.Value, GolemUiKey.Key, state);
}

private void OnDispelled(EntityUid uid, GolemComponent component, DispelledEvent args)
public bool EjectSoul(Entity<GolemComponent> ent)
{
_slotsSystem.SetLock(uid, CrystalSlot, false);
_slotsSystem.TryEject(uid, CrystalSlot, null, out var item);
_slotsSystem.SetLock(uid, CrystalSlot, true);

if (item == null)
return;
_slotsSystem.SetLock(ent, CrystalSlot, false);
_slotsSystem.TryEject(ent, CrystalSlot, null, out var item);
_slotsSystem.SetLock(ent, CrystalSlot, true);

args.Handled = true;
if (item is not {Valid: true} soul)
return false;

var direction = new Vector2(_robustRandom.Next(-30, 30), _robustRandom.Next(-30, 30));
_throwing.TryThrow(item.Value, direction, _robustRandom.Next(1, 10));
_throwing.TryThrow(soul, direction, _robustRandom.Next(1, 10));

if (TryComp<AppearanceComponent>(uid, out var appearance))
_appearance.SetData(uid, ToggleVisuals.Toggled, false, appearance);
if (TryComp<AppearanceComponent>(ent, out var appearance))
_appearance.SetData(ent, ToggleVisuals.Toggled, false, appearance);

if (!_mindSystem.TryGetMind(uid, out var mindId, out var mind))
return;
_metaDataSystem.SetEntityName(ent, Loc.GetString("golem-base-name"));
_metaDataSystem.SetEntityDescription(ent, Loc.GetString("golem-base-desc"));
DirtyEntity(ent);

_metaDataSystem.SetEntityName(uid, Loc.GetString("golem-base-name"));
_metaDataSystem.SetEntityDescription(uid, Loc.GetString("golem-base-desc"));
_mindSystem.TransferTo(mindId, item);
DirtyEntity(uid);
if (!_mindSystem.TryGetMind(ent, out var mindId, out var mind))
return true;
_mindSystem.TransferTo(mindId, soul);

return true;
}

private void OnDispelled(EntityUid uid, GolemComponent component, DispelledEvent args)
{
args.Handled = EjectSoul((uid, component));
}

[ValidatePrototypeId<EntityPrototype>]
Expand All @@ -181,8 +187,7 @@ private void OnMobStateChanged(EntityUid uid, GolemComponent component, MobState
return;

QueueDel(uid);
var ev = new DispelledEvent();
RaiseLocalEvent(uid, ev, false);
EjectSoul((uid, component));

Spawn(Ash, Transform(uid).Coordinates);
_audioSystem.PlayPvs(component.DeathSound, uid);
Expand Down
64 changes: 49 additions & 15 deletions Content.Shared/Backmen/Standing/SharedLayingDownSystem.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Backmen.CCVar;
using Content.Shared.Backmen.Targeting;
using Content.Shared.Body.Components;
using Content.Shared.Buckle;
using Content.Shared.Buckle.Components;
Expand All @@ -12,17 +14,22 @@
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Pulling.Systems;
using Content.Shared.Movement.Systems;
using Content.Shared.Physics;
using Content.Shared.Popups;
using Content.Shared.Standing;
using Content.Shared.Stunnable;
using Content.Shared.Tag;
using Content.Shared.Traits.Assorted;
using Content.Shared.UserInterface;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Containers;
using Robust.Shared.Input.Binding;
using Robust.Shared.Map.Components;
using Robust.Shared.Network;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Player;
using Robust.Shared.Serialization;

Expand All @@ -44,6 +51,7 @@ public abstract class SharedLayingDownSystem : EntitySystem
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;

[Dependency] private readonly IConfigurationManager _config = default!;

Expand Down Expand Up @@ -161,6 +169,9 @@ public void TryProcessAutoGetUp(Entity<LayingDownComponent> ent)
if(_pulling.IsPulled(ent))
return;

if(!IsSafeStanUp(ent, out _))
return;

var autoUp = !_playerManager.TryGetSessionByEntity(ent, out var player) ||
GetAutoGetUp(ent, session: player);

Expand Down Expand Up @@ -189,7 +200,7 @@ private void ToggleStanding(ICommonSession? session)
}
else
{
RaiseNetworkEvent(new ChangeLayingDownEvent());
RaisePredictiveEvent(new ChangeLayingDownEvent());
}

}
Expand Down Expand Up @@ -224,7 +235,7 @@ private void OnChangeState(ChangeLayingDownEvent ev, EntitySessionEventArgs args
return;

//RaiseNetworkEvent(new CheckAutoGetUpEvent(GetNetEntity(uid)));
AutoGetUp((uid,layingDown));
TryProcessAutoGetUp((uid,layingDown));

if (_standing.IsDown(uid, standing))
TryStandUp(uid, layingDown, standing);
Expand All @@ -235,9 +246,11 @@ private void OnChangeState(ChangeLayingDownEvent ev, EntitySessionEventArgs args
private void OnStandingUpDoAfter(EntityUid uid, StandingStateComponent component, StandingUpDoAfterEvent args)
{
if (args.Handled || args.Cancelled || HasComp<KnockedDownComponent>(uid) ||
_mobState.IsIncapacitated(uid) || !_standing.Stand(uid))
_mobState.IsIncapacitated(uid) || !IsSafeStanUp(uid, out _) || !_standing.Stand(uid))
{
component.CurrentState = StandingState.Lying;
Dirty(uid,component);
return;
}

component.CurrentState = StandingState.Standing;
Expand Down Expand Up @@ -265,6 +278,28 @@ private void OnParentChanged(EntityUid uid, LayingDownComponent component, EntPa
_standing.Stand(uid, standingState);
}

public bool IsSafeStanUp(EntityUid entity, [NotNullWhen(false)] out EntityUid? obj)
{
var xform = Transform(entity);
if (xform.GridUid != null)
{
foreach (var ent in _map.GetAnchoredEntities(xform.GridUid.Value, Comp<MapGridComponent>(xform.GridUid.Value), xform.Coordinates))
{
if (!_tag.HasTag(ent, "Structure") || !TryComp<Robust.Shared.Physics.Components.PhysicsComponent>(ent, out var phys))
continue;

if(!phys.CanCollide|| (phys.CollisionMask & (int) CollisionGroup.MidImpassable) == 0x0)
continue;

obj = ent;
return false;
}
}
obj = null;
return true;
}

private static SoundSpecifier _bonkSound = new SoundCollectionSpecifier("TrayHit");
public bool TryStandUp(EntityUid uid, LayingDownComponent? layingDown = null, StandingStateComponent? standingState = null)
{
if (!Resolve(uid, ref standingState, false) ||
Expand All @@ -279,19 +314,18 @@ standingState.CurrentState is not StandingState.Lying ||
return false;
}

var xform = Transform(uid);
if (xform.GridUid != null)
if (!IsSafeStanUp(uid, out var obj))
{
foreach (var obj in _map.GetAnchoredEntities(xform.GridUid.Value, Comp<MapGridComponent>(xform.GridUid.Value), xform.Coordinates))
{
if (!_tag.HasTag(obj, "Structure"))
continue;

_popup.PopupEntity(Loc.GetString("laying-table-head-dmg",("obj", obj), ("self", uid)), obj, PopupType.MediumCaution);
_damageable.TryChangeDamage(uid, new DamageSpecifier(){DamageDict = {{"Blunt", 5}}}, ignoreResistances: true);
_stun.TryStun(uid, TimeSpan.FromSeconds(2), true);
return false;
}
_popup.PopupPredicted(
Loc.GetString("bonkable-success-message-user",("bonkable", obj.Value)),
Loc.GetString("bonkable-success-message-others",("bonkable", obj.Value), ("user", uid)),
obj.Value,
uid,
PopupType.MediumCaution);
_damageable.TryChangeDamage(uid, new DamageSpecifier(){DamageDict = {{"Blunt", 5}}}, ignoreResistances: true, targetPart: TargetBodyPart.Head);
_stun.TryStun(uid, TimeSpan.FromSeconds(2), true);
_audioSystem.PlayPredicted(_bonkSound, uid, obj.Value);
return false;
}

var args = new DoAfterArgs(EntityManager, uid, layingDown.StandingUpTime, new StandingUpDoAfterEvent(), uid)
Expand Down
19 changes: 18 additions & 1 deletion Content.Shared/Damage/Systems/DamageOnInteractSystem.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Content.Shared.Administration.Logs;
using Content.Shared.Backmen.Targeting;
using Content.Shared.Damage.Components;
using Content.Shared.Database;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction;
using Content.Shared.Inventory;
using Content.Shared.Popups;
Expand Down Expand Up @@ -58,8 +60,23 @@ private void OnHandInteract(Entity<DamageOnInteractComponent> entity, ref Intera
totalDamage = DamageSpecifier.ApplyModifierSet(totalDamage, protectiveEntity.Comp.DamageProtection);
}
}
// start-backmen: surgery

totalDamage = _damageableSystem.TryChangeDamage(args.User, totalDamage, origin: args.Target);
TargetBodyPart? targetPart = null;
var hands = CompOrNull<HandsComponent>(args.User);
if (hands is { ActiveHand: not null })
{
targetPart = hands.ActiveHand.Location switch
{
HandLocation.Left => TargetBodyPart.LeftArm,
HandLocation.Right => TargetBodyPart.RightArm,
_ => null
};
}

// end-backmen: surgery

totalDamage = _damageableSystem.TryChangeDamage(args.User, totalDamage, origin: args.Target, targetPart: targetPart);

if (totalDamage != null && totalDamage.AnyPositive())
{
Expand Down
33 changes: 23 additions & 10 deletions Content.Shared/Damage/Systems/DamageableSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public sealed class DamageableSystem : EntitySystem
private EntityQuery<AppearanceComponent> _appearanceQuery;
private EntityQuery<DamageableComponent> _damageableQuery;
private EntityQuery<MindContainerComponent> _mindContainerQuery;
private EntityQuery<TargetingComponent> _targetingQuery;

public override void Initialize()
{
Expand All @@ -38,6 +39,7 @@ public override void Initialize()
_appearanceQuery = GetEntityQuery<AppearanceComponent>();
_damageableQuery = GetEntityQuery<DamageableComponent>();
_mindContainerQuery = GetEntityQuery<MindContainerComponent>();
_targetingQuery = GetEntityQuery<TargetingComponent>();
}

/// <summary>
Expand Down Expand Up @@ -99,16 +101,21 @@ public void SetDamage(EntityUid uid, DamageableComponent damageable, DamageSpeci
/// The damage changed event is used by other systems, such as damage thresholds.
/// </remarks>
public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSpecifier? damageDelta = null,
bool interruptsDoAfters = true, EntityUid? origin = null, bool canSever = true, float partMultiplier = 1.00f)
bool interruptsDoAfters = true, EntityUid? origin = null, bool canSever = true, float partMultiplier = 1.00f,
TargetBodyPart? targetPart = null)
{
TargetBodyPart? targetPart = null;
;
component.Damage.GetDamagePerGroup(_prototypeManager, component.DamagePerGroup);
component.TotalDamage = component.Damage.GetTotal();
// If our target has a TargetingComponent, that means they will take limb damage
// And if their attacker also has one, then we use that part.
if (TryComp<TargetingComponent>(uid, out var target))
if (_targetingQuery.TryComp(uid, out var target))
{
if (origin.HasValue && TryComp<TargetingComponent>(origin.Value, out var targeter))
if (targetPart != null)
{
// keep from args
}
else if (origin.HasValue && _targetingQuery.TryComp(origin.Value, out var targeter))
{
targetPart = targeter.Target;
}
Expand Down Expand Up @@ -143,7 +150,7 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp
/// </returns>
public DamageSpecifier? TryChangeDamage(EntityUid? uid, DamageSpecifier damage, bool ignoreResistances = false,
bool interruptsDoAfters = true, DamageableComponent? damageable = null, EntityUid? origin = null,
bool? canSever = true, float? partMultiplier = 1.00f)
bool? canSever = true, float? partMultiplier = 1.00f, TargetBodyPart? targetPart = null)
{
if (!uid.HasValue || !_damageableQuery.Resolve(uid.Value, ref damageable, false))
{
Expand All @@ -156,7 +163,7 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp
return damage;
}

var before = new BeforeDamageChangedEvent(damage, origin);
var before = new BeforeDamageChangedEvent(damage, origin, targetPart);
RaiseLocalEvent(uid.Value, ref before);

if (before.Cancelled)
Expand All @@ -172,7 +179,7 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp
// use a local private field instead of creating a new dictionary here..
damage = DamageSpecifier.ApplyModifierSet(damage, modifierSet);
}
var ev = new DamageModifyEvent(damage, origin);
var ev = new DamageModifyEvent(damage, origin, targetPart);
RaiseLocalEvent(uid.Value, ev);
damage = ev.Damage;

Expand Down Expand Up @@ -204,7 +211,7 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp
}

if (delta.DamageDict.Count > 0)
DamageChanged(uid.Value, damageable, delta, interruptsDoAfters, origin, canSever ?? true, partMultiplier ?? 1.00f);
DamageChanged(uid.Value, damageable, delta, interruptsDoAfters, origin, canSever ?? true, partMultiplier ?? 1.00f, targetPart);

return delta;
}
Expand Down Expand Up @@ -322,7 +329,11 @@ private void DamageableHandleState(EntityUid uid, DamageableComponent component,
/// Raised before damage is done, so stuff can cancel it if necessary.
/// </summary>
[ByRefEvent]
public record struct BeforeDamageChangedEvent(DamageSpecifier Damage, EntityUid? Origin = null, bool Cancelled = false);
public record struct BeforeDamageChangedEvent(
DamageSpecifier Damage,
EntityUid? Origin = null,
TargetBodyPart? targetPart = null,
bool Cancelled = false);

/// <summary>
/// Raised on an entity when damage is about to be dealt,
Expand All @@ -339,12 +350,14 @@ public sealed class DamageModifyEvent : EntityEventArgs, IInventoryRelayEvent
public readonly DamageSpecifier OriginalDamage;
public DamageSpecifier Damage;
public EntityUid? Origin;
public readonly TargetBodyPart? TargetPart;

public DamageModifyEvent(DamageSpecifier damage, EntityUid? origin = null)
public DamageModifyEvent(DamageSpecifier damage, EntityUid? origin = null, TargetBodyPart? targetPart = null)
{
OriginalDamage = damage;
Damage = damage;
Origin = origin;
TargetPart = targetPart;
}
}

Expand Down
2 changes: 1 addition & 1 deletion Content.Shared/StatusEffect/StatusEffectsSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public override void Update(float frameTime)
continue;
}

foreach (var state in status.ActiveEffects)
foreach (var state in status.ActiveEffects.ToArray())
{
if (curTime > state.Value.Cooldown.Item2)
TryRemoveStatusEffect(uid, state.Key, status);
Expand Down
Loading
Loading