diff --git a/Content.Client/Backmen/Surgery/SurgeryBui.cs b/Content.Client/Backmen/Surgery/SurgeryBui.cs index 6e396d40cc3..5d4b67dd907 100644 --- a/Content.Client/Backmen/Surgery/SurgeryBui.cs +++ b/Content.Client/Backmen/Surgery/SurgeryBui.cs @@ -127,14 +127,15 @@ int GetScore(BodyPartType? partType) return partType switch { BodyPartType.Head => 1, - BodyPartType.Torso => 2, - BodyPartType.Arm => 3, - BodyPartType.Hand => 4, - BodyPartType.Leg => 5, - BodyPartType.Foot => 6, - // BodyPartType.Tail => 7, No tails yet! - BodyPartType.Other => 8, - _ => 9 + BodyPartType.Chest => 2, + BodyPartType.Groin => 3, + BodyPartType.Arm => 4, + BodyPartType.Hand => 5, + BodyPartType.Leg => 6, + BodyPartType.Foot => 7, + // BodyPartType.Tail => 8, No tails yet! + BodyPartType.Other => 9, + _ => 10 }; } diff --git a/Content.Client/Backmen/Surgery/Wounds/WoundableVisualsComponent.cs b/Content.Client/Backmen/Surgery/Wounds/WoundableVisualsComponent.cs new file mode 100644 index 00000000000..2e0279d47b3 --- /dev/null +++ b/Content.Client/Backmen/Surgery/Wounds/WoundableVisualsComponent.cs @@ -0,0 +1,29 @@ +using Content.Shared.Backmen.Surgery.Wounds; +using Content.Shared.FixedPoint; + +namespace Content.Client.Backmen.Surgery.Wounds; + +[RegisterComponent] +public sealed partial class WoundableVisualsComponent : Component +{ + [DataField(required: true)] public Enum OccupiedLayer; + + [DataField] public Dictionary? DamageOverlayGroups = new(); + [DataField] public string BleedingOverlay; + + [DataField(required: true)] public List Thresholds = []; + [DataField] public Dictionary BleedingThresholds = new() + { + { BleedingSeverity.Minor, 2.6 }, + { BleedingSeverity.Severe, 7 }, + }; +} + +// :fort: +[DataDefinition] +public sealed partial class WoundVisualizerSprite +{ + [DataField(required: true)] public string Sprite = default!; + + [DataField] public string? Color; +} diff --git a/Content.Client/Backmen/Surgery/Wounds/WoundableVisualsSystem.cs b/Content.Client/Backmen/Surgery/Wounds/WoundableVisualsSystem.cs new file mode 100644 index 00000000000..8ea0d3f2e23 --- /dev/null +++ b/Content.Client/Backmen/Surgery/Wounds/WoundableVisualsSystem.cs @@ -0,0 +1,349 @@ +using System.Linq; +using Content.Shared.Backmen.Surgery.Body.Events; +using Content.Shared.Backmen.Surgery.Traumas.Components; +using Content.Shared.Backmen.Surgery.Wounds; +using Content.Shared.Backmen.Surgery.Wounds.Components; +using Content.Shared.Backmen.Surgery.Wounds.Systems; +using Content.Shared.Body.Part; +using Content.Shared.Body.Systems; +using Content.Shared.FixedPoint; +using Content.Shared.Humanoid; +using Robust.Client.GameObjects; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Robust.Shared.Utility; + +namespace Content.Client.Backmen.Surgery.Wounds; + +public sealed class WoundableVisualsSystem : VisualizerSystem +{ + [Dependency] private readonly SharedBodySystem _body = default!; + + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly IPrototypeManager _protoMan = default!; + + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + + private const float AltBleedingSpriteChance = 0.15f; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(InitializeEntity, after:[typeof(WoundSystem)]); + SubscribeLocalEvent(WoundableRemoved); + SubscribeLocalEvent(WoundableConnected); + } + + private void InitializeEntity(EntityUid uid, WoundableVisualsComponent component, ComponentInit args) + { + if (!TryComp(uid, out SpriteComponent? partSprite)) + return; + + foreach (var (group, sprite) in component.DamageOverlayGroups!) + { + AddDamageLayerToSprite(partSprite, + sprite.Sprite, + $"{component.OccupiedLayer}_{group}_100", + $"{component.OccupiedLayer}{group}", + sprite.Color); + } + + if (Equals(component.OccupiedLayer, HumanoidVisualLayers.LHand) + || Equals(component.OccupiedLayer, HumanoidVisualLayers.RHand) + || Equals(component.OccupiedLayer, HumanoidVisualLayers.LFoot) + || Equals(component.OccupiedLayer, HumanoidVisualLayers.RFoot)) + return; + + AddDamageLayerToSprite(partSprite, + component.BleedingOverlay, + $"{component.OccupiedLayer}_Minor", + $"{component.OccupiedLayer}Bleeding"); + } + + private void WoundableConnected(EntityUid uid, WoundableVisualsComponent component, BodyPartAddedEvent args) + { + var bodyPart = args.Part.Comp; + if (!bodyPart.Body.HasValue || !TryComp(bodyPart.Body.Value, out SpriteComponent? bodySprite)) + return; + + foreach (var (group, sprite) in component.DamageOverlayGroups!) + { + if (!bodySprite.LayerMapTryGet($"{component.OccupiedLayer}{group}", out _)) + { + AddDamageLayerToSprite(bodySprite, + sprite.Sprite, + $"{component.OccupiedLayer}_{group}_100", + $"{component.OccupiedLayer}{group}", + sprite.Color); + } + } + + if (Equals(component.OccupiedLayer, HumanoidVisualLayers.LHand) + || Equals(component.OccupiedLayer, HumanoidVisualLayers.RHand) + || Equals(component.OccupiedLayer, HumanoidVisualLayers.LFoot) + || Equals(component.OccupiedLayer, HumanoidVisualLayers.RFoot)) + return; + + if (!bodySprite.LayerMapTryGet($"{component.OccupiedLayer}Bleeding", out _)) + { + AddDamageLayerToSprite(bodySprite, + component.BleedingOverlay, + $"{component.OccupiedLayer}_Minor", + $"{component.OccupiedLayer}Bleeding"); + } + + UpdateWoundableVisuals(uid, component, bodySprite); + } + + private void WoundableRemoved(EntityUid uid, WoundableVisualsComponent component, BodyPartRemovedEvent args) + { + var body = args.Part.Comp.Body; + if (!TryComp(body, out SpriteComponent? bodySprite)) + return; + + foreach (var (group, _) in component.DamageOverlayGroups!) + { + if (!bodySprite.LayerMapTryGet($"{component.OccupiedLayer}{group}", out var layer)) + continue; + + bodySprite.LayerSetVisible(layer, false); + bodySprite.LayerMapRemove(layer); + } + + if (bodySprite.LayerMapTryGet($"{component.OccupiedLayer}Bleeding", out var bleeds)) + { + bodySprite.LayerSetVisible(bleeds, false); + bodySprite.LayerMapRemove(bleeds); + } + + if (TryComp(uid, out SpriteComponent? partSprite)) + UpdateWoundableVisuals(uid, component, partSprite); + } + + protected override void OnAppearanceChange(EntityUid uid, WoundableVisualsComponent component, ref AppearanceChangeEvent args) + { + var bodyPart = Comp(uid); + if (!bodyPart.Body.HasValue) + { + if (TryComp(uid, out SpriteComponent? partSprite)) + UpdateWoundableVisuals(uid, component, partSprite); + return; + } + + if (TryComp(bodyPart.Body.Value, out SpriteComponent? bodySprite)) + UpdateWoundableVisuals(uid, component, bodySprite); + } + + private void AddDamageLayerToSprite(SpriteComponent spriteComponent, string sprite, string state, string mapKey, string? color = null) + { + var newLayer = spriteComponent.AddLayer( + new SpriteSpecifier.Rsi( + new ResPath(sprite), + state + )); + spriteComponent.LayerMapSet(mapKey, newLayer); + if (color != null) + spriteComponent.LayerSetColor(newLayer, Color.FromHex(color)); + spriteComponent.LayerSetVisible(newLayer, false); + } + + private void UpdateWoundableVisuals(EntityUid uid, WoundableVisualsComponent visuals, SpriteComponent bodySprite) + { + if (!_appearance.TryGetData(uid, WoundableVisualizerKeys.Wounds, out var wounds)) + return; + + var damagePerGroup = new Dictionary(); + foreach (var comp in wounds.GroupList.Select(GetEntity).Where(ent => !TerminatingOrDeleted(ent)).Select(Comp)) + { + if (comp.DamageGroup == null) + continue; + + if (!damagePerGroup.TryAdd(comp.DamageGroup, comp.WoundSeverityPoint)) + { + damagePerGroup[comp.DamageGroup] += comp.WoundSeverityPoint; + } + } + + if (damagePerGroup.Count == 0 && visuals.DamageOverlayGroups != null) + { + foreach (var damage in visuals.DamageOverlayGroups!) + { + bodySprite.LayerMapTryGet($"{visuals.OccupiedLayer}{damage.Key}", out var damageLayer); + + UpdateDamageLayerState(bodySprite, damageLayer, $"{visuals.OccupiedLayer}_{damage.Key}", 0); + } + } + + foreach (var (type, damage) in damagePerGroup) + { + if (!visuals.DamageOverlayGroups!.ContainsKey(type)) + continue; + + bodySprite.LayerMapTryGet($"{visuals.OccupiedLayer}{type}", out var damageLayer); + + UpdateDamageLayerState(bodySprite, damageLayer, $"{visuals.OccupiedLayer}_{type}", GetThreshold(damage, visuals)); + } + + UpdateBleeding(uid, visuals, visuals.OccupiedLayer, bodySprite); + } + + private void UpdateBleeding(EntityUid uid, WoundableVisualsComponent comp, Enum layer, SpriteComponent sprite) + { + if (!TryComp(uid, out var bodyPart) || !bodyPart.Body.HasValue) + return; + + if (bodyPart.PartType is BodyPartType.Foot or BodyPartType.Hand) + { + if (!_body.TryGetParentBodyPart(uid, out var parentUid, out _)) + return; + + if (!_appearance.TryGetData(uid, WoundableVisualizerKeys.Wounds, out var wounds) + || !_appearance.TryGetData(parentUid.Value, WoundableVisualizerKeys.Wounds, out var parentWounds)) + return; + + var woundList = new List(); + woundList.AddRange(wounds.GroupList.Select(GetEntity)); + woundList.AddRange(parentWounds.GroupList.Select(GetEntity)); + + var totalBleeds = (FixedPoint2) 0; + foreach (var wound in woundList) + { + if (TryComp(wound, out var bleeds)) + totalBleeds += bleeds.BleedingAmount; + } + + var symmetry = bodyPart.Symmetry == BodyPartSymmetry.Left ? "L" : "R"; + var partType = bodyPart.PartType == BodyPartType.Foot ? "Leg" : "Arm"; + + var part = symmetry + partType; + + sprite.LayerMapTryGet($"{part}Bleeding", out var parentBleedingLayer); + + var color = GetBleedsColor(bodyPart.Body.Value); + sprite.LayerSetColor(parentBleedingLayer, color); + + UpdateBleedingLayerState( + sprite, + parentBleedingLayer, + part, + totalBleeds, + GetBleedingThreshold(totalBleeds, comp)); + } + else + { + if (!_appearance.TryGetData(uid, WoundableVisualizerKeys.Wounds, out var wounds)) + return; + + var totalBleeds = (FixedPoint2) 0; + foreach (var wound in wounds.GroupList.Select(GetEntity)) + { + if (TryComp(wound, out var bleeds)) + totalBleeds += bleeds.BleedingAmount; + } + + sprite.LayerMapTryGet($"{layer}Bleeding", out var bleedingLayer); + + var color = GetBleedsColor(bodyPart.Body.Value); + sprite.LayerSetColor(bleedingLayer, color); + + UpdateBleedingLayerState(sprite, + bleedingLayer, + layer.ToString(), + totalBleeds, + GetBleedingThreshold(totalBleeds, comp)); + } + } + + private Color GetBleedsColor(EntityUid body) + { + // return dark red.. If for some reason there is no blood in this entity. + if (!TryComp(body, out var bloodstream)) + return Color.DarkRed; + + return _protoMan.Index(bloodstream.BloodReagent).SubstanceColor; + } + + private FixedPoint2 GetThreshold(FixedPoint2 threshold, WoundableVisualsComponent comp) + { + var nearestSeverity = (FixedPoint2) 0; + + foreach (var value in comp.Thresholds.OrderByDescending(kv => kv.Value)) + { + if (threshold < value) + continue; + + nearestSeverity = value; + break; + } + + return nearestSeverity; + } + + private BleedingSeverity GetBleedingThreshold(FixedPoint2 threshold, WoundableVisualsComponent comp) + { + var nearestSeverity = BleedingSeverity.Minor; + + foreach (var (key, value) in comp.BleedingThresholds.OrderByDescending(kv => kv.Value)) + { + if (threshold < value) + continue; + + nearestSeverity = key; + break; + } + + return nearestSeverity; + } + + private void UpdateBleedingLayerState(SpriteComponent spriteComponent, int spriteLayer, string statePrefix, FixedPoint2 damage, BleedingSeverity threshold) + { + if (damage <= 0) + { + spriteComponent.LayerSetVisible(spriteLayer, false); + } + else + { + if (!spriteComponent[spriteLayer].Visible) + { + spriteComponent.LayerSetVisible(spriteLayer, true); + } + + if (_random.Prob(AltBleedingSpriteChance)) + { + var rsi = spriteComponent.LayerGetActualRSI(spriteLayer); + + if (rsi != null && rsi.TryGetState($"{statePrefix}_{threshold}_alt", out _)) + { + spriteComponent.LayerSetState(spriteLayer, $"{statePrefix}_{threshold}_alt"); + } + } + else + { + var rsi = spriteComponent.LayerGetActualRSI(spriteLayer); + + // ... for some reason? + if (rsi != null && rsi.TryGetState($"{statePrefix}_{threshold}", out _)) + { + spriteComponent.LayerSetState(spriteLayer, $"{statePrefix}_{threshold}"); + } + } + } + } + + private void UpdateDamageLayerState(SpriteComponent spriteComponent, int spriteLayer, string statePrefix, FixedPoint2 threshold) + { + if (threshold <= 0) + { + spriteComponent.LayerSetVisible(spriteLayer, false); + } + else + { + if (!spriteComponent[spriteLayer].Visible) + { + spriteComponent.LayerSetVisible(spriteLayer, true); + } + spriteComponent.LayerSetState(spriteLayer, $"{statePrefix}_{threshold}"); + } + } +} diff --git a/Content.Client/Backmen/Targeting/TargetingSystem.cs b/Content.Client/Backmen/Targeting/TargetingSystem.cs index f6f82e95960..908db70abf6 100644 --- a/Content.Client/Backmen/Targeting/TargetingSystem.cs +++ b/Content.Client/Backmen/Targeting/TargetingSystem.cs @@ -27,8 +27,10 @@ public override void Initialize() CommandBinds.Builder .Bind(ContentKeyFunctions.TargetHead, InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.Head))) - .Bind(ContentKeyFunctions.TargetTorso, - InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.Torso))) + .Bind(ContentKeyFunctions.TargetChest, + InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.Chest))) + .Bind(ContentKeyFunctions.TargetGroin, + InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.Groin))) .Bind(ContentKeyFunctions.TargetLeftArm, InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.LeftArm))) .Bind(ContentKeyFunctions.TargetLeftHand, diff --git a/Content.Client/Backmen/UserInterface/Systems/PartStatus/Widgets/PartStatusControl.xaml.cs b/Content.Client/Backmen/UserInterface/Systems/PartStatus/Widgets/PartStatusControl.xaml.cs index f405b5ca7bc..5c51f3c6714 100644 --- a/Content.Client/Backmen/UserInterface/Systems/PartStatus/Widgets/PartStatusControl.xaml.cs +++ b/Content.Client/Backmen/UserInterface/Systems/PartStatus/Widgets/PartStatusControl.xaml.cs @@ -1,3 +1,4 @@ +using Content.Shared.Backmen.Surgery.Wounds; using Content.Shared.Backmen.Targeting; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.Controls; @@ -19,7 +20,7 @@ public PartStatusControl() _partStatusControls = new Dictionary { { TargetBodyPart.Head, DollHead }, - { TargetBodyPart.Torso, DollTorso }, + { TargetBodyPart.Chest, DollTorso }, { TargetBodyPart.Groin, DollGroin }, { TargetBodyPart.LeftArm, DollLeftArm }, { TargetBodyPart.LeftHand, DollLeftHand }, @@ -28,11 +29,11 @@ public PartStatusControl() { TargetBodyPart.LeftLeg, DollLeftLeg }, { TargetBodyPart.LeftFoot, DollLeftFoot }, { TargetBodyPart.RightLeg, DollRightLeg }, - { TargetBodyPart.RightFoot, DollRightFoot } + { TargetBodyPart.RightFoot, DollRightFoot }, }; } - public void SetTextures(Dictionary state) + public void SetTextures(Dictionary state) { foreach (var (bodyPart, integrity) in state) { diff --git a/Content.Client/Backmen/UserInterface/Systems/Targeting/Widgets/TargetingControl.xaml.cs b/Content.Client/Backmen/UserInterface/Systems/Targeting/Widgets/TargetingControl.xaml.cs index ad92cd9616d..866ed8d9ea6 100644 --- a/Content.Client/Backmen/UserInterface/Systems/Targeting/Widgets/TargetingControl.xaml.cs +++ b/Content.Client/Backmen/UserInterface/Systems/Targeting/Widgets/TargetingControl.xaml.cs @@ -22,7 +22,7 @@ public TargetingControl() { // TODO: ADD EYE AND MOUTH TARGETING { TargetBodyPart.Head, HeadButton }, - { TargetBodyPart.Torso, ChestButton }, + { TargetBodyPart.Chest, ChestButton }, { TargetBodyPart.Groin, GroinButton }, { TargetBodyPart.LeftArm, LeftArmButton }, { TargetBodyPart.LeftHand, LeftHandButton }, diff --git a/Content.Client/Content.Client.csproj b/Content.Client/Content.Client.csproj index 763e7cf263c..8356aff5538 100644 --- a/Content.Client/Content.Client.csproj +++ b/Content.Client/Content.Client.csproj @@ -46,6 +46,9 @@ BonusWageWindow.xaml + + + diff --git a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml index 0a0b5ac89e7..25f1267ced2 100644 --- a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml +++ b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml @@ -26,7 +26,6 @@ Margin="0 0 0 5"> diff --git a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs index 4ed5c3b5c03..29196d69e1e 100644 --- a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs +++ b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs @@ -4,7 +4,11 @@ using Content.Shared.Atmos; using Content.Client.UserInterface.Controls; using Content.Shared.Alert; +using Content.Shared.Backmen.Surgery.Wounds; +using Content.Shared.Backmen.Surgery.Wounds.Components; +using Content.Shared.Backmen.Surgery.Wounds.Systems; using Content.Shared.Backmen.Targeting; +using Content.Shared.Body.Components; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; @@ -37,6 +41,9 @@ public sealed partial class HealthAnalyzerWindow : FancyWindow private readonly IPrototypeManager _prototypes; private readonly IResourceCache _cache; + private readonly WoundSystem _wound; + private readonly SharedAppearanceSystem _appearance; + // Start-backmen: surgery public event Action? OnBodyPartSelected; private EntityUid _spriteViewEntity; @@ -58,11 +65,13 @@ public HealthAnalyzerWindow() _spriteSystem = _entityManager.System(); _prototypes = dependencies.Resolve(); _cache = dependencies.Resolve(); + _wound = _entityManager.System(); + _appearance = _entityManager.System(); // Start-backmen: surgery _bodyPartControls = new Dictionary { { TargetBodyPart.Head, HeadButton }, - { TargetBodyPart.Torso, ChestButton }, + { TargetBodyPart.Chest, ChestButton }, { TargetBodyPart.Groin, GroinButton }, { TargetBodyPart.LeftArm, LeftArmButton }, { TargetBodyPart.LeftHand, LeftHandButton }, @@ -88,8 +97,7 @@ public void SetActiveBodyPart(TargetBodyPart part, TextureButton button) if (_target == null) return; - // Bit of the ole shitcode until we have Groins in the prototypes. - OnBodyPartSelected?.Invoke(part == TargetBodyPart.Groin ? TargetBodyPart.Torso : part, _target.Value); + OnBodyPartSelected?.Invoke(part, _target.Value); } public void ResetBodyPart() @@ -113,8 +121,7 @@ public void Populate(HealthAnalyzerScannedUserMessage msg) EntityUid? part = msg.Part != null ? _entityManager.GetEntity(msg.Part.Value) : null; var isPart = part != null; - if (_target == null - || !_entityManager.TryGetComponent(isPart ? part : _target, out var damageable)) + if (_target == null) { NoPatientDataText.Visible = true; return; @@ -177,9 +184,86 @@ public void Populate(HealthAnalyzerScannedUserMessage msg) ? GetStatus(mobStateComponent.CurrentState) : Loc.GetString("health-analyzer-window-entity-unknown-text"); - // Total Damage + // Damage stuff + + if (_entityManager.TryGetComponent(_target.Value, out var damageable)) + { + DamageLabel.Text = damageable.TotalDamage.ToString(); + + var damageSortedGroups = + damageable.DamagePerGroup.OrderByDescending(damage => damage.Value) + .ToDictionary(x => x.Key, x => x.Value); + + IReadOnlyDictionary damagePerType = damageable.Damage.DamageDict; + + DrawDiagnosticGroups(damageSortedGroups, damagePerType); + } + + if (!isPart && _entityManager.TryGetComponent(_target.Value, out var body) && body.RootContainer.ContainedEntity.HasValue) + { + var damageGroups = new Dictionary(); + foreach (var child in _wound.GetAllWoundableChildren(body.RootContainer.ContainedEntity.Value)) + { + if (!_appearance.TryGetData(child.Item1, WoundableVisualizerKeys.Wounds, out var wounds)) + continue; + + foreach (var wound in wounds.GroupList.Select(_entityManager.GetEntity).Select(_entityManager.GetComponent)) + { + var woundGroup = wound.DamageGroup; + if (woundGroup == null) + continue; + + if (!damageGroups.TryAdd(woundGroup, wound.WoundSeverityPoint)) + { + damageGroups[woundGroup] += wound.WoundSeverityPoint; + } + } + } + + var damageSortedGroups = + damageGroups.OrderByDescending(damage => damage.Value) + .ToDictionary(x => x.Key, x => x.Value); + + IReadOnlyDictionary damagePerType = damageGroups; + + DrawDiagnosticGroups(damageSortedGroups, damagePerType); + + DamageLabel.Text = damageGroups.Values.Sum().ToString(); + } + + if (_entityManager.TryGetComponent(part, out var woundable)) + { + if (!_appearance.TryGetData(part.Value, WoundableVisualizerKeys.Wounds, out var wounds)) + return; + + var woundComps = wounds.GroupList + .Select(_entityManager.GetEntity) + .Select(_entityManager.GetComponent) + .ToList(); + + DamageLabel.Text = woundComps.Aggregate((FixedPoint2) 0, (current, wound) => current + wound.WoundSeverityPoint).ToString(); + + var damageGroups = new Dictionary(); + foreach (var wound in woundComps) + { + var woundGroup = wound.DamageGroup; + if (woundGroup == null) + continue; + + if (!damageGroups.TryAdd(woundGroup, wound.WoundSeverityPoint)) + { + damageGroups[woundGroup] += wound.WoundSeverityPoint; + } + } + + var damageSortedGroups = + damageGroups.OrderByDescending(damage => damage.Value) + .ToDictionary(x => x.Key, x => x.Value); - DamageLabel.Text = damageable.TotalDamage.ToString(); + IReadOnlyDictionary damagePerType = damageGroups; + + DrawDiagnosticGroups(damageSortedGroups, damagePerType); + } // Alerts @@ -212,17 +296,6 @@ public void Populate(HealthAnalyzerScannedUserMessage msg) bleedingLabel.SetMessage(Loc.GetString("health-analyzer-window-entity-bleeding-text"), defaultColor: Color.Red); AlertsContainer.AddChild(bleedingLabel); } - - // Damage Groups - - var damageSortedGroups = - damageable.DamagePerGroup.OrderByDescending(damage => damage.Value) - .ToDictionary(x => x.Key, x => x.Value); - - IReadOnlyDictionary damagePerType = damageable.Damage.DamageDict; - - DrawDiagnosticGroups(damageSortedGroups, damagePerType); - // End-backmen: surgery } private static string GetStatus(MobState mobState) @@ -328,7 +401,7 @@ private BoxContainer CreateDiagnosticGroupTitle(string text, string id) /// /// Sets up the Body Doll using Alert Entity to use in Health Analyzer. /// - private EntityUid? SetupIcon(Dictionary? body) + private EntityUid? SetupIcon(Dictionary? body) { if (body is null) return null; diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index eafaa4774aa..fe49716eeae 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -90,7 +90,8 @@ public static void SetupContexts(IInputContextContainer contexts) human.AddFunction(ContentKeyFunctions.LookUp); // BACKMEN EDIT human.AddFunction(CMKeyFunctions.CMUniqueAction); // BACKMEN EDIT human.AddFunction(ContentKeyFunctions.TargetHead); - human.AddFunction(ContentKeyFunctions.TargetTorso); + human.AddFunction(ContentKeyFunctions.TargetChest); + human.AddFunction(ContentKeyFunctions.TargetGroin); human.AddFunction(ContentKeyFunctions.TargetLeftArm); human.AddFunction(ContentKeyFunctions.TargetLeftHand); human.AddFunction(ContentKeyFunctions.TargetRightArm); diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs index 5cbcef8f7b2..077480e216c 100644 --- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs +++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs @@ -258,7 +258,8 @@ void HandleToggleAutoGetUp(BaseButton.ButtonToggledEventArgs args) // BACKMEN ED AddHeader("ui-options-header-targeting"); AddButton(ContentKeyFunctions.TargetHead); - AddButton(ContentKeyFunctions.TargetTorso); + AddButton(ContentKeyFunctions.TargetChest); + AddButton(ContentKeyFunctions.TargetGroin); AddButton(ContentKeyFunctions.TargetLeftArm); AddButton(ContentKeyFunctions.TargetLeftHand); AddButton(ContentKeyFunctions.TargetRightArm); diff --git a/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs b/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs index 9d9dd309116..88426d20db2 100644 --- a/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs +++ b/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs @@ -1,9 +1,11 @@ +using Content.Shared.Backmen.Surgery.Consciousness.Components; +using Content.Shared.Backmen.Surgery.Consciousness.Systems; +using Content.Shared.Body.Components; using Content.Shared.Damage; using Content.Shared.FixedPoint; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; -using Content.Shared.Traits.Assorted; using JetBrains.Annotations; using Robust.Client.Graphics; using Robust.Client.Player; @@ -19,6 +21,7 @@ public sealed class DamageOverlayUiController : UIController [Dependency] private readonly IOverlayManager _overlayManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; + [UISystemDependency] private readonly ConsciousnessSystem _consciousness = default!; [UISystemDependency] private readonly MobThresholdSystem _mobThresholdSystem = default!; private Overlays.DamageOverlay _overlay = default!; @@ -28,7 +31,7 @@ public override void Initialize() SubscribeLocalEvent(OnPlayerAttach); SubscribeLocalEvent(OnPlayerDetached); SubscribeLocalEvent(OnMobStateChanged); - SubscribeLocalEvent(OnThresholdCheck); + SubscribeNetworkEvent(OnThresholdCheck); } private void OnPlayerAttach(LocalPlayerAttachedEvent args) @@ -55,12 +58,13 @@ private void OnMobStateChanged(MobStateChangedEvent args) UpdateOverlays(args.Target, args.Component); } - private void OnThresholdCheck(ref MobThresholdChecked args) + private void OnThresholdCheck(MobThresholdChecked args, EntitySessionEventArgs session) { - - if (args.Target != _playerManager.LocalEntity) + if (!EntityManager.TryGetEntity(args.Uid, out var entity) + || !_playerManager.LocalEntity.Equals(entity)) return; - UpdateOverlays(args.Target, args.MobState, args.Damageable, args.Threshold); + + UpdateOverlays(entity.Value); } private void ClearOverlay() @@ -71,69 +75,125 @@ private void ClearOverlay() _overlay.OxygenLevel = 0f; } - //TODO: Jezi: adjust oxygen and hp overlays to use appropriate systems once bodysim is implemented - private void UpdateOverlays(EntityUid entity, MobStateComponent? mobState, DamageableComponent? damageable = null, MobThresholdsComponent? thresholds = null) + // Jezi: adjust oxygen and hp overlays to use appropriate systems once bodysim is implemented + // dw vro + private void UpdateOverlays(EntityUid entity, + MobStateComponent? mobState = null, + BodyComponent? body = null, + DamageableComponent? damageable = null, + MobThresholdsComponent? thresholds = null) { if (mobState == null && !EntityManager.TryGetComponent(entity, out mobState) || thresholds == null && !EntityManager.TryGetComponent(entity, out thresholds) || - damageable == null && !EntityManager.TryGetComponent(entity, out damageable)) + body == null && !EntityManager.TryGetComponent(entity, out body) && damageable == null && !EntityManager.TryGetComponent(entity, out damageable)) return; - if (!_mobThresholdSystem.TryGetIncapThreshold(entity, out var foundThreshold, thresholds)) - return; //this entity cannot die or crit!! - if (!thresholds.ShowOverlays) { ClearOverlay(); return; //this entity intentionally has no overlays } - var critThreshold = foundThreshold.Value; _overlay.State = mobState.CurrentState; - - switch (mobState.CurrentState) + if (body == null && damageable != null) { - case MobState.Alive: + if (!_mobThresholdSystem.TryGetIncapThreshold(entity, out var foundThreshold, thresholds)) + return; //this entity cannot die or crit!! + + var critThreshold = foundThreshold.Value; + switch (mobState.CurrentState) { - if (EntityManager.HasComponent(entity)) + case MobState.Alive: { + if (damageable.DamagePerGroup.TryGetValue("Brute", out var bruteDamage)) + { + _overlay.BruteLevel = FixedPoint2.Min(1f, bruteDamage / critThreshold).Float(); + } + + if (damageable.DamagePerGroup.TryGetValue("Airloss", out var oxyDamage)) + { + _overlay.OxygenLevel = FixedPoint2.Min(1f, oxyDamage / critThreshold).Float(); + } + + if (_overlay.BruteLevel < 0.05f) // Don't show damage overlay if they're near enough to max. + { + _overlay.BruteLevel = 0; + } + + _overlay.CritLevel = 0; + _overlay.DeadLevel = 0; + break; + } + case MobState.Critical: + { + if (!_mobThresholdSystem.TryGetDeadPercentage(entity, + FixedPoint2.Max(0.0, damageable.TotalDamage), out var critLevel)) + return; + _overlay.CritLevel = critLevel.Value.Float(); + _overlay.BruteLevel = 0; + _overlay.DeadLevel = 0; + break; } - else if (damageable.DamagePerGroup.TryGetValue("Brute", out var bruteDamage)) + case MobState.Dead: { - _overlay.BruteLevel = FixedPoint2.Min(1f, bruteDamage / critThreshold).Float(); + _overlay.BruteLevel = 0; + _overlay.CritLevel = 0; + break; } + } + } + else if (body != null) + { + if (!EntityManager.TryGetComponent(entity, out var consciousness)) + return; - if (damageable.DamagePerGroup.TryGetValue("Airloss", out var oxyDamage)) + switch (mobState.CurrentState) + { + case MobState.Alive: { - _overlay.OxygenLevel = FixedPoint2.Min(1f, oxyDamage / critThreshold).Float(); + _overlay.CritLevel = 0; + _overlay.DeadLevel = 0; + + if (consciousness.Consciousness <= 0 || consciousness.Consciousness >= consciousness.Cap) + { + _overlay.BruteLevel = 0; + return; + } + + _overlay.BruteLevel = FixedPoint2.Min(1f, + (consciousness.Cap - consciousness.Consciousness) / (consciousness.Cap - consciousness.Threshold)) + .Float(); + + if (_consciousness.TryGetNerveSystem(_playerManager.LocalEntity!.Value, out var nerveSys) && + _consciousness.TryGetConsciousnessModifier(_playerManager.LocalEntity!.Value, nerveSys.Value, out var modifier, "Suffocation")) + { + _overlay.OxygenLevel = FixedPoint2.Min(1f, modifier.Value.Change / (consciousness.Cap - consciousness.Threshold)).Float(); + } + + if (_overlay.BruteLevel < 0.05f) // Don't show damage overlay if they're near enough to max. + { + _overlay.BruteLevel = 0; + } + + break; } + case MobState.Critical: + { + _overlay.CritLevel = FixedPoint2.Min(1f, + (consciousness.Threshold - consciousness.Consciousness) / consciousness.Threshold) + .Float(); - if (_overlay.BruteLevel < 0.05f) // Don't show damage overlay if they're near enough to max. + _overlay.BruteLevel = 0; + _overlay.DeadLevel = 0; + break; + } + case MobState.Dead: { _overlay.BruteLevel = 0; + _overlay.CritLevel = 0; + break; } - - _overlay.CritLevel = 0; - _overlay.DeadLevel = 0; - break; - } - case MobState.Critical: - { - if (!_mobThresholdSystem.TryGetDeadPercentage(entity, - FixedPoint2.Max(0.0, damageable.TotalDamage), out var critLevel)) - return; - _overlay.CritLevel = critLevel.Value.Float(); - - _overlay.BruteLevel = 0; - _overlay.DeadLevel = 0; - break; - } - case MobState.Dead: - { - _overlay.BruteLevel = 0; - _overlay.CritLevel = 0; - break; } } } diff --git a/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs b/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs index cd358065ae9..f3fae3f57d5 100644 --- a/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs +++ b/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs @@ -1,4 +1,5 @@ using System.Linq; +using Content.Shared.Backmen.Surgery.Consciousness.Components; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.Execution; @@ -131,6 +132,9 @@ public async Task TestSuicideWhileDamaged() var player = playerMan.Sessions.First().AttachedEntity!.Value; var mind = mindSystem.GetMind(player); + if (entManager.HasComponent(player)) + return; // Consciousness entities don't use damage to die + MindComponent mindComponent = default; MobStateComponent mobStateComp = default; MobThresholdsComponent mobThresholdsComp = default; diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs index dfa967e41bd..89a72a82dc4 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs @@ -20,6 +20,7 @@ using Content.Server.Tabletop.Components; using Content.Shared.Administration; using Content.Shared.Administration.Components; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.Body.Components; using Content.Shared.Body.Part; using Content.Shared.Clumsy; diff --git a/Content.Server/Armor/ArmorSystem.cs b/Content.Server/Armor/ArmorSystem.cs index 915210419bb..565b5088a22 100644 --- a/Content.Server/Armor/ArmorSystem.cs +++ b/Content.Server/Armor/ArmorSystem.cs @@ -22,7 +22,7 @@ private void GetArmorPrice(EntityUid uid, ArmorComponent component, ref PriceCal foreach (var modifier in component.Modifiers.Coefficients) { var damageType = _protoManager.Index(modifier.Key); - args.Price += component.PriceMultiplier * damageType.ArmorPriceCoefficient * 100 * (1 - modifier.Value); + args.Price += component.PriceMultiplier * damageType.ArmorPriceCoefficient * 45 * (1 - modifier.Value); } foreach (var modifier in component.Modifiers.FlatReduction) diff --git a/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs b/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs index 2b8518f2174..50d7295fc4b 100644 --- a/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs +++ b/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs @@ -207,18 +207,12 @@ public override void Update(float frameTime) _timer -= UpdateTimer; - var enumerator = EntityQueryEnumerator(); - while (enumerator.MoveNext(out var uid, out var barotrauma, out var damageable)) + var enumerator = EntityQueryEnumerator(); + while (enumerator.MoveNext(out var uid, out var barotrauma)) { - var totalDamage = FixedPoint2.Zero; - foreach (var (barotraumaDamageType, _) in barotrauma.Damage.DamageDict) - { - if (!damageable.Damage.DamageDict.TryGetValue(barotraumaDamageType, out var damage)) - continue; - totalDamage += damage; - } - if (totalDamage >= barotrauma.MaxDamage) - continue; + // TODO: bring it back. might be bad, but well + //if (totalDamage >= barotrauma.MaxDamage) + // continue; var pressure = 1f; @@ -238,7 +232,7 @@ public override void Update(float frameTime) if (pressure <= Atmospherics.HazardLowPressure) { // Deal damage and ignore resistances. Resistance to pressure damage should be done via pressure protection gear. - _damageableSystem.TryChangeDamage(uid, barotrauma.Damage * Atmospherics.LowPressureDamage, true, false, canSever: false, partMultiplier: 0.5f); // backmen + _damageableSystem.TryChangeDamage(uid, barotrauma.Damage * Atmospherics.LowPressureDamage, true, false, partMultiplier: 0.5f); // backmen if (!barotrauma.TakingDamage) { barotrauma.TakingDamage = true; @@ -252,7 +246,7 @@ public override void Update(float frameTime) var damageScale = MathF.Min(((pressure / Atmospherics.HazardHighPressure) - 1) * Atmospherics.PressureDamageCoefficient, Atmospherics.MaxHighPressureDamage); // Deal damage and ignore resistances. Resistance to pressure damage should be done via pressure protection gear. - _damageableSystem.TryChangeDamage(uid, barotrauma.Damage * damageScale, true, false, canSever: false, partMultiplier: 0.5f); // backmen + _damageableSystem.TryChangeDamage(uid, barotrauma.Damage * damageScale, true, false, partMultiplier: 0.5f); // backmen RaiseLocalEvent(uid, new MoodEffectEvent("MobHighPressure")); // backmen: mood if (!barotrauma.TakingDamage) diff --git a/Content.Server/Backmen/Abilities/Felinid/FelinidSystem.cs b/Content.Server/Backmen/Abilities/Felinid/FelinidSystem.cs index 00287aeb72b..71d13eaf26c 100644 --- a/Content.Server/Backmen/Abilities/Felinid/FelinidSystem.cs +++ b/Content.Server/Backmen/Abilities/Felinid/FelinidSystem.cs @@ -15,6 +15,7 @@ using Content.Server.Nutrition.EntitySystems; using Content.Server.Popups; using Content.Shared.Backmen.Psionics.Events; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.Chemistry.EntitySystems; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; diff --git a/Content.Server/Backmen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs b/Content.Server/Backmen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs index 7112fb16f95..6e57d2b2a9b 100644 --- a/Content.Server/Backmen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs +++ b/Content.Server/Backmen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs @@ -11,6 +11,7 @@ using Content.Shared.FixedPoint; using Content.Shared.Popups; using Content.Shared.Backmen.Psionics.Events; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.Examine; using Robust.Server.Audio; using static Content.Shared.Examine.ExamineSystemShared; diff --git a/Content.Server/Backmen/Cocoon/CocoonerSystem.cs b/Content.Server/Backmen/Cocoon/CocoonerSystem.cs index 34daaad7eb3..8d4c079e059 100644 --- a/Content.Server/Backmen/Cocoon/CocoonerSystem.cs +++ b/Content.Server/Backmen/Cocoon/CocoonerSystem.cs @@ -8,6 +8,7 @@ using Content.Shared.Administration.Logs; using Content.Shared.Backmen.Arachne; using Content.Shared.Backmen.Cocoon; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.Backmen.Vampiric.Components; using Content.Shared.Containers.ItemSlots; using Content.Shared.Damage; diff --git a/Content.Server/Backmen/Disease/Cures/DiseaseCureSystem.cs b/Content.Server/Backmen/Disease/Cures/DiseaseCureSystem.cs index b13d7ed5364..84dbc01b9c8 100644 --- a/Content.Server/Backmen/Disease/Cures/DiseaseCureSystem.cs +++ b/Content.Server/Backmen/Disease/Cures/DiseaseCureSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Body.Components; using Content.Server.Temperature.Components; using Content.Shared.Backmen.Disease; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.Bed.Sleep; using Content.Shared.Buckle.Components; using Content.Shared.Mobs.Components; diff --git a/Content.Server/Backmen/Disease/Effects/DiseaseAdjustReagent.cs b/Content.Server/Backmen/Disease/Effects/DiseaseAdjustReagent.cs index 131b93d62b4..e3dac48f867 100644 --- a/Content.Server/Backmen/Disease/Effects/DiseaseAdjustReagent.cs +++ b/Content.Server/Backmen/Disease/Effects/DiseaseAdjustReagent.cs @@ -1,5 +1,6 @@ using Content.Server.Body.Components; using Content.Shared.Backmen.Disease; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; diff --git a/Content.Server/Backmen/Flesh/FleshCultistSystem.cs b/Content.Server/Backmen/Flesh/FleshCultistSystem.cs index e2848c7c936..2a1536a13ab 100644 --- a/Content.Server/Backmen/Flesh/FleshCultistSystem.cs +++ b/Content.Server/Backmen/Flesh/FleshCultistSystem.cs @@ -26,6 +26,7 @@ using Content.Shared.FixedPoint; using Content.Shared.Backmen.Flesh; using Content.Shared.Backmen.Language; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Cloning; using Content.Shared.Fluids.Components; @@ -425,7 +426,7 @@ private void OnDevourDoAfter(EntityUid uid, FleshCultistComponent component, Fle if (part.Component.PartType == BodyPartType.Head) continue; - if (part.Component.PartType == BodyPartType.Torso) + if (part.Component.PartType == BodyPartType.Chest) { foreach (var organ in _body.GetPartOrgans(part.Id, part.Component)) { diff --git a/Content.Server/Backmen/Flesh/FleshHeartSystem.cs b/Content.Server/Backmen/Flesh/FleshHeartSystem.cs index a828402f31e..b2442ccf893 100644 --- a/Content.Server/Backmen/Flesh/FleshHeartSystem.cs +++ b/Content.Server/Backmen/Flesh/FleshHeartSystem.cs @@ -272,7 +272,7 @@ private void OnClimbedOn(EntityUid uid, FleshHeartComponent component, ref Climb if (part.Component.PartType == BodyPartType.Head) continue; - if (part.Component.PartType == BodyPartType.Torso) + if (part.Component.PartType == BodyPartType.Chest) { foreach (var organ in _body.GetPartOrgans(part.Id, part.Component)) { diff --git a/Content.Server/Backmen/Flesh/TransformInFleshPudgeOnDeathSystem.cs b/Content.Server/Backmen/Flesh/TransformInFleshPudgeOnDeathSystem.cs index b338b443313..327b37d4831 100644 --- a/Content.Server/Backmen/Flesh/TransformInFleshPudgeOnDeathSystem.cs +++ b/Content.Server/Backmen/Flesh/TransformInFleshPudgeOnDeathSystem.cs @@ -4,6 +4,7 @@ using Content.Server.Forensics; using Content.Server.Mind; using Content.Server.Popups; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.Body.Part; using Content.Shared.Chemistry.Components; using Content.Shared.Forensics.Components; diff --git a/Content.Server/Backmen/Surgery/SurgerySystem.cs b/Content.Server/Backmen/Surgery/SurgerySystem.cs index 96aa90f718d..56f73452574 100644 --- a/Content.Server/Backmen/Surgery/SurgerySystem.cs +++ b/Content.Server/Backmen/Surgery/SurgerySystem.cs @@ -97,7 +97,6 @@ private void SetDamage(EntityUid body, damage, true, origin: user, - canSever: false, partMultiplier: partMultiplier, targetPart: _body.GetTargetBodyPart(partComp)); } @@ -153,12 +152,19 @@ private void OnSurgeryDamageChange(Entity en private void OnSurgerySpecialDamageChange(Entity ent, ref SurgeryStepDamageChangeEvent args) { - if (ent.Comp.DamageType == "Rot") - _rot.ReduceAccumulator(args.Body, TimeSpan.FromSeconds(2147483648)); // BEHOLD, SHITCODE THAT I JUST COPY PASTED. I'll redo it at some point, pinky swear :) - else if (ent.Comp.DamageType == "Eye" - && TryComp(ent, out BlindableComponent? blindComp) - && blindComp.EyeDamage > 0) - _blindableSystem.AdjustEyeDamage((args.Body, blindComp), -blindComp!.EyeDamage); + // Dude. + // TODO: Make this an enum switch + switch (ent.Comp.DamageType) + { + case "Rot": + _rot.ReduceAccumulator(args.Body, TimeSpan.FromSeconds(2147483648)); // BEHOLD, SHITCODE THAT I JUST COPY PASTED. I'll redo it at some point, pinky swear :) + break; + case "Eye" + when TryComp(ent, out BlindableComponent? blindComp) + && blindComp.EyeDamage > 0: + _blindableSystem.AdjustEyeDamage((args.Body, blindComp), -blindComp.EyeDamage); + break; + } } private void OnStepScreamComplete(Entity ent, ref SurgeryStepEvent args) diff --git a/Content.Server/Backmen/Targeting/TargetingSystem.cs b/Content.Server/Backmen/Targeting/TargetingSystem.cs index 3202de8f008..5890ff4d475 100644 --- a/Content.Server/Backmen/Targeting/TargetingSystem.cs +++ b/Content.Server/Backmen/Targeting/TargetingSystem.cs @@ -1,11 +1,12 @@ +using Content.Shared.Backmen.Surgery.Wounds; +using Content.Shared.Backmen.Surgery.Wounds.Systems; using Content.Shared.Backmen.Targeting; -using Content.Shared.Body.Systems; using Content.Shared.Mobs; namespace Content.Server.Backmen.Targeting; public sealed class TargetingSystem : SharedTargetingSystem { - [Dependency] private readonly SharedBodySystem _bodySystem = default!; + [Dependency] private readonly WoundSystem _woundSystem = default!; public override void Initialize() { @@ -32,22 +33,20 @@ private void OnMobStateChange(EntityUid uid, TargetingComponent component, MobSt { foreach (var part in GetValidParts()) { - component.BodyStatus[part] = TargetIntegrity.Dead; + component.BodyStatus[part] = WoundableSeverity.Loss; changed = true; } - // I love groin shitcode. - component.BodyStatus[TargetBodyPart.Groin] = TargetIntegrity.Dead; } - else if (args.OldMobState == MobState.Dead && (args.NewMobState == MobState.Alive || args.NewMobState == MobState.Critical)) + else if (args is { OldMobState: MobState.Dead, NewMobState: MobState.Alive or MobState.Critical }) { - component.BodyStatus = _bodySystem.GetBodyPartStatus(uid); + component.BodyStatus = _woundSystem.GetWoundableStatesOnBodyPainFeels(uid); changed = true; } - if (changed) - { - Dirty(uid, component); - RaiseNetworkEvent(new TargetIntegrityChangeEvent(GetNetEntity(uid)), uid); - } + if (!changed) + return; + + Dirty(uid, component); + RaiseNetworkEvent(new TargetIntegrityChangeEvent(GetNetEntity(uid)), uid); } } diff --git a/Content.Server/Backmen/Vampiric/BkmVampireLevelingSystem.cs b/Content.Server/Backmen/Vampiric/BkmVampireLevelingSystem.cs index f44c18a90c3..c6f250626f5 100644 --- a/Content.Server/Backmen/Vampiric/BkmVampireLevelingSystem.cs +++ b/Content.Server/Backmen/Vampiric/BkmVampireLevelingSystem.cs @@ -9,6 +9,7 @@ using Content.Shared.Actions; using Content.Shared.Administration.Logs; using Content.Shared.Backmen.Abilities.Psionics; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.Backmen.Vampiric; using Content.Shared.Backmen.Vampiric.Components; using Content.Shared.Damage; diff --git a/Content.Server/Backmen/Vampiric/BloodSuckerSystem.cs b/Content.Server/Backmen/Vampiric/BloodSuckerSystem.cs index 6370f726be9..b5ad61cd505 100644 --- a/Content.Server/Backmen/Vampiric/BloodSuckerSystem.cs +++ b/Content.Server/Backmen/Vampiric/BloodSuckerSystem.cs @@ -20,6 +20,7 @@ using Content.Server.NPC.Components; using Content.Server.NPC.Systems; using Content.Server.Nutrition.Components; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.Backmen.Vampiric.Components; using Content.Shared.Body.Components; using Content.Shared.Body.Part; diff --git a/Content.Server/Body/Components/MetabolizerComponent.cs b/Content.Server/Body/Components/MetabolizerComponent.cs index 90c99df7db2..3b868415058 100644 --- a/Content.Server/Body/Components/MetabolizerComponent.cs +++ b/Content.Server/Body/Components/MetabolizerComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Body.Systems; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.Body.Prototypes; using Content.Shared.FixedPoint; using Robust.Shared.Prototypes; diff --git a/Content.Server/Body/Components/StomachComponent.cs b/Content.Server/Body/Components/StomachComponent.cs index 06f03482e7e..471cfd7ead6 100644 --- a/Content.Server/Body/Components/StomachComponent.cs +++ b/Content.Server/Body/Components/StomachComponent.cs @@ -1,5 +1,6 @@ using Content.Server.Body.Systems; using Content.Server.Nutrition.EntitySystems; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.Whitelist; diff --git a/Content.Server/Body/Systems/BloodstreamSystem.cs b/Content.Server/Body/Systems/BloodstreamSystem.cs index d04a9932267..2e1f6f7dd38 100644 --- a/Content.Server/Body/Systems/BloodstreamSystem.cs +++ b/Content.Server/Body/Systems/BloodstreamSystem.cs @@ -4,12 +4,19 @@ using Content.Server.Forensics; using Content.Server.Popups; using Content.Shared.Alert; +using Content.Shared.Backmen.Surgery.Consciousness; +using Content.Shared.Backmen.Surgery.Consciousness.Systems; +using Content.Shared.Backmen.Surgery.Pain.Systems; +using Content.Shared.Backmen.Surgery.Traumas.Components; +using Content.Shared.Backmen.Surgery.Wounds; +using Content.Shared.Backmen.Surgery.Wounds.Components; +using Content.Shared.Backmen.Surgery.Wounds.Systems; +using Content.Shared.Body.Part; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Reagent; using Content.Shared.Damage; -using Content.Shared.Damage.Prototypes; using Content.Shared.Drunk; using Content.Shared.FixedPoint; using Content.Shared.Forensics; @@ -23,6 +30,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; +using BleedInflicterComponent = Content.Shared.Backmen.Surgery.Traumas.Components.BleedInflicterComponent; namespace Content.Server.Body.Systems; @@ -41,6 +49,14 @@ public sealed class BloodstreamSystem : EntitySystem [Dependency] private readonly SharedStutteringSystem _stutteringSystem = default!; [Dependency] private readonly AlertsSystem _alertsSystem = default!; [Dependency] private readonly ForensicsSystem _forensicsSystem = default!; + [Dependency] private readonly ConsciousnessSystem _consciousness = default!; + [Dependency] private readonly BodySystem _body = default!; + [Dependency] private readonly PainSystem _pain = default!; + [Dependency] private readonly WoundSystem _wound = default!; + + // balanced, trust me + private const float BleedsSeverityTrade = 0.15f; + private const float BleedsScalingTimeDefault = 7f; public override void Initialize() { @@ -57,6 +73,9 @@ public override void Initialize() SubscribeLocalEvent>(OnReactionAttempt); SubscribeLocalEvent(OnRejuvenate); SubscribeLocalEvent(OnDnaGenerated); + + SubscribeLocalEvent(OnWoundSeverityUpdate); + SubscribeLocalEvent(OnWoundAdded); } private void OnMapInit(Entity ent, ref MapInitEvent args) @@ -144,8 +163,7 @@ public override void Update(float frameTime) // bloodloss damage is based on the base value, and modified by how low your blood level is. var amt = bloodstream.BloodlossDamage / (0.1f + bloodPercentage); - _damageableSystem.TryChangeDamage(uid, amt, - ignoreResistances: false, interruptsDoAfters: false); + _damageableSystem.TryChangeDamage(uid, amt, ignoreResistances: false, interruptsDoAfters: false); // Apply dizziness as a symptom of bloodloss. // The effect is applied in a way that it will never be cleared without being healthy. @@ -156,7 +174,7 @@ public override void Update(float frameTime) applySlur: false); _stutteringSystem.DoStutter(uid, bloodstream.UpdateInterval * 2, refresh: false); - // storing the drunk and stutter time so we can remove it independently from other effects additions + // storing the drunk and stutter time so we can remove it independently of other effects additions bloodstream.StatusTime += bloodstream.UpdateInterval * 2; } else if (!_mobStateSystem.IsDead(uid)) @@ -165,7 +183,8 @@ public override void Update(float frameTime) _damageableSystem.TryChangeDamage( uid, bloodstream.BloodlossHealDamage * bloodPercentage, - ignoreResistances: true, interruptsDoAfters: false); + ignoreResistances: true, + interruptsDoAfters: false); // Remove the drunk effect when healthy. Should only remove the amount of drunk and stutter added by low blood level _drunkSystem.TryRemoveDrunkenessTime(uid, bloodstream.StatusTime.TotalSeconds); @@ -173,6 +192,60 @@ public override void Update(float frameTime) // Reset the drunk and stutter time to zero bloodstream.StatusTime = TimeSpan.Zero; } + + if (!_consciousness.TryGetNerveSystem(uid, out var nerveSys)) + continue; + + var total = (FixedPoint2) 0; + foreach (var (bodyPart, _) in _body.GetBodyChildren(uid)) + { + foreach (var (wound, _) in _wound.GetWoundableWounds(bodyPart)) + { + if (!TryComp(wound, out var bleeds)) + continue; + + total += bleeds.BleedingAmount; + } + } + + if (!_consciousness.SetConsciousnessModifier(uid, nerveSys.Value, -total, identifier: "Bleeding", type: ConsciousnessModType.Pain)) + { + _consciousness.AddConsciousnessModifier(uid, nerveSys.Value, -total, identifier: "Bleeding", type: ConsciousnessModType.Pain); + } + } + + var bleedsQuery = EntityQueryEnumerator(); + while (bleedsQuery.MoveNext(out var ent, out var bleeds, out var wound)) + { + if (bleeds is { IsBleeding: false, BleedingScales: false }) + { + if (!TryComp(wound.HoldingWoundable, out var holder) || !holder.Body.HasValue) + continue; + + wound.CanBeHealed = true; + } + + var totalTime = bleeds.ScalingFinishesAt - bleeds.ScalingStartsAt; + var currentTime = bleeds.ScalingFinishesAt - _gameTiming.CurTime; + + if (totalTime <= currentTime || bleeds.ScalingLimit == bleeds.Scaling) + continue; + + var newBleeds = FixedPoint2.Clamp( + (totalTime / currentTime) / (bleeds.ScalingLimit - bleeds.Scaling), + 0, + bleeds.ScalingLimit); + + if (TryComp(wound.HoldingWoundable, out var bodyPart) && bodyPart.Body.HasValue) + { + TryModifyBleedAmount(bodyPart.Body.Value, (float) bleeds.BleedingAmount / 1.6f); + } + bleeds.Scaling = newBleeds; + + if (bleeds.Scaling >= bleeds.ScalingLimit || _gameTiming.CurTime > bleeds.ScalingFinishesAt) + bleeds.BleedingScales = false; + + Dirty(ent, bleeds); } } @@ -215,7 +288,7 @@ private void OnDamageChanged(Entity ent, ref DamageChanged } // TODO probably cache this or something. humans get hurt a lot - if (!_prototypeManager.TryIndex(ent.Comp.DamageBleedModifiers, out var modifiers)) + if (!_prototypeManager.TryIndex(ent.Comp.DamageBleedModifiers, out var modifiers)) return; var bloodloss = DamageSpecifier.ApplyModifierSet(args.DamageDelta, modifiers); @@ -229,11 +302,9 @@ private void OnDamageChanged(Entity ent, ref DamageChanged var totalFloat = total.Float(); TryModifyBleedAmount(ent, totalFloat, ent); - /// - /// Critical hit. Causes target to lose blood, using the bleed rate modifier of the weapon, currently divided by 5 - /// The crit chance is currently the bleed rate modifier divided by 25. - /// Higher damage weapons have a higher chance to crit! - /// + // Critical hit. Causes target to lose blood, using the bleed rate modifier of the weapon, currently divided by 5 + // The crit chance is currently the bleed rate modifier divided by 25. + // Higher damage weapons have a higher chance to crit! var prob = Math.Clamp(totalFloat / 25, 0, 1); if (totalFloat > 0 && _robustRandom.Prob(prob)) { @@ -249,8 +320,7 @@ private void OnDamageChanged(Entity ent, ref DamageChanged // We'll play a special sound and popup for feedback. _audio.PlayPvs(ent.Comp.BloodHealedSound, ent); - _popupSystem.PopupEntity(Loc.GetString("bloodstream-component-wounds-cauterized"), ent, - ent, PopupType.Medium); + _popupSystem.PopupEntity(Loc.GetString("bloodstream-component-wounds-cauterized"), ent, ent, PopupType.Medium); } } /// @@ -505,7 +575,8 @@ public List GetEntityBloodData(EntityUid uid) if (TryComp(uid, out var donorComp)) { dnaData.DNA = donorComp.DNA; - } else + } + else { dnaData.DNA = Loc.GetString("forensics-dna-unknown"); } @@ -514,4 +585,44 @@ public List GetEntityBloodData(EntityUid uid) return bloodData; } + + private void OnWoundAdded(EntityUid uid, BleedInflicterComponent component, ref WoundAddedEvent args) + { + if (!args.Component.CanBleed) + return; + + // wounds that BLEED will not HEAL. + component.BleedingAmountRaw = args.Component.WoundSeverityPoint * BleedsSeverityTrade; + + var formula = (float) (args.Component.WoundSeverityPoint / BleedsScalingTimeDefault * args.Component.BleedingScalingMultiplier); + component.ScalingFinishesAt = _gameTiming.CurTime + TimeSpan.FromSeconds(formula); + component.ScalingStartsAt = _gameTiming.CurTime; + + args.Component.CanBeHealed = false; + component.IsBleeding = true; + } + + private void OnWoundSeverityUpdate(EntityUid uid, BleedInflicterComponent component, ref WoundSeverityPointChangedEvent args) + { + if (!args.Component.CanBleed) + return; + + var oldBleedsAmount = args.OldSeverity * BleedsSeverityTrade; + component.BleedingAmountRaw = args.NewSeverity * BleedsSeverityTrade; + component.BleedingScales = true; + + var severityPenalty = component.BleedingAmountRaw - oldBleedsAmount / BleedsScalingTimeDefault; + component.SeverityPenalty += severityPenalty; + + var formula = (float) (args.Component.WoundSeverityPoint / BleedsScalingTimeDefault * args.Component.BleedingScalingMultiplier); + component.ScalingFinishesAt = _gameTiming.CurTime + TimeSpan.FromSeconds(formula); + component.ScalingStartsAt = _gameTiming.CurTime; + + if (!component.IsBleeding && args.NewSeverity > args.OldSeverity) + { + component.ScalingLimit += 0.6; + component.IsBleeding = true; + // When bleeding is reopened, the severity is increased + } + } } diff --git a/Content.Server/Body/Systems/BodySystem.cs b/Content.Server/Body/Systems/BodySystem.cs index 8757f3a7cfa..fd54a2b5f54 100644 --- a/Content.Server/Body/Systems/BodySystem.cs +++ b/Content.Server/Body/Systems/BodySystem.cs @@ -39,7 +39,7 @@ public override void Initialize() // start-backmen: surgery private void OnGibTorsoAttempt(Entity ent, ref AttemptEntityGibEvent args) { - if (ent.Comp.PartType == BodyPartType.Torso) + if (ent.Comp.PartType == BodyPartType.Chest) { args.GibType = GibType.Skip; } @@ -123,7 +123,9 @@ public override HashSet GibBody( Angle splatCone = default, SoundSpecifier? gibSoundOverride = null, GibType gib = GibType.Gib, - GibContentsOption contents = GibContentsOption.Drop) + GibContentsOption contents = GibContentsOption.Drop, + List? allowedContainers = null, + List? excludedContainers = null) { if (!Resolve(bodyId, ref body, logMissing: false) || TerminatingOrDeleted(bodyId) @@ -136,9 +138,9 @@ public override HashSet GibBody( if (xform.MapUid is null) return new HashSet(); - var gibs = base.GibBody(bodyId, gibOrgans, body, launchGibs: launchGibs, - splatDirection: splatDirection, splatModifier: splatModifier, splatCone: splatCone, - gib: gib, contents: contents); + var gibs = base.GibBody(bodyId, gibOrgans, body, launchGibs: launchGibs, splatDirection: splatDirection, + splatModifier: splatModifier, splatCone: splatCone, gib: gib, contents: contents, + allowedContainers: allowedContainers, excludedContainers: excludedContainers); var ev = new BeingGibbedEvent(gibs); RaiseLocalEvent(bodyId, ref ev); diff --git a/Content.Server/Body/Systems/RespiratorSystem.cs b/Content.Server/Body/Systems/RespiratorSystem.cs index d4146c15fb9..493fe6faf70 100644 --- a/Content.Server/Body/Systems/RespiratorSystem.cs +++ b/Content.Server/Body/Systems/RespiratorSystem.cs @@ -18,6 +18,8 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Backmen.Mood; using Content.Shared.Backmen.Surgery.Body; +using Content.Shared.Backmen.Surgery.Consciousness; +using Content.Shared.Backmen.Surgery.Consciousness.Systems; using JetBrains.Annotations; using Robust.Shared.Prototypes; using Robust.Shared.Timing; @@ -39,6 +41,7 @@ public sealed class RespiratorSystem : EntitySystem [Dependency] private readonly IPrototypeManager _protoMan = default!; [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly ChatSystem _chat = default!; + [Dependency] private readonly ConsciousnessSystem _consciousness = default!; private static readonly ProtoId GasId = new("Gas"); @@ -310,6 +313,30 @@ private void TakeSuffocationDamage(Entity ent) RaiseLocalEvent(ent, new MoodEffectEvent("Suffocating")); // backmen: mood } + if (_consciousness.TryGetNerveSystem(ent, out var nerveSys)) + { + if (!_consciousness.TryGetConsciousnessModifier(ent, nerveSys.Value, out var modifier, "Suffocation")) + { + _consciousness.AddConsciousnessModifier( + ent, + nerveSys.Value, + -ent.Comp.Damage.GetTotal(), + identifier: "Suffocation", + type: ConsciousnessModType.Pain); + } + else + { + _consciousness.SetConsciousnessModifier( + ent, + nerveSys.Value, + modifier.Value.Change - ent.Comp.Damage.GetTotal(), + identifier: "Suffocation", + type: ConsciousnessModType.Pain); + } + + return; + } + _damageableSys.TryChangeDamage(ent, HasComp(ent) ? ent.Comp.Damage * 4.5f : ent.Comp.Damage, interruptsDoAfters: false); } @@ -325,10 +352,33 @@ private void StopSuffocation(Entity ent) _alertsSystem.ClearAlert(ent, entity.Comp1.Alert); } + if (_consciousness.TryGetNerveSystem(ent, out var nerveSys)) + { + if (!_consciousness.TryGetConsciousnessModifier(ent, nerveSys.Value, out var modifier, "Suffocation")) + return; + + if (modifier.Value.Change < ent.Comp.DamageRecovery.GetTotal()) + { + _consciousness.RemoveConsciousnessModifier(ent, nerveSys.Value, "Suffocation"); + } + else + { + _consciousness.SetConsciousnessModifier( + ent, + nerveSys.Value, + modifier.Value.Change + ent.Comp.DamageRecovery.GetTotal(), + identifier: "Suffocation", + type: ConsciousnessModType.Pain); + } + + return; + } + _damageableSys.TryChangeDamage(ent, ent.Comp.DamageRecovery); } - public void UpdateSaturation(EntityUid uid, float amount, + public void UpdateSaturation(EntityUid uid, + float amount, RespiratorComponent? respirator = null) { if (!Resolve(uid, ref respirator, false)) diff --git a/Content.Server/Chat/SuicideSystem.cs b/Content.Server/Chat/SuicideSystem.cs index 4eda5323854..58cf9ca1465 100644 --- a/Content.Server/Chat/SuicideSystem.cs +++ b/Content.Server/Chat/SuicideSystem.cs @@ -1,5 +1,6 @@ using Content.Server.Ghost; using Content.Shared.Administration.Logs; +using Content.Shared.Backmen.Surgery.Consciousness.Components; using Content.Shared.Chat; using Content.Shared.Damage; using Content.Shared.Database; @@ -31,6 +32,7 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnDamageableSuicide); + SubscribeLocalEvent(OnConsciousnessSuicide); SubscribeLocalEvent(OnEnvironmentalSuicide); SubscribeLocalEvent(OnSuicideGhost); } @@ -166,4 +168,19 @@ private void OnDamageableSuicide(Entity victim, ref Suicide _suicide.ApplyLethalDamage(victim, args.DamageType); args.Handled = true; } + + private void OnConsciousnessSuicide(Entity theOneToLeave, ref SuicideEvent args) + { + if (args.Handled) + return; + + var othersMessage = Loc.GetString("suicide-command-default-text-others", ("name", theOneToLeave)); + _popup.PopupEntity(othersMessage, theOneToLeave, Filter.PvsExcept(theOneToLeave), true); + + var selfMessage = Loc.GetString("suicide-command-default-text-self"); + _popup.PopupEntity(selfMessage, theOneToLeave, theOneToLeave); + + _suicide.KillConsciousness(theOneToLeave); + args.Handled = true; + } } diff --git a/Content.Server/Chemistry/EntitySystems/HypospraySystem.cs b/Content.Server/Chemistry/EntitySystems/HypospraySystem.cs index d537c2ffdd7..7f4efc23c8e 100644 --- a/Content.Server/Chemistry/EntitySystems/HypospraySystem.cs +++ b/Content.Server/Chemistry/EntitySystems/HypospraySystem.cs @@ -14,6 +14,7 @@ using Content.Shared.Weapons.Melee.Events; using Content.Server.Body.Components; using System.Linq; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Robust.Server.Audio; namespace Content.Server.Chemistry.EntitySystems; diff --git a/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs b/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs index eb2039604af..57789d32d44 100644 --- a/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs @@ -1,5 +1,6 @@ using Content.Server.Body.Components; using Content.Server.Body.Systems; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; diff --git a/Content.Server/Chemistry/EntitySystems/SolutionInjectOnEventSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionInjectOnEventSystem.cs index f79609cac89..d24e6bfe0bd 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionInjectOnEventSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionInjectOnEventSystem.cs @@ -1,6 +1,7 @@ using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.Chemistry.Components; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.Chemistry.Components; // GoobStation using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Events; diff --git a/Content.Server/EntityEffects/Effects/AdjustPainFeels.cs b/Content.Server/EntityEffects/Effects/AdjustPainFeels.cs new file mode 100644 index 00000000000..a9f3eb197a6 --- /dev/null +++ b/Content.Server/EntityEffects/Effects/AdjustPainFeels.cs @@ -0,0 +1,63 @@ +using System.Text.Json.Serialization; +using Content.Server.Body.Systems; +using Content.Shared.Backmen.Surgery.Consciousness.Systems; +using Content.Shared.Backmen.Surgery.Pain.Systems; +using Content.Shared.EntityEffects; +using Content.Shared.FixedPoint; +using JetBrains.Annotations; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server.EntityEffects.Effects; + +[UsedImplicitly] +public sealed partial class AdjustPainFeels : EntityEffect +{ + [DataField(required: true)] + [JsonPropertyName("amount")] + public FixedPoint2 Amount = default!; + + [DataField] + [JsonPropertyName("identifier")] + public string ModifierIdentifier = "PainSuppressant"; + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-suppress-pain", ("chance", Probability)); + + public override void Effect(EntityEffectBaseArgs args) + { + var scale = FixedPoint2.New(1); + + if (args is EntityEffectReagentArgs reagentArgs) + { + scale = reagentArgs.Quantity * reagentArgs.Scale; + } + + if (!args.EntityManager.System().TryGetNerveSystem(args.TargetEntity, out var nerveSys)) + return; + + foreach (var bodyPart in args.EntityManager.System().GetBodyChildren(args.TargetEntity)) + { + if (!args.EntityManager.System() + .TryGetPainFeelsModifier(bodyPart.Id, nerveSys.Value, ModifierIdentifier, out var modifier)) + { + args.EntityManager.System() + .TryAddPainFeelsModifier( + nerveSys.Value, + ModifierIdentifier, + bodyPart.Id, + IoCManager.Resolve().Prob(0.3f) ? Amount * scale : -Amount * scale); + } + else + { + var add = IoCManager.Resolve().Prob(0.3f) ? Amount : -Amount; + args.EntityManager.System() + .TryChangePainFeelsModifier( + nerveSys.Value, + ModifierIdentifier, + bodyPart.Id, + modifier.Value.Change + add * scale); + } + } + } +} diff --git a/Content.Server/EntityEffects/Effects/HealthChange.cs b/Content.Server/EntityEffects/Effects/HealthChange.cs index 2150e95b639..e22f6450210 100644 --- a/Content.Server/EntityEffects/Effects/HealthChange.cs +++ b/Content.Server/EntityEffects/Effects/HealthChange.cs @@ -168,8 +168,7 @@ public override void Effect(EntityEffectBaseArgs args) interruptsDoAfters: false, // start-backmen: surgery targetPart: TargetBodyPart.All, - partMultiplier: 0.5f, - canSever: false); + partMultiplier: 0.5f); // end-backmen: surgery } } diff --git a/Content.Server/EntityEffects/Effects/ModifyBleedAmount.cs b/Content.Server/EntityEffects/Effects/ModifyBleedAmount.cs index 58bc304f5ea..ec34930638a 100644 --- a/Content.Server/EntityEffects/Effects/ModifyBleedAmount.cs +++ b/Content.Server/EntityEffects/Effects/ModifyBleedAmount.cs @@ -1,5 +1,6 @@ using Content.Server.Body.Components; using Content.Server.Body.Systems; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.EntityEffects; using Robust.Shared.Prototypes; diff --git a/Content.Server/EntityEffects/Effects/ModifyBloodLevel.cs b/Content.Server/EntityEffects/Effects/ModifyBloodLevel.cs index d8aca7d2842..ebad4bf2a52 100644 --- a/Content.Server/EntityEffects/Effects/ModifyBloodLevel.cs +++ b/Content.Server/EntityEffects/Effects/ModifyBloodLevel.cs @@ -1,5 +1,6 @@ using Content.Server.Body.Components; using Content.Server.Body.Systems; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.EntityEffects; using Content.Shared.FixedPoint; using Robust.Shared.Prototypes; diff --git a/Content.Server/EntityEffects/Effects/SuppressPain.cs b/Content.Server/EntityEffects/Effects/SuppressPain.cs new file mode 100644 index 00000000000..2b80e523e23 --- /dev/null +++ b/Content.Server/EntityEffects/Effects/SuppressPain.cs @@ -0,0 +1,54 @@ +using System.Text.Json.Serialization; +using Content.Server.Database; +using Content.Shared.Backmen.Surgery.Consciousness.Systems; +using Content.Shared.Backmen.Surgery.Pain.Systems; +using Content.Shared.EntityEffects; +using Content.Shared.FixedPoint; +using JetBrains.Annotations; +using Robust.Shared.Prototypes; + +namespace Content.Server.EntityEffects.Effects; + +[UsedImplicitly] +public sealed partial class SuppressPain : EntityEffect +{ + [DataField(required: true)] + [JsonPropertyName("amount")] + public FixedPoint2 Amount = default!; + + [DataField(required: true)] + [JsonPropertyName("time")] + public TimeSpan Time = default!; + + [DataField] + [JsonPropertyName("identifier")] + public string ModifierIdentifier = "PainSuppressant"; + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-suppress-pain", ("chance", Probability)); + + public override void Effect(EntityEffectBaseArgs args) + { + var scale = FixedPoint2.New(1); + + if (args is EntityEffectReagentArgs reagentArgs) + { + scale = reagentArgs.Quantity * reagentArgs.Scale; + } + + if (!args.EntityManager.System().TryGetNerveSystem(args.TargetEntity, out var nerveSys)) + return; + + if (!args.EntityManager.System() + .TryGetPainModifier(nerveSys.Value, nerveSys.Value, ModifierIdentifier, out var modifier)) + { + args.EntityManager.System() + .TryAddPainModifier(nerveSys.Value, nerveSys.Value, ModifierIdentifier, Amount * scale, time: Time); + } + else + { + args.EntityManager.System() + .TryChangePainModifier(nerveSys.Value, nerveSys.Value, ModifierIdentifier, modifier.Value.Change + Amount * scale, time: Time); + } + } +} diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs index 73d2f8ad5fa..37f4fd523d5 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs @@ -2,6 +2,8 @@ using System.Numerics; using Content.Server.Atmos.EntitySystems; using Content.Server.Explosion.Components; +using Content.Shared.Backmen.Surgery.Consciousness.Components; +using Content.Shared.Body.Components; using Content.Shared.CCVar; using Content.Shared.Damage; using Content.Shared.Database; @@ -471,8 +473,19 @@ private void ProcessEntity( } // TODO EXPLOSIONS turn explosions into entities, and pass the the entity in as the damage origin. - _damageableSystem.TryChangeDamage(entity, damage * _damageableSystem.UniversalExplosionDamageModifier, ignoreResistances: true); - + if (TryComp(entity, out var body) && HasComp(entity)) + { + var bodyParts = _body.GetBodyChildren(entity, body).ToList(); + foreach (var bodyPart in bodyParts) + { + // Distribute the last damage on the other parts... for the cinematic effect :3 + _damageableSystem.TryChangeDamage(bodyPart.Id, damage / bodyParts.Count, ignoreResistances: true); + } + } + else + { + _damageableSystem.TryChangeDamage(entity, damage, ignoreResistances: true); + } } } diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs index c5d6ea7731c..15020fb2723 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs @@ -5,6 +5,8 @@ using Content.Server.Chat.Managers; using Content.Server.NodeContainer.EntitySystems; using Content.Server.NPC.Pathfinding; +using Content.Shared.Armor; +using Content.Shared.Body.Systems; using Content.Shared.Camera; using Content.Shared.CCVar; using Content.Shared.Damage; @@ -52,6 +54,7 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly SharedMapSystem _map = default!; + [Dependency] private readonly SharedBodySystem _body = default!; private EntityQuery _flammableQuery; private EntityQuery _physicsQuery; diff --git a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs index 1c59909b265..e8af939a556 100644 --- a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs +++ b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs @@ -21,7 +21,7 @@ using Robust.Shared.Random; using Robust.Shared.Timing; using System.Linq; - +using Content.Shared.Backmen.Surgery.Traumas.Components; using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent; namespace Content.Server.Fluids.EntitySystems; diff --git a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs index 868e6d99f25..b47cc80c5c2 100644 --- a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs +++ b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs @@ -6,6 +6,7 @@ using Content.Server.Power.Components; using Content.Shared.Administration.Logs; using Content.Shared.Audio; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.CCVar; using Content.Shared.Chemistry.Components; using Content.Shared.Climbing.Events; diff --git a/Content.Server/Medical/CryoPodSystem.cs b/Content.Server/Medical/CryoPodSystem.cs index 50fd66d6745..43ae385289e 100644 --- a/Content.Server/Medical/CryoPodSystem.cs +++ b/Content.Server/Medical/CryoPodSystem.cs @@ -11,6 +11,7 @@ using Content.Server.Temperature.Components; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Atmos; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.UserInterface; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; diff --git a/Content.Server/Medical/DefibrillatorSystem.cs b/Content.Server/Medical/DefibrillatorSystem.cs index a508eb06af6..06224392840 100644 --- a/Content.Server/Medical/DefibrillatorSystem.cs +++ b/Content.Server/Medical/DefibrillatorSystem.cs @@ -204,7 +204,7 @@ public void Zap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorCo else { if (_mobState.IsDead(target, mob)) - _damageable.TryChangeDamage(target, component.ZapHeal, true, origin: uid, targetPart: TargetBodyPart.Torso); // backmen: surgery + _damageable.TryChangeDamage(target, component.ZapHeal, true, origin: uid, targetPart: TargetBodyPart.Chest); // backmen: surgery if (_mobThreshold.TryGetThresholdForState(target, MobState.Dead, out var threshold) && TryComp(target, out var damageableComponent) && diff --git a/Content.Server/Medical/HealingSystem.cs b/Content.Server/Medical/HealingSystem.cs index d3517e9f713..45272fd6d72 100644 --- a/Content.Server/Medical/HealingSystem.cs +++ b/Content.Server/Medical/HealingSystem.cs @@ -1,8 +1,5 @@ using Content.Server.Administration.Logs; -using Content.Server.Body.Components; using Content.Server.Body.Systems; -using Content.Shared.Body.Part; -using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Medical.Components; using Content.Server.Popups; using Content.Server.Stack; @@ -26,6 +23,9 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Random; using System.Linq; +using Content.Shared.Backmen.Surgery.Consciousness.Components; +using Content.Shared.Backmen.Surgery.Traumas.Components; +using Content.Shared.Backmen.Surgery.Wounds.Systems; using Content.Shared.Backmen.Targeting; namespace Content.Server.Medical; @@ -44,6 +44,7 @@ public sealed class HealingSystem : EntitySystem [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly SharedBodySystem _bodySystem = default!; [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!; + [Dependency] private readonly WoundSystem _wounds = default!; public override void Initialize() { @@ -51,13 +52,15 @@ public override void Initialize() SubscribeLocalEvent(OnHealingUse); SubscribeLocalEvent(OnHealingAfterInteract); SubscribeLocalEvent(OnDoAfter); + SubscribeLocalEvent(OnBodyDoAfter); } private void OnDoAfter(Entity entity, ref HealingDoAfterEvent args) { var dontRepeat = false; - if (!TryComp(args.Used, out HealingComponent? healing)) + // Consciousness check because some body entities don't have Consciousness + if (!TryComp(args.Used, out HealingComponent? healing) || HasComp(entity) && HasComp(entity)) return; if (args.Handled || args.Cancelled) @@ -90,7 +93,7 @@ entity.Comp.DamageContainerID is not null && if (healing.ModifyBloodLevel != 0) _bloodstreamSystem.TryModifyBloodLevel(entity.Owner, healing.ModifyBloodLevel); - var healed = _damageable.TryChangeDamage(entity.Owner, healing.Damage * _damageable.UniversalTopicalsHealModifier, true, canSever: false, origin: args.Args.User); + var healed = _damageable.TryChangeDamage(entity.Owner, healing.Damage * _damageable.UniversalTopicalsHealModifier, true, origin: args.Args.User); if (healed == null && healing.BloodlossModifier != 0) return; @@ -125,12 +128,152 @@ entity.Comp.DamageContainerID is not null && _audio.PlayPvs(healing.HealingEndSound, entity.Owner, AudioHelpers.WithVariation(0.125f, _random).WithVolume(1f)); // Logic to determine whether or not to repeat the healing action - args.Repeat = HasDamage(entity, healing) && !dontRepeat || IsPartDamaged(args.User, entity); + args.Repeat = HasDamage(entity, healing) && !dontRepeat; if (!args.Repeat && !dontRepeat) _popupSystem.PopupEntity(Loc.GetString("medical-item-finished-using", ("item", args.Used)), entity.Owner, args.User); args.Handled = true; } + private void OnBodyDoAfter(EntityUid ent, BodyComponent comp, ref HealingDoAfterEvent args) + { + var dontRepeat = false; + + if (!TryComp(args.Used, out HealingComponent? healing)) + return; + + if (args.Handled || args.Cancelled) + return; + + /*if (healing.DamageContainers is not null && + entity.Comp.DamageContainerID is not null && + !healing.DamageContainers.Contains(entity.Comp.DamageContainerID)) + { + return; + }*/ // TODO: Lowkey.. We wanna introduce something similar for woundables, if we wanna make borgs and other shi + + var stuffToHeal = new Dictionary(); + var targetedWoundable = EntityUid.Invalid; + if (TryComp(args.User, out var targeting)) + { + var (partType, symmetry) = _bodySystem.ConvertTargetBodyPart(targeting.Target); + var targetedBodyPart = _bodySystem.GetBodyChildrenOfType(ent, partType, comp, symmetry).ToList().FirstOrDefault(); + + foreach (var damage in + healing.Damage.DamageDict.Where(damage => + _wounds.HasDamageOfGroup(targetedBodyPart.Id, damage.Key) + || _wounds.HasDamageOfType(targetedBodyPart.Id, damage.Key))) + { + stuffToHeal.Add(damage.Key, damage.Value); + } + + if (stuffToHeal.Count > 0) + targetedWoundable = targetedBodyPart.Id; + } + + if (targetedWoundable == EntityUid.Invalid) + { + _popupSystem.PopupEntity(Loc.GetString("does-not-exist-rebell"), ent, args.User, PopupType.MediumCaution); + return; + } + + // Heal some bleeds + if (healing.BloodlossModifier != 0) + { + var bleedStopAbility = -(FixedPoint2) healing.BloodlossModifier; + foreach (var wound in _wounds.GetWoundableWounds(targetedWoundable)) + { + if (!TryComp(wound.Item1, out var bleeds) || !bleeds.IsBleeding) + continue; + + if (bleedStopAbility > bleeds.BleedingAmount) + { + bleeds.BleedingAmountRaw = 0; + bleeds.IsBleeding = false; + + wound.Item2.CanBeHealed = true; + } + else + { + bleeds.BleedingAmountRaw -= bleedStopAbility; + } + + bleedStopAbility -= bleeds.BleedingAmount; + } + _bloodstreamSystem.TryModifyBleedAmount(ent, healing.ModifyBloodLevel); + + if (bleedStopAbility != healing.BloodlossModifier) + { + _popupSystem.PopupEntity(bleedStopAbility > 0 + ? Loc.GetString("rebell-medical-item-stop-bleeding-fully") + : Loc.GetString("rebell-medical-item-stop-bleeding-partially"), + ent, + args.User); + } + } + + if (targetedWoundable == EntityUid.Invalid || stuffToHeal.Count == 0 && healing.BloodlossModifier == 0) + { + _popupSystem.PopupEntity(Loc.GetString("medical-item-cant-use", ("item", args.User)), ent, args.User); + return; + } + + // Re-verify that we can heal the damage. + if (TryComp(args.Used.Value, out var stackComp)) + { + _stacks.Use(args.Used.Value, 1, stackComp); + + if (_stacks.GetCount(args.Used.Value, stackComp) <= 0) + dontRepeat = true; + } + else + { + QueueDel(args.Used.Value); + } + + var healedTotal = (FixedPoint2) 0; + foreach (var (key, value) in stuffToHeal) + { + if (_wounds.TryHealWoundsOnWoundable(targetedWoundable, -value, key, out var healed)) + { + healedTotal += healed; + continue; + } + + // Check for a group if it's not a type + if (_wounds.TryHealWoundsOnWoundable(targetedWoundable, -value, out var healedGroup, damageGroup: key)) + { + healedTotal += healedGroup; + } + } + + if (healedTotal <= 0) + { + if (healing.BloodlossModifier == 0) + _popupSystem.PopupEntity(Loc.GetString("medical-item-cant-use-rebell", ("target", ent)), ent, args.User, PopupType.MediumCaution); + + return; + } + + if (ent != args.User) + { + _adminLogger.Add(LogType.Healed, + $"{EntityManager.ToPrettyString(args.User):user} healed {EntityManager.ToPrettyString(ent):target} for {healedTotal:damage} damage"); + } + else + { + _adminLogger.Add(LogType.Healed, + $"{EntityManager.ToPrettyString(args.User):user} healed themselves for {healedTotal:damage} damage"); + } + + _audio.PlayPvs(healing.HealingEndSound, ent, AudioHelpers.WithVariation(0.125f, _random).WithVolume(1f)); + + // Logic to determine whether or not to repeat the healing action + args.Repeat = IsBodyDamaged((ent, comp), args.User, healing); + if (!args.Repeat && !dontRepeat) + _popupSystem.PopupEntity(Loc.GetString("medical-item-finished-using", ("item", args.Used)), ent, args.User, PopupType.Medium); + args.Handled = true; + } + private bool HasDamage(Entity ent, HealingComponent healing) { var damageableDict = ent.Comp.Damage.DamageDict; @@ -163,16 +306,30 @@ private bool HasDamage(Entity ent, HealingComponent healing return false; } - private bool IsPartDamaged(EntityUid user, EntityUid target) + private bool IsBodyDamaged(Entity target, EntityUid user, HealingComponent healing) { - if (!TryComp(user, out TargetingComponent? targeting)) + if (!TryComp(user, out var targeting)) return false; - var (targetType, targetSymmetry) = _bodySystem.ConvertTargetBodyPart(targeting.Target); - foreach (var part in _bodySystem.GetBodyChildrenOfType(target, targetType, symmetry: targetSymmetry)) - if (TryComp(part.Id, out var damageable) - && damageable.TotalDamage > part.Component.MinIntegrity) + var (partType, symmetry) = _bodySystem.ConvertTargetBodyPart(targeting.Target); + var targetedBodyPart = _bodySystem.GetBodyChildrenOfType(target, partType, target, symmetry).ToList().FirstOrDefault(); + + if (healing.Damage.DamageDict.Keys.ToList() + .Any(damage => _wounds.HasDamageOfGroup(targetedBodyPart.Id, damage) || _wounds.HasDamageOfType(targetedBodyPart.Id, damage))) + { + return true; + } + + if (healing.BloodlossModifier != 0) + { + foreach (var wound in _wounds.GetWoundableWounds(targetedBodyPart.Id)) + { + if (!TryComp(wound.Item1, out var bleeds) || !bleeds.IsBleeding) + continue; + return true; + } + } return false; } @@ -215,7 +372,8 @@ targetDamage.DamageContainerID is not null && var anythingToDo = HasDamage((target, targetDamage), component) || - IsPartDamaged(user, target) || + (TryComp(target, out var bodyComp) && // I'm paranoid, sorry. + IsBodyDamaged((target, bodyComp), user, component)) || component.ModifyBloodLevel > 0 // Special case if healing item can restore lost blood... && TryComp(target, out var bloodstream) && _solutionContainerSystem.ResolveSolution(target, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution) @@ -227,11 +385,9 @@ targetDamage.DamageContainerID is not null && return false; } - _audio.PlayPvs(component.HealingBeginSound, uid, - AudioHelpers.WithVariation(0.125f, _random).WithVolume(1f)); + _audio.PlayPvs(component.HealingBeginSound, uid, AudioHelpers.WithVariation(0.125f, _random).WithVolume(1f)); var isNotSelf = user != target; - if (isNotSelf) { var msg = Loc.GetString("medical-item-popup-target", ("user", Identity.Entity(user, EntityManager)), ("item", uid)); @@ -265,13 +421,19 @@ targetDamage.DamageContainerID is not null && public float GetScaledHealingPenalty(EntityUid uid, HealingComponent component) { var output = component.Delay; - if (!TryComp(uid, out var mobThreshold) || - !TryComp(uid, out var damageable)) + if (!TryComp(uid, out var mobThreshold)) return output; if (!_mobThresholdSystem.TryGetThresholdForState(uid, MobState.Critical, out var amount, mobThreshold)) return 1; - var percentDamage = (float) (damageable.TotalDamage / amount); + var percentDamage = (float) 1; + if (TryComp(uid, out var damageable)) + percentDamage = (float) (damageable.TotalDamage / amount); + else if (TryComp(uid, out var consciousness)) + { + percentDamage = (float) (consciousness.Threshold / consciousness.Cap - consciousness.Consciousness); + } + //basically make it scale from 1 to the multiplier. var modifier = percentDamage * (component.SelfHealPenaltyMultiplier - 1) + 1; return Math.Max(modifier, 1); diff --git a/Content.Server/Medical/HealthAnalyzerSystem.cs b/Content.Server/Medical/HealthAnalyzerSystem.cs index 93810ed0424..9f1d1c532c4 100644 --- a/Content.Server/Medical/HealthAnalyzerSystem.cs +++ b/Content.Server/Medical/HealthAnalyzerSystem.cs @@ -1,15 +1,11 @@ using Content.Server.Body.Components; -using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Medical.Components; using Content.Server.PowerCell; using Content.Server.Temperature.Components; -using Content.Server.Traits.Assorted; using Content.Shared.Backmen.Targeting; using Content.Shared.Chemistry.EntitySystems; -// backmen: surgery Start using Content.Shared.Body.Part; using Content.Shared.Body.Systems; -// backmen: surgery End using Content.Shared.Damage; using Content.Shared.DoAfter; using Content.Shared.IdentityManagement; @@ -23,9 +19,13 @@ using Robust.Server.GameObjects; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; -using Robust.Shared.Player; using Robust.Shared.Timing; using System.Linq; +using Content.Server.Traits.Assorted; +using Content.Shared.Backmen.Surgery.Traumas.Components; +using Content.Shared.Backmen.Surgery.Wounds; +using Content.Shared.Backmen.Surgery.Wounds.Systems; +using Content.Shared.Body.Components; using Content.Shared.Traits.Assorted; namespace Content.Server.Medical; @@ -39,6 +39,7 @@ public sealed class HealthAnalyzerSystem : EntitySystem [Dependency] private readonly ItemToggleSystem _toggle = default!; [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly SharedBodySystem _bodySystem = default!; + [Dependency] private readonly WoundSystem _woundSystem = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; [Dependency] private readonly TransformSystem _transformSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; @@ -239,8 +240,6 @@ public void UpdateScannedUser(EntityUid healthAnalyzer, EntityUid target, bool s if (!_uiSystem.HasUi(healthAnalyzer, HealthAnalyzerUiKey.Key)) return; - if (!HasComp(target)) - return; var bodyTemperature = float.NaN; if (TryComp(target, out var temp)) @@ -262,9 +261,9 @@ public void UpdateScannedUser(EntityUid healthAnalyzer, EntityUid target, bool s unrevivable = true; // Start-backmen: surgery - Dictionary? body = null; - if (HasComp(target)) - body = _bodySystem.GetBodyPartStatus(target); + Dictionary? body = null; + if (HasComp(target)) + body = _woundSystem.GetWoundableStatesOnBody(target); // End-backmen: surgery _uiSystem.ServerSendUiMessage(healthAnalyzer, HealthAnalyzerUiKey.Key, new HealthAnalyzerScannedUserMessage( diff --git a/Content.Server/Medical/VomitSystem.cs b/Content.Server/Medical/VomitSystem.cs index 006ea402048..5fcd660809d 100644 --- a/Content.Server/Medical/VomitSystem.cs +++ b/Content.Server/Medical/VomitSystem.cs @@ -13,6 +13,7 @@ using Content.Shared.StatusEffect; using Robust.Server.Audio; using Content.Shared.Backmen.Mood; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Robust.Shared.Audio; using Robust.Shared.Prototypes; diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs index 48fb946135e..908d76dc9d9 100644 --- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs +++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs @@ -14,6 +14,7 @@ using Content.Shared.Nutrition; using System.Threading; using Content.Shared.Atmos; +using Content.Shared.Backmen.Surgery.Traumas.Components; /// /// System for vapes diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs index 0d637139d82..32a9fb9f280 100644 --- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs @@ -17,6 +17,7 @@ using Robust.Server.GameObjects; using Robust.Shared.Containers; using System.Linq; +using Content.Shared.Backmen.Surgery.Traumas.Components; namespace Content.Server.Nutrition.EntitySystems { diff --git a/Content.Server/Tourniquet/TourniquetComponent.cs b/Content.Server/Tourniquet/TourniquetComponent.cs new file mode 100644 index 00000000000..69e14eb851d --- /dev/null +++ b/Content.Server/Tourniquet/TourniquetComponent.cs @@ -0,0 +1,43 @@ +using Content.Shared.Body.Part; +using Robust.Shared.Audio; + +namespace Content.Server.Tourniquet; + +/// +/// This is used for tourniquet. Yes +/// +[RegisterComponent] +public sealed partial class TourniquetComponent : Component +{ + [ViewVariables(VVAccess.ReadOnly)] + public EntityUid? BodyPartTorniqueted; + + /// + /// How long it takes to put the tourniquet on. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public float Delay = 5f; + + /// + /// How long it takes to take the tourniquet off. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public float RemoveDelay = 7f; + + [DataField, ViewVariables(VVAccess.ReadOnly)] + public List BlockedBodyParts = new(); + + /// + /// Sound played on healing begin + /// + [DataField("putOnSound")] + public SoundSpecifier? TourniquetPutOnSound = null; + + /// + /// Sound played on healing end + /// + [DataField("putOffSound")] + public SoundSpecifier? TourniquetPutOffSound = null; +} diff --git a/Content.Server/Tourniquet/TourniquetSystem.cs b/Content.Server/Tourniquet/TourniquetSystem.cs new file mode 100644 index 00000000000..d3f404362a4 --- /dev/null +++ b/Content.Server/Tourniquet/TourniquetSystem.cs @@ -0,0 +1,221 @@ +using System.Linq; +using Content.Shared.Backmen.Surgery.Pain.Systems; +using Content.Shared.Backmen.Surgery.Traumas.Components; +using Content.Shared.Backmen.Surgery.Wounds.Systems; +using Content.Shared.Backmen.Targeting; +using Content.Shared.Body.Components; +using Content.Shared.Body.Systems; +using Content.Shared.DoAfter; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Interaction; +using Content.Shared.Interaction.Events; +using Content.Shared.Popups; +using Content.Shared.Tourniquet; +using Content.Shared.Verbs; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Containers; + +namespace Content.Server.Tourniquet; + +/// +/// This handles tourniqueting people +/// +public sealed class TourniquetSystem : EntitySystem +{ + [Dependency] private readonly SharedBodySystem _body = default!; + [Dependency] private readonly WoundSystem _wound = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly PainSystem _pain = default!; + + private const string TourniquetContainerId = "Tourniquet"; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTourniquetUse); + SubscribeLocalEvent(OnTourniquetAfterInteract); + + SubscribeLocalEvent(OnBodyDoAfter); + SubscribeLocalEvent(OnTourniquetTakenOff); + + SubscribeLocalEvent>(OnBodyGetVerbs); + } + + private bool TryTourniquet(EntityUid target, EntityUid user, EntityUid tourniquetEnt, TourniquetComponent tourniquet) + { + if (!TryComp(user, out var targeting)) + return false; + + if (!HasComp(target)) + return false; + + var (partType, symmetry) = _body.ConvertTargetBodyPart(targeting.Target); + if (tourniquet.BlockedBodyParts.Contains(partType)) + return false; + + var targetPart = _body.GetBodyChildrenOfType(target, partType, symmetry: symmetry).FirstOrDefault(); + _popup.PopupEntity(Loc.GetString("puts-on-a-tourniquet", ("user", user), ("part", targetPart.Id)), target, PopupType.Medium); + + _audio.PlayPvs(tourniquet.TourniquetPutOnSound, target, AudioParams.Default.WithVariation(0.125f).WithVolume(1f)); + + var doAfterEventArgs = + new DoAfterArgs(EntityManager, user, tourniquet.Delay, new TourniquetDoAfterEvent(), target, target: target, used: tourniquetEnt) + { + BreakOnDamage = true, + NeedHand = true, + BreakOnMove = true, + BreakOnWeightlessMove = false, + }; + + _doAfter.TryStartDoAfter(doAfterEventArgs); + return true; + } + + private void TakeOffTourniquet(EntityUid target, EntityUid user, EntityUid tourniquetEnt, TourniquetComponent tourniquet) + { + _popup.PopupEntity(Loc.GetString("takes-off-a-tourniquet", ("user", user), ("part", tourniquet.BodyPartTorniqueted!)), target, PopupType.Medium); + _audio.PlayPvs(tourniquet.TourniquetPutOffSound, target, AudioParams.Default.WithVariation(0.125f).WithVolume(1f)); + + var doAfterEventArgs = + new DoAfterArgs(EntityManager, user, tourniquet.RemoveDelay, new RemoveTourniquetDoAfterEvent(), target, target: target, used: tourniquetEnt) + { + BreakOnDamage = true, + NeedHand = true, + BreakOnMove = true, + BreakOnWeightlessMove = false, + }; + + _doAfter.TryStartDoAfter(doAfterEventArgs); + } + + private void OnTourniquetUse(Entity ent, ref UseInHandEvent args) + { + if (args.Handled) + return; + + if (TryTourniquet(args.User, args.User, ent, ent)) + args.Handled = true; + } + + private void OnTourniquetAfterInteract(Entity ent, ref AfterInteractEvent args) + { + if (args.Handled || !args.CanReach || args.Target == null) + return; + + if (TryTourniquet(args.Target.Value, args.User, ent, ent)) + args.Handled = true; + } + + private void OnBodyDoAfter(EntityUid ent, BodyComponent comp, ref TourniquetDoAfterEvent args) + { + if (args.Handled || args.Cancelled) + return; + + if (!TryComp(args.Used, out var tourniquet)) + return; + + if (!TryComp(args.User, out var targeting)) + return; + + var (partType, symmetry) = _body.ConvertTargetBodyPart(targeting.Target); + if (tourniquet.BlockedBodyParts.Contains(partType)) + return; + + var container = _container.EnsureContainer(args.Target!.Value, TourniquetContainerId); + if (container.ContainedEntity.HasValue) + { + _popup.PopupEntity(Loc.GetString("already-tourniqueted"), ent, PopupType.Medium); + return; + } + + if (!_container.Insert(args.Used.Value, container)) + { + _popup.PopupEntity(Loc.GetString("cant-tourniquet"), ent, PopupType.Medium); + return; + } + + var targetPart = _body.GetBodyChildrenOfType(ent, partType, symmetry: symmetry).FirstOrDefault(); + + _wound.TryHaltAllBleeding(targetPart.Id); + _pain.TryAddPainFeelsModifier(args.Used.Value, "Tourniquet", targetPart.Id, -10f); + + foreach (var woundable in _wound.GetAllWoundableChildren(targetPart.Id)) + { + _wound.TryHaltAllBleeding(woundable.Item1); + _pain.TryAddPainFeelsModifier(woundable.Item1, "Tourniquet", targetPart.Id, -10f); + } + + tourniquet.BodyPartTorniqueted = targetPart.Id; + + args.Repeat = false; + args.Handled = true; + } + + private void OnTourniquetTakenOff(EntityUid ent, BodyComponent comp, RemoveTourniquetDoAfterEvent args) + { + if (args.Handled || args.Cancelled) + return; + + if (!TryComp(args.Used, out var tourniquet)) + return; + + if (!_container.TryGetContainer(ent, TourniquetContainerId, out var container)) + return; + + foreach (var wound in _wound.GetAllWounds(tourniquet.BodyPartTorniqueted!.Value)) + { + wound.Item2.CanBleed = true; + wound.Item2.CanBeHealed = false; + + if (!TryComp(wound.Item1, out var bleeds)) + continue; + + bleeds.IsBleeding = true; + bleeds.BleedingScales = true; + + bleeds.ScalingLimit += 1; + // Punishing players for not healing people properly and using a tourniquet. + } + + _pain.TryRemovePainFeelsModifier(args.Used.Value, "Tourniquet", tourniquet.BodyPartTorniqueted!.Value); + foreach (var woundable in _wound.GetAllWoundableChildren(tourniquet.BodyPartTorniqueted!.Value)) + { + _pain.TryRemovePainFeelsModifier(args.Used.Value, "Tourniquet", woundable.Item1); + } + + _container.Remove(args.Used.Value, container); + + _hands.TryPickupAnyHand(args.User, args.Used.Value); + tourniquet.BodyPartTorniqueted = null; + + args.Handled = true; + } + + private void OnBodyGetVerbs(EntityUid ent, BodyComponent comp, GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract) + return; + + if (!_container.TryGetContainer(args.Target, TourniquetContainerId, out var container)) + return; + + foreach (var entity in container.ContainedEntities) + { + var tourniquet = Comp(entity); + InnateVerb verb = new() + { + Act = () => TakeOffTourniquet(args.Target, args.User, entity, tourniquet), + Text = Loc.GetString("take-off-tourniquet", ("part", tourniquet.BodyPartTorniqueted!)), + // Icon = new SpriteSpecifier.Texture(new ("/Textures/")), + Priority = 2 + }; + args.Verbs.Add(verb); + } + } +} diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs index b0a95624b97..39816a597d4 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs @@ -212,7 +212,7 @@ public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? var hitName = ToPrettyString(hitEntity); if (dmg != null) - dmg = Damageable.TryChangeDamage(hitEntity, dmg * Damageable.UniversalHitscanDamageModifier, origin: user, canEvade: true); // backmen: surgery + dmg = Damageable.TryChangeDamage(hitEntity, dmg * Damageable.UniversalHitscanDamageModifier, origin: user, canBeCancelled: true); // backmen: surgery // check null again, as TryChangeDamage returns modified damage values if (dmg != null) diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index 798d9585dfe..39a4e7e54bc 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -13,6 +13,7 @@ using Content.Server.NPC.Systems; using Content.Server.Speech.Components; using Content.Server.Temperature.Components; +using Content.Shared.Backmen.Surgery.Traumas.Components; using Content.Shared.CombatMode; using Content.Shared.CombatMode.Pacification; using Content.Shared.Damage; diff --git a/Content.Shared/Armor/ArmorComponent.cs b/Content.Shared/Armor/ArmorComponent.cs index 8ffbb5a4f83..56a7eaa861c 100644 --- a/Content.Shared/Armor/ArmorComponent.cs +++ b/Content.Shared/Armor/ArmorComponent.cs @@ -1,4 +1,8 @@ -using Content.Shared.Damage; +using Content.Shared.Backmen.Surgery.Traumas.Systems; +using Content.Shared.Body.Part; +using Content.Shared.Damage; +using Content.Shared.FixedPoint; +using Content.Shared.Damage; using Content.Shared.Inventory; using Robust.Shared.GameStates; using Robust.Shared.Utility; @@ -8,7 +12,7 @@ namespace Content.Shared.Armor; /// /// Used for clothing that reduces damage when worn. /// -[RegisterComponent, NetworkedComponent, Access(typeof(SharedArmorSystem))] +[RegisterComponent, NetworkedComponent, Access(typeof(SharedArmorSystem), typeof(TraumaSystem))] public sealed partial class ArmorComponent : Component { /// @@ -23,6 +27,25 @@ public sealed partial class ArmorComponent : Component /// [DataField] public float PriceMultiplier = 1; + + /// + /// If true, the coverage won't show. + /// + [DataField("coverageHidden")] + public bool ArmourCoverageHidden = false; + + /// + /// If true, the modifiers won't show. + /// + [DataField("modifiersHidden")] + public bool ArmourModifiersHidden = false; + + // thankfully all the armor in the game is symmetrical. + [DataField("coverage")] + public List ArmorCoverage = new(); + + [DataField] + public FixedPoint2 DismembermentChanceDeduction = 0; } /// diff --git a/Content.Shared/Armor/SharedArmorSystem.cs b/Content.Shared/Armor/SharedArmorSystem.cs index bea875256f8..38c35c35f68 100644 --- a/Content.Shared/Armor/SharedArmorSystem.cs +++ b/Content.Shared/Armor/SharedArmorSystem.cs @@ -1,4 +1,7 @@ -using Content.Shared.Damage; +using System.Linq; +using Content.Shared.Body.Part; +using Content.Shared.Body.Systems; +using Content.Shared.Damage; using Content.Shared.Examine; using Content.Shared.Inventory; using Content.Shared.Silicons.Borgs; @@ -13,6 +16,7 @@ namespace Content.Shared.Armor; public abstract class SharedArmorSystem : EntitySystem { [Dependency] private readonly ExamineSystemShared _examine = default!; + [Dependency] private readonly SharedBodySystem _body = default!; /// public override void Initialize() @@ -40,7 +44,12 @@ private void OnCoefficientQuery(Entity ent, ref InventoryRelayed private void OnDamageModify(EntityUid uid, ArmorComponent component, InventoryRelayedEvent args) { - args.Args.Damage = DamageSpecifier.ApplyModifierSet(args.Args.Damage, component.Modifiers); + var (partType, _) = _body.ConvertTargetBodyPart(args.Args.TargetPart); + + if (component.ArmorCoverage.Contains(partType)) + { + args.Args.Damage = DamageSpecifier.ApplyModifierSet(args.Args.Damage, component.Modifiers); + } } private void OnBorgDamageModify(EntityUid uid, ArmorComponent component, @@ -54,7 +63,13 @@ private void OnArmorVerbExamine(EntityUid uid, ArmorComponent component, GetVerb if (!args.CanInteract || !args.CanAccess) return; - var examineMarkup = GetArmorExamine(component.Modifiers); + if (component is { ArmourCoverageHidden: true, ArmourModifiersHidden: true }) + return; + + if (!component.Modifiers.Coefficients.Any() && !component.Modifiers.FlatReduction.Any()) + return; + + var examineMarkup = GetArmorExamine(component); var ev = new ArmorExamineEvent(examineMarkup); RaiseLocalEvent(uid, ref ev); @@ -64,31 +79,48 @@ private void OnArmorVerbExamine(EntityUid uid, ArmorComponent component, GetVerb Loc.GetString("armor-examinable-verb-message")); } - private FormattedMessage GetArmorExamine(DamageModifierSet armorModifiers) + private FormattedMessage GetArmorExamine(ArmorComponent component) { var msg = new FormattedMessage(); msg.AddMarkupOrThrow(Loc.GetString("armor-examine")); - foreach (var coefficientArmor in armorModifiers.Coefficients) + var coverage = component.ArmorCoverage; + var armorModifiers = component.Modifiers; + + if (!component.ArmourCoverageHidden) { - msg.PushNewline(); + foreach (var coveragePart in coverage.Where(coveragePart => coveragePart != BodyPartType.Other)) + { + msg.PushNewline(); - var armorType = Loc.GetString("armor-damage-type-" + coefficientArmor.Key.ToLower()); - msg.AddMarkupOrThrow(Loc.GetString("armor-coefficient-value", - ("type", armorType), - ("value", MathF.Round((1f - coefficientArmor.Value) * 100, 1)) - )); + var bodyPartType = Loc.GetString("armor-coverage-type-" + coveragePart.ToString().ToLower()); + msg.AddMarkupOrThrow(Loc.GetString("armor-coverage-value", ("type", bodyPartType))); + } } - foreach (var flatArmor in armorModifiers.FlatReduction) + if (!component.ArmourModifiersHidden) { - msg.PushNewline(); - - var armorType = Loc.GetString("armor-damage-type-" + flatArmor.Key.ToLower()); - msg.AddMarkupOrThrow(Loc.GetString("armor-reduction-value", - ("type", armorType), - ("value", flatArmor.Value) - )); + foreach (var coefficientArmor in armorModifiers.Coefficients) + { + msg.PushNewline(); + + var armorType = Loc.GetString("armor-damage-type-" + coefficientArmor.Key.ToLower()); + msg.AddMarkupOrThrow(Loc.GetString("armor-coefficient-value", + ("type", armorType), + ("value", MathF.Round((1f - coefficientArmor.Value) * 100, 1)) + )); + } + + foreach (var flatArmor in armorModifiers.FlatReduction) + { + msg.PushNewline(); + + var armorType = Loc.GetString("armor-damage-type-" + flatArmor.Key.ToLower()); + msg.AddMarkupOrThrow(Loc.GetString("armor-reduction-value", + ("type", armorType), + ("value", flatArmor.Value) + )); + } } return msg; diff --git a/Content.Shared/Backmen/Standing/SharedLayingDownSystem.cs b/Content.Shared/Backmen/Standing/SharedLayingDownSystem.cs index c1e5426b07b..93988eca34a 100644 --- a/Content.Shared/Backmen/Standing/SharedLayingDownSystem.cs +++ b/Content.Shared/Backmen/Standing/SharedLayingDownSystem.cs @@ -48,7 +48,6 @@ public abstract class SharedLayingDownSystem : EntitySystem [Dependency] private readonly ISharedPlayerManager _playerManager = default!; [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedBuckleSystem _buckle = default!; - [Dependency] private readonly INetManager _net = default!; [Dependency] private readonly PullingSystem _pulling = default!; [Dependency] private readonly SharedMapSystem _map = default!; [Dependency] private readonly SharedStunSystem _stun = default!; @@ -323,7 +322,7 @@ standingState.CurrentState is not StandingState.Lying || obj.Value, uid, PopupType.MediumCaution); - _damageable.TryChangeDamage(uid, new DamageSpecifier(){DamageDict = {{"Blunt", 5}}}, ignoreResistances: true, canEvade: false, canSever: false, targetPart: TargetBodyPart.Head); + _damageable.TryChangeDamage(uid, new DamageSpecifier{DamageDict = {{"Blunt", 5}}}, canBeCancelled: false, ignoreResistances: true, targetPart: TargetBodyPart.Head); _stun.TryStun(uid, TimeSpan.FromSeconds(2), true); _audioSystem.PlayPredicted(_bonkSound, uid, obj.Value); return false; diff --git a/Content.Shared/Backmen/Surgery/Body/AmputateAttemptEvent.cs b/Content.Shared/Backmen/Surgery/Body/AmputateAttemptEvent.cs deleted file mode 100644 index b71a0407bf2..00000000000 --- a/Content.Shared/Backmen/Surgery/Body/AmputateAttemptEvent.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Content.Shared.Body.Events; - -/// -/// Raised on an entity when attempting to remove a body part. -/// -[ByRefEvent] -public readonly record struct AmputateAttemptEvent(EntityUid Part); diff --git a/Content.Shared/Backmen/Surgery/Body/Events/BodyPartEvents.cs b/Content.Shared/Backmen/Surgery/Body/Events/BodyPartEvents.cs index a1bb59761d6..70be572d1ff 100644 --- a/Content.Shared/Backmen/Surgery/Body/Events/BodyPartEvents.cs +++ b/Content.Shared/Backmen/Surgery/Body/Events/BodyPartEvents.cs @@ -1,22 +1,8 @@ +using Content.Shared.Body.Components; using Content.Shared.Body.Part; namespace Content.Shared.Backmen.Surgery.Body.Events; -/// -/// Raised on an entity when attempting to remove a body part. -/// -[ByRefEvent] -public readonly record struct AmputateAttemptEvent(EntityUid Part); - -// Kind of a clone of BodyPartAddedEvent for surgical reattachment specifically. -[ByRefEvent] -public readonly record struct BodyPartAttachedEvent(Entity Part); - -// Kind of a clone of BodyPartRemovedEvent for any instances where we call DropPart(), reasoning being that RemovedEvent fires off -// a lot more often than what I'd like due to PVS. -[ByRefEvent] -public readonly record struct BodyPartDroppedEvent(Entity Part); - [ByRefEvent] public readonly record struct BodyPartEnableChangedEvent(bool Enabled); diff --git a/Content.Shared/Backmen/Surgery/Body/SharedBodySystem.PartAppearance.cs b/Content.Shared/Backmen/Surgery/Body/SharedBodySystem.PartAppearance.cs index a917aaa8ecb..725a98081b0 100644 --- a/Content.Shared/Backmen/Surgery/Body/SharedBodySystem.PartAppearance.cs +++ b/Content.Shared/Backmen/Surgery/Body/SharedBodySystem.PartAppearance.cs @@ -21,6 +21,7 @@ private void InitializePartAppearances() SubscribeLocalEvent(OnPartAppearanceStartup); SubscribeLocalEvent(HandleState); + SubscribeLocalEvent(OnPartAttachedToBody); SubscribeLocalEvent(OnPartDroppedFromBody); } diff --git a/Content.Shared/Backmen/Surgery/Body/SharedBodySystem.Targeting.cs b/Content.Shared/Backmen/Surgery/Body/SharedBodySystem.Targeting.cs deleted file mode 100644 index cb53658076f..00000000000 --- a/Content.Shared/Backmen/Surgery/Body/SharedBodySystem.Targeting.cs +++ /dev/null @@ -1,499 +0,0 @@ -using System.Linq; -using Content.Shared.Body.Components; -using Content.Shared.Body.Part; -using Content.Shared.Damage; -using Content.Shared.Mobs.Components; -using Content.Shared.IdentityManagement; -using Content.Shared.Mobs.Systems; -using Content.Shared.Popups; -using Content.Shared.Standing; -using Content.Shared.Backmen.Targeting; -using Robust.Shared.CPUJob.JobQueues; -using Robust.Shared.CPUJob.JobQueues.Queues; -using Robust.Shared.Network; -using Robust.Shared.Random; -using Robust.Shared.Timing; -using System.Threading; -using System.Threading.Tasks; -using Content.Shared.Backmen.Surgery.Body.Events; -using Content.Shared.Backmen.Surgery.Steps.Parts; -using Content.Shared.Damage.Prototypes; -using Content.Shared.FixedPoint; -using Content.Shared.Inventory; - -// ReSharper disable once CheckNamespace -namespace Content.Shared.Body.Systems; - -public partial class SharedBodySystem -{ - [Dependency] private readonly INetManager _net = default!; - [Dependency] private readonly MobStateSystem _mobState = default!; - [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly DamageableSystem _damageable = default!; - [Dependency] private readonly SharedPopupSystem _popup = default!; - - private readonly string[] _severingDamageTypes = { "Slash", "Pierce", "Blunt" }; - - private const double IntegrityJobTime = 0.005; - private readonly JobQueue _integrityJobQueue = new(IntegrityJobTime); - public sealed class IntegrityJob : Job - { - private readonly SharedBodySystem _self; - private readonly Entity _ent; - public IntegrityJob(SharedBodySystem self, Entity ent, double maxTime, CancellationToken cancellation = default) : base(maxTime, cancellation) - { - _self = self; - _ent = ent; - } - - public IntegrityJob(SharedBodySystem self, Entity ent, double maxTime, IStopwatch stopwatch, CancellationToken cancellation = default) : base(maxTime, stopwatch, cancellation) - { - _self = self; - _ent = ent; - } - - protected override Task Process() - { - _self.ProcessIntegrityTick(_ent); - - return Task.FromResult(null); - } - } - - private EntityQuery _queryTargeting; - private void InitializeBkm() - { - _queryTargeting = GetEntityQuery(); - SubscribeLocalEvent(OnTryChangePartDamage); - SubscribeLocalEvent(OnBodyDamageModify); - SubscribeLocalEvent(OnPartDamageModify); - SubscribeLocalEvent(OnDamageChanged); - } - - public DamageSpecifier GetHealingSpecifier(BodyPartComponent part) - { - var damage = new DamageSpecifier() - { - DamageDict = new Dictionary() - { - { "Blunt", -part.SelfHealingAmount }, - { "Slash", -part.SelfHealingAmount }, - { "Piercing", -part.SelfHealingAmount }, - { "Heat", -part.SelfHealingAmount }, - { "Cold", -part.SelfHealingAmount }, - { "Shock", -part.SelfHealingAmount }, - { "Caustic", -part.SelfHealingAmount * 0.1}, // not much caustic healing - } - }; - - return damage; - } - - private void ProcessIntegrityTick(Entity entity) - { - if (!TryComp(entity, out var damageable)) - return; - - var damage = damageable.TotalDamage; - - if (entity.Comp is { Body: { } body } - && damage > entity.Comp.MinIntegrity - && damage <= entity.Comp.IntegrityThresholds[TargetIntegrity.HeavilyWounded] - && _queryTargeting.HasComp(body) - && !_mobState.IsDead(body)) - _damageable.TryChangeDamage(entity, GetHealingSpecifier(entity), canSever: false, targetPart: GetTargetBodyPart(entity)); - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - _integrityJobQueue.Process(); - - if (!_timing.IsFirstTimePredicted) - return; - - using var query = EntityQueryEnumerator(); - while (query.MoveNext(out var ent, out var part)) - { - part.HealingTimer += frameTime; - - if (part.HealingTimer >= part.HealingTime) - { - part.HealingTimer = 0; - _integrityJobQueue.EnqueueJob(new IntegrityJob(this, (ent, part), IntegrityJobTime)); - } - } - } - - private void OnTryChangePartDamage(Entity ent, ref TryChangePartDamageEvent args) - { - // 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 (_queryTargeting.TryComp(ent, out var targetEnt)) - { - var damage = args.Damage; - TargetBodyPart? targetPart = null; - - if (args.TargetPart != null) - { - targetPart = args.TargetPart; - } - else if (args.Origin.HasValue && _queryTargeting.TryComp(args.Origin.Value, out var targeter)) - { - targetPart = targeter.Target; - // If the target is Torso then have a 33% chance to also hit another part - if (targetPart.Value == TargetBodyPart.Torso) - { - var additionalPart = GetRandomPartSpread(_random, 10); - targetPart = targetPart.Value | additionalPart; - } - } - else - { - // If there's an origin in this case, that means it comes from an entity without TargetingComponent, - // such as an animal, so we attack a random part. - if (args.Origin.HasValue) - { - targetPart = GetRandomBodyPart(ent, targetEnt); - } - // Otherwise we damage all parts equally (barotrauma, explosions, etc). - else if (damage != null) - { - // Division by 2 cuz damaging all parts by the same damage by default is too much. - damage /= 2; - targetPart = TargetBodyPart.All; - } - } - - if (targetPart == null) - return; - - if (!TryChangePartDamage(ent, args.Damage, args.CanSever, args.CanEvade, args.PartMultiplier, targetPart.Value) - && args.CanEvade) - { - _popup.PopupEntity(Loc.GetString("surgery-part-damage-evaded", ("user", Identity.Entity(ent, EntityManager))), ent); - args.Evaded = true; - } - } - } - - private void OnBodyDamageModify(Entity bodyEnt, ref DamageModifyEvent args) - { - if (args.TargetPart != null) - { - var (targetType, _) = ConvertTargetBodyPart(args.TargetPart.Value); - args.Damage *= GetPartDamageModifier(targetType); - } - } - - private void OnPartDamageModify(Entity partEnt, ref DamageModifyEvent args) - { - if (partEnt.Comp.Body != null - && TryComp(partEnt.Comp.Body.Value, out InventoryComponent? inventory)) - _inventory.RelayEvent((partEnt.Comp.Body.Value, inventory), ref args); - - if (_prototypeManager.TryIndex("PartDamage", out var partModifierSet)) - args.Damage = DamageSpecifier.ApplyModifierSet(args.Damage, partModifierSet); - - args.Damage *= GetPartDamageModifier(partEnt.Comp.PartType); - } - - private bool TryChangePartDamage(EntityUid entity, - DamageSpecifier damage, - bool canSever, - bool canEvade, - float partMultiplier, - TargetBodyPart targetParts) - { - var landed = false; - var targets = SharedTargetingSystem.GetValidParts(); - foreach (var target in targets) - { - if (!targetParts.HasFlag(target)) - continue; - - var (targetType, targetSymmetry) = ConvertTargetBodyPart(target); - if (GetBodyChildrenOfType(entity, targetType, symmetry: targetSymmetry) is { } part) - { - if (canEvade && TryEvadeDamage(part.FirstOrDefault().Id, GetEvadeChance(targetType))) - continue; - - var damageResult = _damageable.TryChangeDamage(part.FirstOrDefault().Id, damage * partMultiplier, canSever: canSever); - if (damageResult != null && damageResult.GetTotal() != 0) - landed = true; - } - } - - return landed; - } - - private void OnDamageChanged(Entity partEnt, ref DamageChangedEvent args) - { - if (!TryComp(partEnt, out var damageable)) - return; - - var severed = false; - var partIdSlot = GetParentPartAndSlotOrNull(partEnt)?.Slot; - var delta = args.DamageDelta; - - if (args.CanSever - && partEnt.Comp.CanSever - && partIdSlot is not null - && delta != null - && !HasComp(partEnt) - && !partEnt.Comp.Enabled - && damageable.TotalDamage >= partEnt.Comp.SeverIntegrity - && _severingDamageTypes.Any(damageType => delta.DamageDict.TryGetValue(damageType, out var value) && value > 0)) - severed = true; - - CheckBodyPart(partEnt, GetTargetBodyPart(partEnt), severed, damageable); - - if (severed) - DropPart(partEnt); - - Dirty(partEnt, partEnt.Comp); - } - - /// - /// Gets the random body part rolling a number between 1 and 9, and returns - /// Torso if the result is 9 or more. The higher torsoWeight is, the higher chance to return it. - /// - private static TargetBodyPart GetRandomPartSpread(IRobustRandom random, ushort torsoWeight = 9) - { - const int targetPartsAmount = 9; - return random.Next(1, targetPartsAmount + torsoWeight) switch - { - 1 => TargetBodyPart.Head, - 2 => TargetBodyPart.RightArm, - 3 => TargetBodyPart.RightHand, - 4 => TargetBodyPart.LeftArm, - 5 => TargetBodyPart.LeftHand, - 6 => TargetBodyPart.RightLeg, - 7 => TargetBodyPart.RightFoot, - 8 => TargetBodyPart.LeftLeg, - 9 => TargetBodyPart.LeftFoot, - _ => TargetBodyPart.Torso, - }; - } - - public TargetBodyPart? GetRandomBodyPart(EntityUid uid, TargetingComponent? target = null) - { - if (!Resolve(uid, ref target)) - return null; - - var totalWeight = target.TargetOdds.Values.Sum(); - var randomValue = _random.NextFloat() * totalWeight; - - foreach (var (part, weight) in target.TargetOdds) - { - if (randomValue <= weight) - return part; - randomValue -= weight; - } - - return TargetBodyPart.Torso; // Default to torso if something goes wrong - } - - /// This should be called after body part damage was changed. - /// - public void CheckBodyPart( - Entity partEnt, - TargetBodyPart? targetPart, - bool severed, - DamageableComponent? damageable = null) - { - if (!Resolve(partEnt, ref damageable)) - return; - - var integrity = damageable.TotalDamage; - - // KILL the body part - if (partEnt.Comp.Enabled && integrity >= partEnt.Comp.IntegrityThresholds[TargetIntegrity.CriticallyWounded]) - { - var ev = new BodyPartEnableChangedEvent(false); - RaiseLocalEvent(partEnt, ref ev); - } - - // LIVE the body part - if (!partEnt.Comp.Enabled && integrity <= partEnt.Comp.IntegrityThresholds[partEnt.Comp.EnableIntegrity] && !severed) - { - var ev = new BodyPartEnableChangedEvent(true); - RaiseLocalEvent(partEnt, ref ev); - } - - if (_queryTargeting.TryComp(partEnt.Comp.Body, out var targeting) - && HasComp(partEnt.Comp.Body)) - { - var newIntegrity = GetIntegrityThreshold(partEnt.Comp, integrity.Float(), severed); - // We need to check if the part is dead to prevent the UI from showing dead parts as alive. - if (targetPart is not null && - targeting.BodyStatus.ContainsKey(targetPart.Value) && - targeting.BodyStatus[targetPart.Value] != TargetIntegrity.Dead) - { - targeting.BodyStatus[targetPart.Value] = newIntegrity; - if (targetPart.Value == TargetBodyPart.Torso) - targeting.BodyStatus[TargetBodyPart.Groin] = newIntegrity; - - Dirty(partEnt.Comp.Body.Value, targeting); - } - // Revival events are handled by the server, so we end up being locked to a network event. - // I hope you like the _net.IsServer, Remuchi :) - if (_net.IsServer) - RaiseNetworkEvent(new TargetIntegrityChangeEvent(GetNetEntity(partEnt.Comp.Body.Value)), partEnt.Comp.Body.Value); - } - } - - /// - /// Gets the integrity of all body parts in the entity. - /// - public Dictionary GetBodyPartStatus(EntityUid entityUid) - { - var result = new Dictionary(); - - if (!TryComp(entityUid, out var body)) - return result; - - foreach (var part in SharedTargetingSystem.GetValidParts()) - { - result[part] = TargetIntegrity.Severed; - } - - foreach (var partComponent in GetBodyChildren(entityUid, body)) - { - var targetBodyPart = GetTargetBodyPart(partComponent.Component.PartType, partComponent.Component.Symmetry); - - if (targetBodyPart != null && TryComp(partComponent.Id, out var damageable)) - result[targetBodyPart.Value] = GetIntegrityThreshold(partComponent.Component, damageable.TotalDamage.Float(), false); - } - - // Hardcoded shitcode for Groin :) - result[TargetBodyPart.Groin] = result[TargetBodyPart.Torso]; - - return result; - } - - public TargetBodyPart? GetTargetBodyPart(Entity part) => GetTargetBodyPart(part.Comp.PartType, part.Comp.Symmetry); - public TargetBodyPart? GetTargetBodyPart(BodyPartComponent part) => GetTargetBodyPart(part.PartType, part.Symmetry); - /// - /// Converts Enums from BodyPartType to their Targeting system equivalent. - /// - public TargetBodyPart? GetTargetBodyPart(BodyPartType type, BodyPartSymmetry symmetry) - { - return (type, symmetry) switch - { - (BodyPartType.Head, _) => TargetBodyPart.Head, - (BodyPartType.Torso, _) => TargetBodyPart.Torso, - (BodyPartType.Arm, BodyPartSymmetry.Left) => TargetBodyPart.LeftArm, - (BodyPartType.Arm, BodyPartSymmetry.Right) => TargetBodyPart.RightArm, - (BodyPartType.Hand, BodyPartSymmetry.Left) => TargetBodyPart.LeftHand, - (BodyPartType.Hand, BodyPartSymmetry.Right) => TargetBodyPart.RightHand, - (BodyPartType.Leg, BodyPartSymmetry.Left) => TargetBodyPart.LeftLeg, - (BodyPartType.Leg, BodyPartSymmetry.Right) => TargetBodyPart.RightLeg, - (BodyPartType.Foot, BodyPartSymmetry.Left) => TargetBodyPart.LeftFoot, - (BodyPartType.Foot, BodyPartSymmetry.Right) => TargetBodyPart.RightFoot, - _ => null - }; - } - - /// - /// Converts Enums from Targeting system to their BodyPartType equivalent. - /// - public (BodyPartType Type, BodyPartSymmetry Symmetry) ConvertTargetBodyPart(TargetBodyPart targetPart) - { - return targetPart switch - { - TargetBodyPart.Head => (BodyPartType.Head, BodyPartSymmetry.None), - TargetBodyPart.Torso => (BodyPartType.Torso, BodyPartSymmetry.None), - TargetBodyPart.Groin => (BodyPartType.Torso, BodyPartSymmetry.None), // TODO: Groin is not a part type yet - TargetBodyPart.LeftArm => (BodyPartType.Arm, BodyPartSymmetry.Left), - TargetBodyPart.LeftHand => (BodyPartType.Hand, BodyPartSymmetry.Left), - TargetBodyPart.RightArm => (BodyPartType.Arm, BodyPartSymmetry.Right), - TargetBodyPart.RightHand => (BodyPartType.Hand, BodyPartSymmetry.Right), - TargetBodyPart.LeftLeg => (BodyPartType.Leg, BodyPartSymmetry.Left), - TargetBodyPart.LeftFoot => (BodyPartType.Foot, BodyPartSymmetry.Left), - TargetBodyPart.RightLeg => (BodyPartType.Leg, BodyPartSymmetry.Right), - TargetBodyPart.RightFoot => (BodyPartType.Foot, BodyPartSymmetry.Right), - _ => (BodyPartType.Torso, BodyPartSymmetry.None) - }; - - } - - /// - /// Fetches the damage multiplier for part integrity based on part types. - /// - /// TODO: Serialize this per body part. - public static float GetPartDamageModifier(BodyPartType partType) - { - return partType switch - { - BodyPartType.Head => 0.5f, // 50% damage, necks are hard to cut - BodyPartType.Torso => 1.0f, // 100% damage - BodyPartType.Arm => 0.7f, // 70% damage - BodyPartType.Hand => 0.7f, // 70% damage - BodyPartType.Leg => 0.7f, // 70% damage - BodyPartType.Foot => 0.7f, // 70% damage - }; - } - - /// - /// Fetches the TargetIntegrity equivalent of the current integrity value for the body part. - /// - public static TargetIntegrity GetIntegrityThreshold(BodyPartComponent component, float integrity, bool severed) - { - var enabled = component.Enabled; - - if (severed) - return TargetIntegrity.Severed; - else if (!component.Enabled) - return TargetIntegrity.Disabled; - - var targetIntegrity = TargetIntegrity.Healthy; - foreach (var threshold in component.IntegrityThresholds) - { - if (integrity <= threshold.Value) - targetIntegrity = threshold.Key; - } - - return targetIntegrity; - } - - /// - /// Fetches the chance to evade integrity damage for a body part. - /// Used when the entity is not dead, laying down, or incapacitated. - /// - public static float GetEvadeChance(BodyPartType partType) - { - return partType switch - { - BodyPartType.Head => 0.70f, // 70% chance to evade - BodyPartType.Arm => 0.20f, // 20% chance to evade - BodyPartType.Hand => 0.20f, // 20% chance to evade - BodyPartType.Leg => 0.20f, // 20% chance to evade - BodyPartType.Foot => 0.20f, // 20% chance to evade - BodyPartType.Torso => 0f, // 0% chance to evade - _ => 0f - }; - } - - public bool CanEvadeDamage(Entity uid) - { - if (!Resolve(uid, ref uid.Comp)) - return false; - - return TryComp(uid, out var standingState) - && !_mobState.IsCritical(uid, uid) - && !_mobState.IsDead(uid, uid) - && standingState.CurrentState != StandingState.Lying; - } - - public bool TryEvadeDamage(Entity uid, float evadeChance) - { - if (!Resolve(uid, ref uid.Comp)) - return false; - - if (!CanEvadeDamage(uid)) - return false; - - return _random.NextFloat() < evadeChance; - } -} diff --git a/Content.Shared/Backmen/Surgery/Body/Subsystems/GenerateChildPartSystem.cs b/Content.Shared/Backmen/Surgery/Body/Subsystems/GenerateChildPartSystem.cs deleted file mode 100644 index d2f691e90d7..00000000000 --- a/Content.Shared/Backmen/Surgery/Body/Subsystems/GenerateChildPartSystem.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Content.Shared.Body.Part; -using Content.Shared.Body.Systems; -using Robust.Shared.Map; -using Robust.Shared.Timing; -using Robust.Shared.Network; -using System.Numerics; -using Content.Shared.Backmen.Surgery.Body.Events; - -namespace Content.Shared.Backmen.Surgery.Body.Subsystems; - -public sealed class GenerateChildPartSystem : EntitySystem -{ - [Dependency] private readonly SharedBodySystem _bodySystem = default!; - [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly INetManager _net = default!; - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnPartComponentsModify); - } - - private void OnPartComponentsModify(EntityUid uid, GenerateChildPartComponent component, ref BodyPartComponentsModifyEvent args) - { - if (args.Add) - CreatePart(uid, component); - //else - //DeletePart(uid, component); - } - - private void CreatePart(EntityUid uid, GenerateChildPartComponent component) - { - if (!TryComp(uid, out BodyPartComponent? partComp) - || partComp.Body is null - || component.Active) - return; - - // I pinky swear to also move this to the server side properly next update :) - if (_net.IsServer) - { - var childPart = Spawn(component.Id, new EntityCoordinates(partComp.Body.Value, Vector2.Zero)); - - if (!TryComp(childPart, out BodyPartComponent? childPartComp)) - return; - - var slotName = _bodySystem.GetSlotFromBodyPart(childPartComp); - _bodySystem.TryCreatePartSlot(uid, slotName, childPartComp.PartType, out var _); - _bodySystem.AttachPart(uid, slotName, childPart, partComp, childPartComp); - component.ChildPart = childPart; - component.Active = true; - Dirty(childPart, childPartComp); - } - } - - // Still unusued, gotta figure out what I want to do with this function outside of fuckery with mantis blades. - private void DeletePart(EntityUid uid, GenerateChildPartComponent component) - { - if (!TryComp(uid, out BodyPartComponent? partComp)) - return; - - _bodySystem.DropSlotContents((uid, partComp)); - var ev = new BodyPartDroppedEvent((uid, partComp)); - RaiseLocalEvent(uid, ref ev); - QueueDel(uid); - } -} - diff --git a/Content.Shared/Backmen/Surgery/CCVar/SurgeryCVars.cs b/Content.Shared/Backmen/Surgery/CCVar/SurgeryCVars.cs new file mode 100644 index 00000000000..b2228e9df26 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/CCVar/SurgeryCVars.cs @@ -0,0 +1,48 @@ +using Content.Shared.FixedPoint; +using Robust.Shared; +using Robust.Shared.Configuration; + +namespace Content.Shared.Backmen.Surgery.CCVar; + +public sealed class SurgeryCvars : CVars +{ + /* + * Medical CVars + */ + + /// + /// How many times per second do we want to heal wounds. + /// + public static readonly CVarDef MedicalHealingTickrate = + CVarDef.Create("medical.heal_tickrate", 0.5f, CVar.SERVER | CVar.REPLICATED); + + /// + /// The name is self-explanatory + /// + public static readonly CVarDef MaxWoundSeverity = + CVarDef.Create("wounding.max_wound_severity", 200f, CVar.SERVER | CVar.REPLICATED); + + /// + /// The same as above + /// + public static readonly CVarDef WoundScarChance = + CVarDef.Create("wounding.wound_scar_chance", 0.10f, CVar.SERVER | CVar.REPLICATED); + + /// + /// What part of wounds will be transferred from a destroyed woundable to its parent? + /// + public static readonly CVarDef WoundTransferPart = + CVarDef.Create("wounding.wound_severity_transfer", 0.10f, CVar.SERVER | CVar.REPLICATED); + + /// + /// for every x units of distance, (tiles), chance for dodging is increased by x percents, look for it down here + /// + public static readonly CVarDef DodgeDistanceChance = + CVarDef.Create("targeting.dodge_chance_distance", 4f, CVar.SERVER | CVar.REPLICATED); + + /// + /// for every x units of distance, (tiles), chance for dodging is increased by x percents, look for it down here + /// + public static readonly CVarDef DodgeDistanceChange = + CVarDef.Create("targeting.dodge_change_distance", 0.05f, CVar.SERVER | CVar.REPLICATED); +} diff --git a/Content.Shared/Backmen/Surgery/Consciousness/Components/ConsciousnessComponent.cs b/Content.Shared/Backmen/Surgery/Consciousness/Components/ConsciousnessComponent.cs new file mode 100644 index 00000000000..a09d5aa8dbc --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Consciousness/Components/ConsciousnessComponent.cs @@ -0,0 +1,88 @@ +using Content.Shared.Backmen.Surgery.Pain.Components; +using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; + +namespace Content.Shared.Backmen.Surgery.Consciousness.Components; + +[RegisterComponent, NetworkedComponent] +public sealed partial class ConsciousnessComponent : Component +{ + /// + /// Represents the limit at which point the entity falls unconscious. + /// + [DataField(required: true)] + [ViewVariables(VVAccess.ReadOnly)] + public FixedPoint2 Threshold = 30; + + /// + /// Represents the base consciousness value before applying any modifiers. + /// + [DataField] + [ViewVariables(VVAccess.ReadOnly)] + public FixedPoint2 RawConsciousness = -1; + + /// + /// Gets the consciousness value after applying the multiplier and clamping between 0 and Cap. + /// + [ViewVariables(VVAccess.ReadOnly)] + public FixedPoint2 Consciousness => FixedPoint2.Clamp(RawConsciousness * Multiplier, 0, Cap); + + /// + /// Represents the multiplier to be applied on the RawConsciousness. + /// + [DataField] + [ViewVariables(VVAccess.ReadOnly)] + public FixedPoint2 Multiplier = 1.0; + + /// + /// Represents the maximum possible consciousness value. Also used as the default RawConsciousness value if it is set to -1. + /// + [DataField] + [ViewVariables(VVAccess.ReadOnly)] + public FixedPoint2 Cap = 100; + + /// + /// Represents the collection of additional effects that modify the base consciousness level. + /// + [ViewVariables(VVAccess.ReadOnly)] + public Dictionary<(EntityUid, string), ConsciousnessModifier> Modifiers = new(); + + /// + /// Represents the collection of coefficients that further modulate the consciousness level. + /// + [ViewVariables(VVAccess.ReadOnly)] + public Dictionary<(EntityUid, string), ConsciousnessMultiplier> Multipliers = new(); + + /// + /// Defines which parts of the consciousness state are necessary for the entity. + /// + [ViewVariables(VVAccess.ReadOnly)] + public Dictionary RequiredConsciousnessParts = new(); + + [ViewVariables(VVAccess.ReadOnly)] + public Entity NerveSystem = default; + + // Forceful control attributes, it's recommended not to use them directly. + [ViewVariables(VVAccess.ReadWrite)] + public bool PassedOut = false; + + [ViewVariables(VVAccess.ReadOnly)] + public TimeSpan PassedOutTime = TimeSpan.Zero; + + [ViewVariables(VVAccess.ReadOnly)] + public TimeSpan ForceConsciousnessTime = TimeSpan.Zero; + + [ViewVariables(VVAccess.ReadOnly)] + public bool ForceDead; + + [ViewVariables(VVAccess.ReadOnly)] + public bool ForceUnconscious; + + // funny + [ViewVariables(VVAccess.ReadOnly)] + public bool ForceConscious; + + [ViewVariables(VVAccess.ReadOnly)] + public bool IsConscious = true; + // Forceful control attributes, it's recommended not to use them directly. +} diff --git a/Content.Shared/Backmen/Surgery/Consciousness/Components/ConsciousnessRequiredComponent.cs b/Content.Shared/Backmen/Surgery/Consciousness/Components/ConsciousnessRequiredComponent.cs new file mode 100644 index 00000000000..d1c38f7de1f --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Consciousness/Components/ConsciousnessRequiredComponent.cs @@ -0,0 +1,19 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Backmen.Surgery.Consciousness.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ConsciousnessRequiredComponent : Component +{ + /// + /// Identifier, basically. Must be unique. + /// + [AutoNetworkedField, DataField] + public string Identifier = "requiredConsciousnessPart"; + + /// + /// Not having this part means death, or only unconsciousness. + /// + [AutoNetworkedField, DataField] + public bool CausesDeath = true; +} diff --git a/Content.Shared/Backmen/Surgery/Consciousness/ConsciousnessSerializable.cs b/Content.Shared/Backmen/Surgery/Consciousness/ConsciousnessSerializable.cs new file mode 100644 index 00000000000..64eaa02b8a0 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Consciousness/ConsciousnessSerializable.cs @@ -0,0 +1,39 @@ +using Content.Shared.Backmen.Surgery.Pain; +using Content.Shared.FixedPoint; +using Robust.Shared.Serialization; + +namespace Content.Shared.Backmen.Surgery.Consciousness; + +[Serializable] +public enum ConsciousnessModType +{ + Generic, // Same for generic + Pain, // Pain is affected only by pain multipliers +} + +// The networking on consciousness is rather silly. +[Serializable, NetSerializable] +public sealed class ConsciousnessComponentState : ComponentState +{ + public FixedPoint2 Threshold; + public FixedPoint2 RawConsciousness; + public FixedPoint2 Multiplier; + public FixedPoint2 Cap; + + public readonly Dictionary<(NetEntity, string), ConsciousnessModifier> Modifiers = new(); + public readonly Dictionary<(NetEntity, string), ConsciousnessMultiplier> Multipliers = new(); + public readonly Dictionary RequiredConsciousnessParts = new(); + + public bool ForceDead; + public bool ForceUnconscious; + public bool IsConscious; +} + +[ByRefEvent] +public record struct ConsciousnessUpdatedEvent(bool IsConscious, FixedPoint2 ConsciousnessDelta); + +[Serializable, DataRecord] +public record struct ConsciousnessModifier(FixedPoint2 Change, ConsciousnessModType Type = ConsciousnessModType.Generic); + +[Serializable, DataRecord] +public record struct ConsciousnessMultiplier(FixedPoint2 Change, ConsciousnessModType Type = ConsciousnessModType.Generic); diff --git a/Content.Shared/Backmen/Surgery/Consciousness/Systems/ConsciousnessSystem.Helpers.cs b/Content.Shared/Backmen/Surgery/Consciousness/Systems/ConsciousnessSystem.Helpers.cs new file mode 100644 index 00000000000..4d49e387b32 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Consciousness/Systems/ConsciousnessSystem.Helpers.cs @@ -0,0 +1,491 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Content.Shared.Backmen.Surgery.Consciousness.Components; +using Content.Shared.Backmen.Surgery.Pain.Components; +using Content.Shared.FixedPoint; +using Content.Shared.Mobs; +using Content.Shared.Mobs.Components; + +namespace Content.Shared.Backmen.Surgery.Consciousness.Systems; + +public partial class ConsciousnessSystem +{ + + #region PublicApi + + /// + /// Gets a nerve system off a body, if has one. + /// + /// Target entity + /// Consciousness component + public Entity? GetNerveSystem(EntityUid body, ConsciousnessComponent? consciousness = null) + { + if (!Resolve(body, ref consciousness)) + return null; + + return consciousness.NerveSystem; + } + + /// + /// Gets a nerve system off a body, if has one. + /// + /// Target entity + /// The nerve system you wanted. + public bool TryGetNerveSystem( + EntityUid body, + [NotNullWhen(true)] out Entity? nerveSys) + { + nerveSys = null; + if (!TryComp(body, out var consciousness)) + return false; + + nerveSys = consciousness.NerveSystem; + return true; + } + + /// + /// Checks to see if an entity should be made unconscious, this is called whenever any consciousness values are changed. + /// Unless you are directly modifying a consciousness component (pls dont) you don't need to call this. + /// + /// Target entity + /// ConsciousnessComponent + /// MobStateComponent + public bool CheckConscious(EntityUid target, ConsciousnessComponent? consciousness = null, MobStateComponent? mobState = null) + { + if (!Resolve(target, ref consciousness, ref mobState, false)) + return false; + + var shouldBeConscious = + consciousness.Consciousness > consciousness.Threshold || consciousness is { ForceUnconscious: false, ForceConscious: true }; + + SetConscious(target, shouldBeConscious, consciousness); + UpdateMobState(target, consciousness, mobState); + + return shouldBeConscious; + } + + /// + /// Force passes out an entity with consciousness component. + /// + /// Target to pass out. + /// Time. + /// of an entity. + public void ForcePassout(EntityUid target, TimeSpan time, ConsciousnessComponent? consciousness = null) + { + if (!Resolve(target, ref consciousness)) + return; + + consciousness.PassedOut = true; + consciousness.PassedOutTime = _timing.CurTime + time; + + CheckConscious(target, consciousness); + } + + /// + /// Forces the entity to stay alive even if on 0 Consciousness, unless induced injuries that cause direct death, like getting your brain blown out + /// Overrides ForcePassout and all other factors, the only requirement is entity being able to live + /// + /// Target to pass out. + /// Time. + /// of an entity. + public void ForceConscious(EntityUid target, TimeSpan time, ConsciousnessComponent? consciousness = null) + { + if (!Resolve(target, ref consciousness)) + return; + + consciousness.ForceConscious = true; + consciousness.ForceConsciousnessTime = _timing.CurTime + time; + + CheckConscious(target, consciousness); + } + + #endregion + + #region Private Implementation + + private void UpdateConsciousnessModifiers(EntityUid uid, ConsciousnessComponent? consciousness) + { + if (!Resolve(uid, ref consciousness)) + return; + + var totalDamage + = consciousness.Modifiers.Aggregate((FixedPoint2) 0, + (current, modifier) => current + modifier.Value.Change * consciousness.Multiplier); + + consciousness.RawConsciousness = consciousness.Cap + totalDamage; + + Dirty(uid, consciousness); + } + + private void UpdateConsciousnessMultipliers(EntityUid uid, ConsciousnessComponent? consciousness) + { + if (!Resolve(uid, ref consciousness)) + return; + + consciousness.Multiplier = consciousness.Multipliers.Aggregate((FixedPoint2) 0, + (current, multiplier) => current + multiplier.Value.Change) / consciousness.Multipliers.Count; + + UpdateConsciousnessModifiers(uid, consciousness); + } + + /// + /// Only used internally. Do not use this, instead use consciousness modifiers/multipliers! + /// + /// target entity + /// should this entity be conscious + /// consciousness component + private void SetConscious(EntityUid target, bool isConscious, ConsciousnessComponent? consciousness = null) + { + if (!Resolve(target, ref consciousness)) + return; + + consciousness.IsConscious = isConscious; + Dirty(target, consciousness); + } + + private void UpdateMobState(EntityUid target, ConsciousnessComponent? consciousness = null, MobStateComponent? mobState = null) + { + if (TerminatingOrDeleted(target) || !Resolve(target, ref consciousness, ref mobState) || _net.IsClient) + return; + + var newMobState = consciousness.IsConscious + ? MobState.Alive + : MobState.Critical; + + if (consciousness.PassedOut) + newMobState = MobState.Critical; + + if (consciousness.ForceUnconscious) + newMobState = MobState.Critical; + + if (consciousness.Consciousness <= 0 && !consciousness.ForceConscious) + newMobState = MobState.Dead; + + if (consciousness.ForceDead) + newMobState = MobState.Dead; + + _mobStateSystem.ChangeMobState(target, newMobState, mobState); + } + + private void CheckRequiredParts(EntityUid bodyId, ConsciousnessComponent consciousness) + { + var alive = true; + var conscious = true; + + foreach (var (/*identifier */_, (entity, forcesDeath, isLost)) in consciousness.RequiredConsciousnessParts) + { + if (entity == null || !isLost) + continue; + + if (forcesDeath) + { + consciousness.ForceDead = true; + Dirty(bodyId, consciousness); + + alive = false; + break; + } + + conscious = false; + } + + if (alive) + { + consciousness.ForceDead = false; + consciousness.ForceUnconscious = !conscious; + + Dirty(bodyId, consciousness); + } + + CheckConscious(bodyId, consciousness); + } + + #endregion + + #region Multipliers and Modifiers + + + /// + /// Get all consciousness multipliers present on an entity. Note: these are copies, do not try to edit the values + /// + /// target entity + /// consciousness component + /// Enumerable of Modifiers + public IEnumerable<((EntityUid, string), ConsciousnessModifier)> GetAllModifiers(EntityUid target, + ConsciousnessComponent? consciousness = null) + { + if (!Resolve(target, ref consciousness)) + yield break; + + foreach (var (owner, modifier) in consciousness.Modifiers) + { + yield return (owner, modifier); + } + } + + /// + /// Get all consciousness multipliers present on an entity. Note: these are copies, do not try to edit the values + /// + /// target entity + /// consciousness component + /// Enumerable of Multipliers + public IEnumerable<((EntityUid, string), ConsciousnessMultiplier)> GetAllMultipliers(EntityUid target, + ConsciousnessComponent? consciousness = null) + { + if (!Resolve(target, ref consciousness)) + yield break; + + foreach (var (owner, multiplier) in consciousness.Multipliers) + { + yield return (owner, multiplier); + } + } + + /// + /// Add a unique consciousness modifier. This value gets added to the raw consciousness value. + /// The owner and type combo must be unique, if you are adding multiple values from a single owner and type, combine them into one modifier + /// + /// Target entity + /// Owner of a modifier + /// Value of the modifier + /// ConsciousnessComponent + /// Localized text name for the modifier (for debug/admins) + /// Modifier type, defaults to generic + /// Successful + public bool AddConsciousnessModifier(EntityUid target, + EntityUid modifierOwner, + FixedPoint2 modifier, + ConsciousnessComponent? consciousness = null, + string identifier = "Unspecified", + ConsciousnessModType type = ConsciousnessModType.Generic) + { + if (!Resolve(target, ref consciousness) || modifier == 0) + return false; + + if (!consciousness.Modifiers.TryAdd((modifierOwner, identifier), new ConsciousnessModifier(modifier, type))) + return false; + + UpdateConsciousnessModifiers(target, consciousness); + + var ev = new ConsciousnessUpdatedEvent(CheckConscious(target, consciousness), modifier * consciousness.Multiplier); + RaiseLocalEvent(target, ref ev, true); + + Dirty(target, consciousness); + + return true; + } + + /// + /// Get a copy of a consciousness modifier. This value gets added to the raw consciousness value. + /// + /// Target entity + /// Owner of a modifier + /// copy of the found modifier, changes are NOT saved + /// Identifier of the requested modifier + /// Consciousness component + /// Successful + public bool TryGetConsciousnessModifier(EntityUid target, + EntityUid modifierOwner, + [NotNullWhen(true)] out ConsciousnessModifier? modifier, + string identifier, + ConsciousnessComponent? consciousness = null) + { + modifier = null; + if (!Resolve(target, ref consciousness) || + !consciousness.Modifiers.TryGetValue((modifierOwner, identifier), out var rawModifier)) + return false; + + modifier = rawModifier; + + return true; + } + + /// + /// Remove a consciousness modifier. This value gets added to the raw consciousness value. + /// + /// Target entity + /// Owner of a modifier + /// Consciousness component + /// Identifier of the modifier to remove + /// Successful + public bool RemoveConsciousnessModifier(EntityUid target, + EntityUid modifierOwner, + string identifier, + ConsciousnessComponent? consciousness = null) + { + if (!Resolve(target, ref consciousness)) + return false; + + if (!consciousness.Modifiers.Remove((modifierOwner, identifier), out var foundModifier)) + return false; + + UpdateConsciousnessModifiers(target, consciousness); + + var ev = new ConsciousnessUpdatedEvent(CheckConscious(target, consciousness), + foundModifier.Change * consciousness.Multiplier); + RaiseLocalEvent(target, ref ev, true); + + Dirty(target, consciousness); + + return true; + } + + /// + /// Edit a consciousness modifier. This value gets set to the raw consciousness value. + /// + /// Target entity + /// Owner of a modifier + /// Value that is being added onto the modifier + /// Consciousness component + /// The string identifier of this modifier. + /// Modifier type, defaults to generic + /// Successful + public bool SetConsciousnessModifier(EntityUid target, + EntityUid modifierOwner, + FixedPoint2 modifierChange, + ConsciousnessComponent? consciousness = null, + string identifier = "Unspecified", + ConsciousnessModType type = ConsciousnessModType.Generic) + { + if (!Resolve(target, ref consciousness)) + return false; + + var newModifier = new ConsciousnessModifier(Change: modifierChange, Type: type); + + consciousness.Modifiers[(modifierOwner, identifier)] = newModifier; + UpdateConsciousnessModifiers(target, consciousness); + + var ev = new ConsciousnessUpdatedEvent(CheckConscious(target, consciousness), + modifierChange * consciousness.Multiplier); + RaiseLocalEvent(target, ref ev, true); + + Dirty(target, consciousness); + + return true; + } + + /// + /// Edit a consciousness modifier. This value gets added to the raw consciousness value. + /// + /// Target entity + /// Owner of a modifier + /// Value that is being added onto the modifier + /// The string identifier of the modifier to change + /// Consciousness component + /// Successful + public bool EditConsciousnessModifier(EntityUid target, + EntityUid modifierOwner, + FixedPoint2 modifierChange, + string identifier, + ConsciousnessComponent? consciousness = null) + { + if (!Resolve(target, ref consciousness) || + !consciousness.Modifiers.TryGetValue((modifierOwner, identifier), out var oldModifier)) + return false; + + var newModifier = oldModifier with {Change = oldModifier.Change + modifierChange}; + + consciousness.Modifiers[(modifierOwner, identifier)] = newModifier; + UpdateConsciousnessModifiers(target, consciousness); + + var ev = new ConsciousnessUpdatedEvent(CheckConscious(target, consciousness), + modifierChange * consciousness.Multiplier); + RaiseLocalEvent(target, ref ev, true); + + Dirty(target, consciousness); + + return true; + } + + /// + /// Add a unique consciousness multiplier. This value gets added onto the multiplier used to calculate consciousness. + /// The owner and type combo must be unique, if you are adding multiple values from a single owner and type, combine them into one multiplier + /// + /// Target entity + /// Owner of a multiplier + /// Value of the multiplier + /// ConsciousnessComponent + /// Localized text name for the multiplier (for debug/admins) + /// Multiplier type, defaults to generic + /// Successful + public bool AddConsciousnessMultiplier(EntityUid target, + EntityUid multiplierOwner, + FixedPoint2 multiplier, + string identifier = "Unspecified", + ConsciousnessComponent? consciousness = null, + ConsciousnessModType type = ConsciousnessModType.Generic) + { + if (!Resolve(target, ref consciousness) || multiplier == 0) + return false; + + if (!consciousness.Multipliers.TryAdd((multiplierOwner, identifier), new ConsciousnessMultiplier(multiplier, type))) + return false; + + UpdateConsciousnessMultipliers(target, consciousness); + + var ev = new ConsciousnessUpdatedEvent(CheckConscious(target, consciousness), multiplier * consciousness.RawConsciousness); + RaiseLocalEvent(target, ref ev, true); + + Dirty(target, consciousness); + + return true; + } + + /// + /// Get a copy of a consciousness multiplier. This value gets added onto the multiplier used to calculate consciousness. + /// + /// Target entity + /// Owner of a multiplier + /// String identifier of the multiplier to get + /// Copy of the found multiplier, changes are NOT saved + /// Consciousness component + /// Successful + public bool TryGetConsciousnessMultiplier(EntityUid target, + EntityUid multiplierOwner, + string identifier, + out ConsciousnessMultiplier? multiplier, + ConsciousnessComponent? consciousness = null) + { + multiplier = null; + if (!Resolve(target, ref consciousness) || + !consciousness.Multipliers.TryGetValue((multiplierOwner, identifier), out var rawMultiplier)) + return false; + + multiplier = rawMultiplier; + + return true; + } + + /// + /// Remove a consciousness multiplier. This value gets added onto the multiplier used to calculate consciousness. + /// + /// Target entity + /// Owner of a multiplier + /// String identifier of the multiplier to remove + /// Consciousness component + /// Successful + public bool RemoveConsciousnessMultiplier(EntityUid target, + EntityUid multiplierOwner, + string identifier, + ConsciousnessComponent? consciousness = null) + { + if (!Resolve(target, ref consciousness)) + return false; + + if (!consciousness.Multipliers.Remove((multiplierOwner, identifier), out var foundMultiplier)) + return false; + + UpdateConsciousnessMultipliers(target, consciousness); + + var ev = new ConsciousnessUpdatedEvent(CheckConscious(target, consciousness), + foundMultiplier.Change * consciousness.RawConsciousness); + RaiseLocalEvent(target, ref ev, true); + + Dirty(target, consciousness); + UpdateConsciousnessModifiers(target, consciousness); + + return true; + } + + #endregion +} diff --git a/Content.Shared/Backmen/Surgery/Consciousness/Systems/ConsciousnessSystem.Networking.cs b/Content.Shared/Backmen/Surgery/Consciousness/Systems/ConsciousnessSystem.Networking.cs new file mode 100644 index 00000000000..d618532f678 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Consciousness/Systems/ConsciousnessSystem.Networking.cs @@ -0,0 +1,78 @@ +using Content.Shared.Backmen.Surgery.Consciousness.Components; +using Robust.Shared.GameStates; + +namespace Content.Shared.Backmen.Surgery.Consciousness.Systems; + +public partial class ConsciousnessSystem +{ + private void InitNet() + { + SubscribeLocalEvent(OnComponentGet); + SubscribeLocalEvent(OnComponentHandleState); + } + + private void OnComponentHandleState(EntityUid uid, ConsciousnessComponent component, ref ComponentHandleState args) + { + if (args.Current is not ConsciousnessComponentState state) + return; + + component.Threshold = state.Threshold; + component.RawConsciousness = state.RawConsciousness; + component.Multiplier = state.Multiplier; + component.Cap = state.Cap; + component.ForceDead = state.ForceDead; + component.ForceUnconscious = state.ForceUnconscious; + component.IsConscious = state.IsConscious; + component.Modifiers.Clear(); + component.Multipliers.Clear(); + component.RequiredConsciousnessParts.Clear(); + + foreach (var ((modEntity, modType), modifier) in state.Modifiers) + { + component.Modifiers.Add((GetEntity(modEntity), modType), modifier); + } + + foreach (var ((multiplierEntity, multiplierType), modifier) in state.Multipliers) + { + component.Multipliers.Add((GetEntity(multiplierEntity), multiplierType), modifier); + } + + foreach (var (id, (entity, causesDeath, isLost)) in state.RequiredConsciousnessParts) + { + component.RequiredConsciousnessParts.Add(id, (GetEntity(entity), causesDeath, isLost)); + } + } + + private void OnComponentGet(EntityUid uid, ConsciousnessComponent comp, ref ComponentGetState args) + { + var state = new ConsciousnessComponentState(); + + state.Threshold = comp.Threshold; + state.RawConsciousness = comp.RawConsciousness; + state.Multiplier = comp.Multiplier; + state.Cap = comp.Cap; + state.ForceDead = comp.ForceDead; + state.ForceUnconscious = comp.ForceUnconscious; + state.IsConscious = comp.IsConscious; + + foreach (var ((modEntity, modType), modifier) in comp.Modifiers) + { + if (!TerminatingOrDeleted(modEntity)) + state.Modifiers.Add((GetNetEntity(modEntity), modType), modifier); + } + + foreach (var ((multiplierEntity, multiplierType), modifier) in comp.Multipliers) + { + if (!TerminatingOrDeleted(multiplierEntity)) + state.Multipliers.Add((GetNetEntity(multiplierEntity), multiplierType), modifier); + } + + foreach (var (id, (entity, causesDeath, isLost)) in comp.RequiredConsciousnessParts) + { + if (!TerminatingOrDeleted(entity)) + state.RequiredConsciousnessParts.Add(id, (GetNetEntity(entity), causesDeath, isLost)); + } + + args.State = state; + } +} diff --git a/Content.Shared/Backmen/Surgery/Consciousness/Systems/ConsciousnessSystem.Process.cs b/Content.Shared/Backmen/Surgery/Consciousness/Systems/ConsciousnessSystem.Process.cs new file mode 100644 index 00000000000..8ba7ea852ff --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Consciousness/Systems/ConsciousnessSystem.Process.cs @@ -0,0 +1,199 @@ +using System.Linq; +using Content.Shared.Backmen.Surgery.Body.Events; +using Content.Shared.Backmen.Surgery.Consciousness.Components; +using Content.Shared.Backmen.Surgery.Pain.Components; +using Content.Shared.Body.Events; +using Content.Shared.Body.Systems; +using Content.Shared.Mobs; +using Content.Shared.Rejuvenate; + +namespace Content.Shared.Backmen.Surgery.Consciousness.Systems; + +public partial class ConsciousnessSystem +{ + private void InitProcess() + { + SubscribeLocalEvent(OnMobStateChanged); + + // To prevent people immediately falling down as rejuvenated + SubscribeLocalEvent(OnRejuvenate, after: [typeof(SharedBodySystem)]); + + SubscribeLocalEvent(OnBodyPartAdded); + SubscribeLocalEvent(OnBodyPartRemoved); + + SubscribeLocalEvent(OnOrganAdded); + SubscribeLocalEvent(OnOrganRemoved); + + SubscribeLocalEvent(OnConsciousnessMapInit); + } + + private const string NerveSystemIdentifier = "nerveSystem"; + + private void UpdatePassedOut(float frameTime) + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var ent, out var consciousness)) + { + if (consciousness.ForceDead) + continue; + + if (consciousness.PassedOutTime < _timing.CurTime) + consciousness.PassedOut = false; + + if (consciousness.ForceConsciousnessTime < _timing.CurTime) + consciousness.ForceConscious = false; + + if (!consciousness.PassedOut || consciousness.ForceConscious) + CheckConscious(ent, consciousness); + } + } + + private void OnMobStateChanged(EntityUid uid, ConsciousnessComponent component, MobStateChangedEvent args) + { + if (args.NewMobState != MobState.Dead) + return; + + AddConsciousnessModifier(uid, uid, -component.Cap, component, "DeathThreshold", ConsciousnessModType.Pain); + // To prevent people from suddenly resurrecting while being dead. whoops + + foreach (var multiplier in + component.Multipliers.Where(multiplier => multiplier.Value.Type != ConsciousnessModType.Pain)) + { + RemoveConsciousnessMultiplier(uid, multiplier.Key.Item1, multiplier.Key.Item2, component); + } + + foreach (var multiplier in + component.Modifiers.Where(multiplier => multiplier.Value.Type != ConsciousnessModType.Pain)) + { + RemoveConsciousnessModifier(uid, multiplier.Key.Item1, multiplier.Key.Item2, component); + } + } + + private void OnRejuvenate(EntityUid uid, ConsciousnessComponent component, RejuvenateEvent args) + { + foreach (var painModifier in component.NerveSystem.Comp.Modifiers) + { + _pain.TryRemovePainModifier(component.NerveSystem.Owner, painModifier.Key.Item1, painModifier.Key.Item2, component.NerveSystem.Comp); + } + + foreach (var painMultiplier in component.NerveSystem.Comp.Multipliers) + { + _pain.TryRemovePainMultiplier(component.NerveSystem.Owner, painMultiplier.Key, component.NerveSystem.Comp); + } + + + foreach (var multiplier in + component.Multipliers.Where(multiplier => multiplier.Value.Type == ConsciousnessModType.Pain)) + { + RemoveConsciousnessMultiplier(uid, multiplier.Key.Item1, multiplier.Key.Item2, component); + } + + foreach (var modifier in + component.Modifiers.Where(modifier => modifier.Value.Type == ConsciousnessModType.Pain)) + { + RemoveConsciousnessModifier(uid, modifier.Key.Item1, modifier.Key.Item2, component); + } + + foreach (var nerve in component.NerveSystem.Comp.Nerves) + { + foreach (var painFeelsModifier in nerve.Value.PainFeelingModifiers) + { + _pain.TryRemovePainFeelsModifier(painFeelsModifier.Key.Item1, painFeelsModifier.Key.Item2, nerve.Key, nerve.Value); + } + } + + CheckRequiredParts(uid, component); + ForceConscious(uid, TimeSpan.FromSeconds(1f), component); + } + + private void OnConsciousnessMapInit(EntityUid uid, ConsciousnessComponent consciousness, MapInitEvent args) + { + if (consciousness.RawConsciousness < 0) + { + consciousness.RawConsciousness = consciousness.Cap; + Dirty(uid, consciousness); + } + + CheckConscious(uid, consciousness); + } + + private void OnBodyPartAdded(EntityUid uid, ConsciousnessRequiredComponent component, ref BodyPartAddedEvent args) + { + if (_net.IsClient) + return; + + if (args.Part.Comp.Body == null || + !TryComp(args.Part.Comp.Body, out var consciousness)) + return; + + if (consciousness.RequiredConsciousnessParts.TryGetValue(component.Identifier, out var value) && value.Item1 != null && value.Item1 != uid) + { + _sawmill.Warning($"ConsciousnessRequirementPart with duplicate Identifier {component.Identifier}:{uid} added to a body:" + + $" {args.Part.Comp.Body} this will result in unexpected behaviour!"); + } + + consciousness.RequiredConsciousnessParts[component.Identifier] = (uid, component.CausesDeath, false); + + CheckRequiredParts(args.Part.Comp.Body.Value, consciousness); + } + + private void OnBodyPartRemoved(EntityUid uid, ConsciousnessRequiredComponent component, ref BodyPartRemovedEvent args) + { + if (_net.IsClient) + return; + + if (args.Part.Comp.Body == null || !TryComp(args.Part.Comp.Body.Value, out var consciousness)) + return; + + if (!consciousness.RequiredConsciousnessParts.TryGetValue(component.Identifier, out var value)) + { + _sawmill.Warning($"ConsciousnessRequirementPart with identifier {component.Identifier}:{uid} not found on body:{args.Part.Comp.Body}"); + return; + } + + consciousness.RequiredConsciousnessParts[component.Identifier] = (uid, value.Item2, true); + + CheckRequiredParts(args.Part.Comp.Body.Value, consciousness); + } + + private void OnOrganAdded(EntityUid uid, ConsciousnessRequiredComponent component, ref OrganAddedToBodyEvent args) + { + if (_net.IsClient) + return; + + if (!TryComp(args.Body, out var consciousness)) + return; + + if (consciousness.RequiredConsciousnessParts.TryGetValue(component.Identifier, out var value) && value.Item1 != null && value.Item1 != uid) + { + _sawmill.Warning($"ConsciousnessRequirementPart with duplicate Identifier {component.Identifier}:{uid} added to a body:" + + $" {args.Body} this will result in unexpected behaviour! Old {component.Identifier} wielder: {value.Item1}"); + } + + consciousness.RequiredConsciousnessParts[component.Identifier] = (uid, component.CausesDeath, false); + + if (component.Identifier == NerveSystemIdentifier) + consciousness.NerveSystem = (uid, Comp(uid)); + + CheckRequiredParts(args.Body, consciousness); + } + + private void OnOrganRemoved(EntityUid uid, ConsciousnessRequiredComponent component, ref OrganRemovedFromBodyEvent args) + { + if (_net.IsClient) + return; + + if (!TryComp(args.OldBody, out var consciousness)) + return; + + if (!consciousness.RequiredConsciousnessParts.TryGetValue(component.Identifier, out var value)) + { + _sawmill.Warning($"ConsciousnessRequirementPart with identifier {component.Identifier}:{uid} not found on body:{args.OldBody}"); + return; + } + + consciousness.RequiredConsciousnessParts[component.Identifier] = (uid, value.Item2, true); + + CheckRequiredParts(args.OldBody, consciousness); + } +} diff --git a/Content.Shared/Backmen/Surgery/Consciousness/Systems/ConsciousnessSystem.cs b/Content.Shared/Backmen/Surgery/Consciousness/Systems/ConsciousnessSystem.cs new file mode 100644 index 00000000000..79489a5d6a4 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Consciousness/Systems/ConsciousnessSystem.cs @@ -0,0 +1,35 @@ +using Content.Shared.Backmen.Surgery.Pain.Systems; +using Content.Shared.Mobs.Systems; +using Robust.Shared.Network; +using Robust.Shared.Timing; + +namespace Content.Shared.Backmen.Surgery.Consciousness.Systems; + +[Virtual] +public sealed partial class ConsciousnessSystem : EntitySystem +{ + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + [Dependency] private readonly MobStateSystem _mobStateSystem = default!; + [Dependency] private readonly PainSystem _pain = default!; + + private ISawmill _sawmill = default!; + + public override void Initialize() + { + base.Initialize(); + + _sawmill = Logger.GetSawmill("consciousness"); + + InitProcess(); + InitNet(); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + UpdatePassedOut(frameTime); + } +} diff --git a/Content.Shared/Backmen/Surgery/Pain/Components/NerveComponent.cs b/Content.Shared/Backmen/Surgery/Pain/Components/NerveComponent.cs new file mode 100644 index 00000000000..31db78b36b5 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Pain/Components/NerveComponent.cs @@ -0,0 +1,26 @@ +using System.Linq; +using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; + +namespace Content.Shared.Backmen.Surgery.Pain.Components; + +[RegisterComponent, NetworkedComponent] +public sealed partial class NerveComponent : Component +{ + // Yuh-uh + [DataField, ViewVariables(VVAccess.ReadOnly)] + public FixedPoint2 PainMultiplier = 1.0f; + + // How feel able the pain is; The value can be decreased by pain suppressants and Nerve Damage. + [ViewVariables(VVAccess.ReadOnly)] + public FixedPoint2 PainFeels => 1f + PainFeelingModifiers.Values.Sum(modifier => (float) modifier.Change); + + [ViewVariables(VVAccess.ReadOnly)] + public Dictionary<(EntityUid, string), PainFeelingModifier> PainFeelingModifiers = new(); + + /// + /// Nerve system, to which this nerve is parented. + /// + [ViewVariables(VVAccess.ReadOnly)] + public EntityUid ParentedNerveSystem; +} diff --git a/Content.Shared/Backmen/Surgery/Pain/Components/NerveSystemComponent.cs b/Content.Shared/Backmen/Surgery/Pain/Components/NerveSystemComponent.cs new file mode 100644 index 00000000000..ad581651f29 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Pain/Components/NerveSystemComponent.cs @@ -0,0 +1,183 @@ +using Content.Shared.FixedPoint; +using Content.Shared.Humanoid; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Components; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Backmen.Surgery.Pain.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class NerveSystemComponent : Component +{ + /// + /// Pain. + /// + [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + public FixedPoint2 Pain = 0f; + + /// + /// How much Pain can this nerve system hold. + /// + [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadOnly)] + public FixedPoint2 PainCap = 200f; + + // Don't change, OR I will break your knees, filled up upon initialization. + public Dictionary Nerves = new(); + + // Don't add manually!! Use built-in functions. + public Dictionary Multipliers = new(); + public Dictionary<(EntityUid, string), PainModifier> Modifiers = new(); + + public Dictionary PlayedPainSounds = new(); + public Dictionary PainSoundsToPlay = new(); + + [DataField("lastThreshold"), ViewVariables(VVAccess.ReadOnly)] + public FixedPoint2 LastPainThreshold = 0; + + [ViewVariables(VVAccess.ReadOnly)] + public PainThresholdTypes LastThresholdType = PainThresholdTypes.None; + + [DataField("thresholdUpdate")] + public TimeSpan ThresholdUpdateTime = TimeSpan.FromSeconds(2f); + + [DataField("accumulated", customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan UpdateTime = TimeSpan.Zero; + + [DataField("painShockStun")] + public TimeSpan PainShockStunTime = TimeSpan.FromSeconds(11f); + + [DataField("passoutTime")] + public TimeSpan ForcePassoutTime = TimeSpan.FromSeconds(7f); + + [DataField] + public SoundSpecifier PainRattles = new SoundCollectionSpecifier("PainRattles"); + + [DataField] + public Dictionary PainScreams = new() + { + { + Sex.Male, new SoundCollectionSpecifier("PainScreamsShortMale") + { + Params = AudioParams.Default.WithVariation(0.04f), + } + }, + { + Sex.Female, new SoundCollectionSpecifier("PainScreamsShortFemale") + { + Params = AudioParams.Default.WithVariation(0.04f), + } + }, + { + Sex.Unsexed, new SoundCollectionSpecifier("PainScreamsShortMale") // yeah + { + Params = AudioParams.Default.WithVariation(0.2f), + } + }, + }; + + [DataField] + public Dictionary AgonyScreams = new() + { + { + Sex.Male, new SoundCollectionSpecifier("AgonyScreamsMale") + { + Params = AudioParams.Default.WithVariation(0.04f), + } + }, + { + Sex.Female, new SoundCollectionSpecifier("AgonyScreamsFemale") + { + Params = AudioParams.Default.WithVariation(0.04f), + } + }, + { + Sex.Unsexed, new SoundCollectionSpecifier("AgonyScreamsMale") // yeah + { + Params = AudioParams.Default.WithVariation(0.2f), + } + }, + }; + + [DataField] + public Dictionary PainShockScreams = new() + { + { + Sex.Male, new SoundCollectionSpecifier("PainShockScreamsMale") + { + Params = AudioParams.Default.WithVariation(0.05f), + } + }, + { + Sex.Female, new SoundCollectionSpecifier("PainShockScreamsFemale") + { + Params = AudioParams.Default.WithVariation(0.05f), + } + }, + { + Sex.Unsexed, new SoundCollectionSpecifier("PainShockScreamsMale") // yeah + { + Params = AudioParams.Default.WithVariation(0.2f), + } + }, + }; + + [DataField] + public Dictionary CritWhimpers = new() + { + { + Sex.Male, new SoundCollectionSpecifier("CritWhimpersMale") + { + Params = AudioParams.Default, + } + }, + { + Sex.Female, new SoundCollectionSpecifier("CritWhimpersFemale") + { + Params = AudioParams.Default, + } + }, + { + Sex.Unsexed, new SoundCollectionSpecifier("CritWhimpersMale") // yeah + { + Params = AudioParams.Default, + } + }, + }; + + [DataField] + public Dictionary PainShockWhimpers = new() + { + { + Sex.Male, new SoundCollectionSpecifier("PainShockWhimpersMale") + { + Params = AudioParams.Default, + } + }, + { + Sex.Female, new SoundCollectionSpecifier("PainShockWhimpersFemale") + { + Params = AudioParams.Default, + } + }, + { + Sex.Unsexed, new SoundCollectionSpecifier("PainShockWhimpersMale") // yeah + { + Params = AudioParams.Default, + } + }, + }; + + [DataField("reflexThresholds"), ViewVariables(VVAccess.ReadOnly)] + public Dictionary PainThresholds = new() + { + { PainThresholdTypes.PainFlinch, 5 }, + { PainThresholdTypes.Agony, 18 }, + // Just having 'PainFlinch' is lame, people scream for a few seconds before passing out / getting pain shocked, so I added agony. + // A lot of screams (individual pain screams poll), for the funnies. + { PainThresholdTypes.PainShock, 36 }, + // usually appears after an explosion. or some ultra big damage output thing, you might survive, and most importantly, you will fall down in pain. + // :troll: + { PainThresholdTypes.PainPassout, 60 }, + }; +} diff --git a/Content.Shared/Backmen/Surgery/Pain/Components/PainInflicterComponent.cs b/Content.Shared/Backmen/Surgery/Pain/Components/PainInflicterComponent.cs new file mode 100644 index 00000000000..90fb83595f7 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Pain/Components/PainInflicterComponent.cs @@ -0,0 +1,21 @@ +using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; + +namespace Content.Shared.Backmen.Surgery.Pain.Components; + +/// +/// Used to mark wounds, that afflict pain; It's calculated automatically from severity and the multiplier +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class PainInflicterComponent : Component +{ + /// + /// Pain this one exact wound inflicts + /// + [DataField, ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] + public FixedPoint2 Pain; + + // Some wounds hurt harder. + [DataField("multiplier"), ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] + public FixedPoint2 PainMultiplier = 1; +} diff --git a/Content.Shared/Backmen/Surgery/Pain/PainSerializable.cs b/Content.Shared/Backmen/Surgery/Pain/PainSerializable.cs new file mode 100644 index 00000000000..bf3db580de0 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Pain/PainSerializable.cs @@ -0,0 +1,49 @@ +using Content.Shared.Backmen.Surgery.Pain.Components; +using Content.Shared.FixedPoint; +using Robust.Shared.Serialization; + +namespace Content.Shared.Backmen.Surgery.Pain; + +[Serializable, NetSerializable] +public enum PainThresholdTypes +{ + None, + PainFlinch, + Agony, + PainShock, + PainPassout, +} + +[Serializable, NetSerializable] +public sealed class NerveComponentState : ComponentState +{ + public FixedPoint2 PainMultiplier; + + public Dictionary<(NetEntity, string), PainFeelingModifier> PainFeelingModifiers = new(); + + public NetEntity ParentedNerveSystem; +} + +[Serializable, DataRecord] +public record struct PainMultiplier(FixedPoint2 Change, string Identifier = "Unspecified", TimeSpan? Time = null); + +[Serializable, DataRecord] +public record struct PainFeelingModifier(FixedPoint2 Change, TimeSpan? Time = null); + +[Serializable, DataRecord] +public record struct PainModifier(FixedPoint2 Change, string Identifier = "Unspecified", TimeSpan? Time = null); // Easier to manage pain with modifiers. + +[ByRefEvent] +public record struct PainThresholdTriggered(EntityUid NerveSystem, NerveSystemComponent Component, PainThresholdTypes ThresholdType, FixedPoint2 PainInput, bool Cancelled = false); + +[ByRefEvent] +public record struct PainThresholdEffected(EntityUid NerveSystem, NerveSystemComponent Component, PainThresholdTypes ThresholdType, FixedPoint2 PainInput); + +[ByRefEvent] +public record struct PainModifierAddedEvent(EntityUid NerveSystem, EntityUid NerveUid, FixedPoint2 AddedPain); + +[ByRefEvent] +public record struct PainModifierRemovedEvent(EntityUid NerveSystem, EntityUid NerveUid, FixedPoint2 CurrentPain); + +[ByRefEvent] +public record struct PainModifierChangedEvent(EntityUid NerveSystem, EntityUid NerveUid, FixedPoint2 CurrentPain); diff --git a/Content.Shared/Backmen/Surgery/Pain/Systems/PainSystem.Affliction.cs b/Content.Shared/Backmen/Surgery/Pain/Systems/PainSystem.Affliction.cs new file mode 100644 index 00000000000..607e098932b --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Pain/Systems/PainSystem.Affliction.cs @@ -0,0 +1,85 @@ +using Content.Shared.Backmen.Surgery.Pain.Components; +using Content.Shared.Backmen.Surgery.Wounds; +using Content.Shared.Body.Components; +using Content.Shared.Body.Part; +using Content.Shared.FixedPoint; + +namespace Content.Shared.Backmen.Surgery.Pain.Systems; + +public partial class PainSystem +{ + private void InitAffliction() + { + // Pain management hooks. + SubscribeLocalEvent(OnPainRemoved); + SubscribeLocalEvent(OnPainChanged); + } + + private const string PainModifierIdentifier = "Pain"; + + #region Event Handling + + private void OnPainChanged(EntityUid uid, PainInflicterComponent pain, WoundSeverityPointChangedEvent args) + { + if (!TryComp(args.Component.HoldingWoundable, out var bodyPart)) + return; + + if (bodyPart.Body == null) + return; + + if (!_consciousness.TryGetNerveSystem(bodyPart.Body.Value, out var nerveSys)) + return; + + // bro how + pain.Pain = FixedPoint2.Clamp(args.NewSeverity * pain.PainMultiplier, 0, 100); + var allPain = (FixedPoint2) 0; + + foreach (var (woundId, _) in _wound.GetWoundableWounds(args.Component.HoldingWoundable)) + { + if (!TryComp(woundId, out var painInflicter)) + continue; + + allPain += painInflicter.Pain; + } + + if (!TryAddPainModifier(nerveSys.Value, args.Component.HoldingWoundable, PainModifierIdentifier, allPain)) + TryChangePainModifier(nerveSys.Value, args.Component.HoldingWoundable, PainModifierIdentifier, allPain); + } + + private void OnPainRemoved(EntityUid uid, PainInflicterComponent pain, WoundRemovedEvent args) + { + if (!TryComp(args.Component.HoldingWoundable, out var bodyPart)) + return; + + if (bodyPart.Body == null) + return; + + var rootPart = Comp(bodyPart.Body.Value).RootContainer.ContainedEntity; + if (!rootPart.HasValue) + return; + + if (!_consciousness.TryGetNerveSystem(bodyPart.Body.Value, out var nerveSys)) + return; + + // bro how + var allPain = (FixedPoint2) 0; + foreach (var (woundId, _) in _wound.GetWoundableWounds(args.Component.HoldingWoundable)) + { + if (!TryComp(woundId, out var painInflicter)) + continue; + + allPain += painInflicter.Pain; + } + + if (allPain <= 0) + { + TryRemovePainModifier(nerveSys.Value, args.Component.HoldingWoundable, PainModifierIdentifier); + } + else + { + TryChangePainModifier(nerveSys.Value, args.Component.HoldingWoundable, PainModifierIdentifier, allPain); + } + } + + #endregion +} diff --git a/Content.Shared/Backmen/Surgery/Pain/Systems/PainSystem.Damage.cs b/Content.Shared/Backmen/Surgery/Pain/Systems/PainSystem.Damage.cs new file mode 100644 index 00000000000..90b345009d2 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Pain/Systems/PainSystem.Damage.cs @@ -0,0 +1,568 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Content.Shared.Backmen.Surgery.Consciousness; +using Content.Shared.Backmen.Surgery.Pain.Components; +using Content.Shared.Body.Organ; +using Content.Shared.FixedPoint; +using Content.Shared.Humanoid; +using Content.Shared.Popups; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Components; +using Robust.Shared.CPUJob.JobQueues; +using Robust.Shared.CPUJob.JobQueues.Queues; +using Robust.Shared.Timing; + +namespace Content.Shared.Backmen.Surgery.Pain.Systems; + +public partial class PainSystem +{ + private const double PainJobTime = 0.005; + private readonly JobQueue _painJobQueue = new(PainJobTime); + + #region Public API + + /// + /// Changes a pain value for a specific nerve, if there's any. Adds MORE PAIN to it basically. + /// + /// Uid of the nerveSystem component owner. + /// Nerve uid. + /// Identifier of the said modifier. + /// How many pain to set. + /// NerveSystemComponent. + /// How long will the modifier last? + /// Returns true, if PAIN QUOTA WAS COLLECTED. + public bool TryChangePainModifier(EntityUid uid, EntityUid nerveUid, string identifier, FixedPoint2 change, NerveSystemComponent? nerveSys = null, TimeSpan? time = null) + { + if (!Resolve(uid, ref nerveSys, false)) + return false; + + if (!nerveSys.Modifiers.TryGetValue((nerveUid, identifier), out var modifier)) + return false; + + var modifierToSet = + modifier with {Change = change, Time = time ?? modifier.Time}; + nerveSys.Modifiers[(nerveUid, identifier)] = modifierToSet; + + var ev = new PainModifierChangedEvent(uid, nerveUid, modifier.Change); + RaiseLocalEvent(uid, ref ev); + + UpdateNerveSystemPain(uid, nerveSys); + Dirty(uid, nerveSys); + + return true; + } + + /// + /// Gets a copy of pain modifier. + /// + /// Uid of the nerveSystem component owner. + /// Nerve uid, used to seek for modifier. + /// Identifier of the said modifier. + /// Modifier copy acquired. + /// NerveSystemComponent. + /// Returns true, if the modifier was acquired. + public bool TryGetPainModifier( + EntityUid uid, + EntityUid nerveUid, + string identifier, + [NotNullWhen(true)] out PainModifier? modifier, + NerveSystemComponent? nerveSys = null) + { + modifier = null; + if (!Resolve(uid, ref nerveSys, false)) + return false; + + if (!nerveSys.Modifiers.TryGetValue((nerveUid, identifier), out var data)) + return false; + + modifier = data; + return true; + } + + /// + /// Adds pain to needed nerveSystem, uses modifiers. + /// + /// Uid of the nerveSystem owner. + /// Uid of the nerve, to which damage was applied. + /// Identifier of the said modifier. + /// Number of pain to add. + /// NerveSystem component. + /// Timespan of the modifier's existence + /// Returns true, if the PAIN WAS APPLIED. + public bool TryAddPainModifier(EntityUid uid, EntityUid nerveUid, string identifier, FixedPoint2 change, NerveSystemComponent? nerveSys = null, TimeSpan? time = null) + { + if (!Resolve(uid, ref nerveSys, false)) + return false; + + var modifier = new PainModifier(change, MetaData(nerveUid).EntityPrototype!.ID, _timing.CurTime + time); + if (!nerveSys.Modifiers.TryAdd((nerveUid, identifier), modifier)) + return false; + + var ev = new PainModifierAddedEvent(uid, nerveUid, change); + RaiseLocalEvent(uid, ref ev); + + UpdateNerveSystemPain(uid, nerveSys); + Dirty(uid, nerveSys); + + return true; + } + + /// + /// Adds a pain feeling modifier to the needed nerve, uses modifiers. + /// + /// Uid of the owner of this effect. + /// The string identifier of the modifier to add + /// Uid of the nerve, to which damage is being applied. + /// Number of pain feeling to add / subtract. + /// The nerve component of the nerve entity. + /// The TimeSpan of the effect; When runs out, the effect will be removed. + /// Returns true, if the pain feeling modifier was added. + public bool TryAddPainFeelsModifier(EntityUid effectOwner, string identifier, EntityUid nerveUid, FixedPoint2 change, NerveComponent? nerve = null, TimeSpan? time = null) + { + if (!Resolve(nerveUid, ref nerve, false)) + return false; + + var modifier = new PainFeelingModifier(change, _timing.CurTime + time); + if (!nerve.PainFeelingModifiers.TryAdd((effectOwner, identifier), modifier)) + return false; + + Dirty(nerveUid, nerve); + return true; + } + + /// + /// Tries to get a pain feeling modifier. + /// + /// Uid of the nerve from which you get the modifier. + /// Uid of the effect owner. + /// String identifier of the modifier. + /// The modifier you wanted. + /// The nerve component of the nerve entity. + /// Returns true, if the pain feeling modifier was added. + public bool TryGetPainFeelsModifier(EntityUid nerveEnt, + EntityUid effectOwner, + string identifier, + [NotNullWhen(true)] out PainFeelingModifier? modifier, + NerveComponent? nerve = null) + { + modifier = null; + if (!Resolve(nerveEnt, ref nerve, false)) + return false; + + if (!nerve.PainFeelingModifiers.TryGetValue((effectOwner, identifier), out var data)) + return false; + + modifier = data; + return true; + } + + /// + /// Changes a pain feeling modifier of a needed nerve, uses modifiers. + /// + /// Uid of the owner of this effect. + /// The string identifier of this.. yeah + /// Uid of the nerve, to which damage is being applied. + /// Number of pain feeling to add / subtract. + /// The nerve component of the nerve entity. + /// The TimeSpan of the effect; When runs out, the effect will be removed. + /// Returns true, if the pain feeling modifier was changed. + public bool TryChangePainFeelsModifier( + EntityUid effectOwner, + string identifier, + EntityUid nerveUid, + FixedPoint2 change, + NerveComponent? nerve = null, + TimeSpan? time = null) + { + if (!Resolve(nerveUid, ref nerve, false)) + return false; + + if (!nerve.PainFeelingModifiers.TryGetValue((effectOwner, identifier), out var modifier)) + return false; + + var modifierToSet = + new PainFeelingModifier(Change: change, Time: time ?? modifier.Time); + nerve.PainFeelingModifiers[(nerveUid, identifier)] = modifierToSet; + + Dirty(nerveUid, nerve); + return true; + } + + /// + /// Removes a pain feeling modifier of a needed nerve, uses modifiers. + /// + /// Uid of the owner of this effect. + /// The identifier of the said modifier. + /// Uid of the nerve, to which damage is being applied. + /// The nerve component of the nerve entity. + /// Returns true, if the pain feeling modifier was removed. + public bool TryRemovePainFeelsModifier(EntityUid effectOwner, string identifier, EntityUid nerveUid, NerveComponent? nerve = null) + { + if (!Resolve(nerveUid, ref nerve, false)) + return false; + + Dirty(nerveUid, nerve); + return nerve.PainFeelingModifiers.Remove((effectOwner, identifier)); + } + + /// + /// Removes a specified pain modifier. + /// + /// NerveSystemComponent owner. + /// Nerve Uid, to which pain is applied. + /// Identifier of the said pain modifier. + /// NerveSystemComponent. + /// Returns true, if the pain modifier was removed. + public bool TryRemovePainModifier(EntityUid uid, EntityUid nerveUid, string identifier, NerveSystemComponent? nerveSys = null) + { + if (!Resolve(uid, ref nerveSys, false) || _net.IsClient) + return false; + + if (!nerveSys.Modifiers.Remove((nerveUid, identifier))) + return false; + + var ev = new PainModifierRemovedEvent(uid, nerveUid, nerveSys.Pain); + RaiseLocalEvent(uid, ref ev); + + UpdateNerveSystemPain(uid, nerveSys); + Dirty(uid, nerveSys); + + return true; + } + + /// + /// Adds pain multiplier to nerveSystem. + /// + /// NerveSystem owner's uid. + /// ID for the multiplier. + /// Number to multiply. + /// NerveSystemComponent. + /// A timer for this multiplier; Upon it's end, the multiplier gets removed. + /// Returns true, if the multiplier was applied. + public bool TryAddPainMultiplier(EntityUid uid, + string identifier, + FixedPoint2 change, + NerveSystemComponent? nerveSys = null, + TimeSpan? time = null) + { + if (!Resolve(uid, ref nerveSys, false) || _net.IsClient) + return false; + + var modifier = new PainMultiplier(change, identifier, _timing.CurTime + time); + if (!nerveSys.Multipliers.TryAdd(identifier, modifier)) + return false; + + UpdateNerveSystemPain(uid, nerveSys); + + Dirty(uid, nerveSys); + return true; + } + + + /// + /// Changes an existing pain multiplier's data, on a specified nerve system. + /// + /// NerveSystem owner's uid. + /// ID for the multiplier. + /// Number to multiply. + /// NerveSystemComponent. + /// Returns true, if the multiplier was changed. + public bool TryChangePainMultiplier(EntityUid uid, string identifier, FixedPoint2 change, NerveSystemComponent? nerveSys = null) + { + if (!Resolve(uid, ref nerveSys, false) || _net.IsClient) + return false; + + if (!nerveSys.Multipliers.TryGetValue(identifier, out var multiplier)) + return false; + + var multiplierToSet = + multiplier with {Change = change}; + nerveSys.Multipliers[identifier] = multiplierToSet; + + UpdateNerveSystemPain(uid, nerveSys); + Dirty(uid, nerveSys); + + return true; + } + + /// + /// Removes a pain multiplier. + /// + /// NerveSystem owner's uid. + /// ID to seek for the multiplier, what must be removed. + /// NerveSystemComponent. + /// Returns true, if the multiplier was removed. + public bool TryRemovePainMultiplier(EntityUid uid, string identifier, NerveSystemComponent? nerveSys = null) + { + if (!Resolve(uid, ref nerveSys, false) || _net.IsClient) + return false; + + if (!nerveSys.Multipliers.Remove(identifier)) + return false; + + UpdateNerveSystemPain(uid, nerveSys); + Dirty(uid, nerveSys); + + return true; + } + + public Entity? PlayPainSound(EntityUid body, NerveSystemComponent nerveSys, SoundSpecifier specifier, AudioParams? audioParams = null) + { + var sound = _IHaveNoMouthAndIMustScream.PlayPvs(specifier, body, audioParams); + if (!sound.HasValue) + return null; + + nerveSys.PlayedPainSounds.Add(sound.Value.Entity, sound.Value.Component); + return sound.Value; + } + + public void PlayPainSound(EntityUid body, NerveSystemComponent nerveSys, SoundSpecifier specifier, TimeSpan delay, AudioParams? audioParams = null) + { + nerveSys.PainSoundsToPlay.Add(body, (specifier, audioParams, _timing.CurTime + delay)); + } + + #endregion + + #region Private API + + public sealed class PainTimerJob : Job + { + private readonly PainSystem _self; + private readonly Entity _ent; + public PainTimerJob(PainSystem self, Entity ent, double maxTime, CancellationToken cancellation = default) : base(maxTime, cancellation) + { + _self = self; + _ent = ent; + } + + public PainTimerJob(PainSystem self, Entity ent, double maxTime, IStopwatch stopwatch, CancellationToken cancellation = default) : base(maxTime, stopwatch, cancellation) + { + _self = self; + _ent = ent; + } + + protected override Task Process() + { + _self.UpdateDamage(_ent.Owner, _ent.Comp); + return Task.FromResult(null); + } + } + + private void UpdateDamage(EntityUid nerveSysEnt, NerveSystemComponent nerveSys) + { + if (nerveSys.LastPainThreshold != nerveSys.Pain && _timing.CurTime > nerveSys.UpdateTime) + nerveSys.LastPainThreshold = nerveSys.Pain; + + foreach (var (key, value) in nerveSys.PainSoundsToPlay) + { + if (_timing.CurTime < value.Item3) + continue; + + PlayPainSound(key, nerveSys, value.Item1, value.Item2); + nerveSys.PainSoundsToPlay.Remove(key); + } + + foreach (var (key, value) in nerveSys.Modifiers) + { + if (_timing.CurTime > value.Time) + TryRemovePainModifier(nerveSysEnt, key.Item1, key.Item2, nerveSys); + } + + foreach (var (key, value) in nerveSys.Multipliers) + { + if (_timing.CurTime > value.Time) + TryRemovePainMultiplier(nerveSysEnt, key, nerveSys); + } + + // I hate myself. + foreach (var (ent, nerve) in nerveSys.Nerves) + { + foreach (var (key, value) in nerve.PainFeelingModifiers.ToList()) + { + if (_timing.CurTime > value.Time) + TryRemovePainFeelsModifier(key.Item1, key.Item2, ent, nerve); + } + } + } + + private void UpdateNerveSystemPain(EntityUid uid, NerveSystemComponent? nerveSys = null) + { + if (!Resolve(uid, ref nerveSys, false)) + return; + + if (!TryComp(uid, out var organ) || organ.Body == null) + return; + + nerveSys.Pain = + FixedPoint2.Clamp( + nerveSys.Modifiers.Aggregate((FixedPoint2) 0, + (current, modifier) => + current + ApplyModifiersToPain(modifier.Key.Item1, modifier.Value.Change, nerveSys)), + 0, + nerveSys.PainCap); + + UpdatePainThreshold(uid, nerveSys); + if (!_consciousness.SetConsciousnessModifier( + organ.Body.Value, + uid, + -nerveSys.Pain, + identifier: PainModifierIdentifier, + type: ConsciousnessModType.Pain)) + { + _consciousness.AddConsciousnessModifier( + organ.Body.Value, + uid, + -nerveSys.Pain, + identifier: PainModifierIdentifier, + type: ConsciousnessModType.Pain); + } + } + + private void CleanupSounds(NerveSystemComponent nerveSys) + { + foreach (var (id, _) in nerveSys.PlayedPainSounds.Where(sound => !TerminatingOrDeleted(sound.Key))) + { + _IHaveNoMouthAndIMustScream.Stop(id); + nerveSys.PlayedPainSounds.Remove(id); + } + + foreach (var (id, _) in nerveSys.PainSoundsToPlay.Where(sound => !TerminatingOrDeleted(sound.Key))) + { + nerveSys.PainSoundsToPlay.Remove(id); + } + } + + private void ApplyPainReflexesEffects(EntityUid body, Entity nerveSys, PainThresholdTypes reaction) + { + if (!_net.IsServer) + return; + + var sex = Sex.Unsexed; + if (TryComp(body, out var humanoid)) + sex = humanoid.Sex; + + switch (reaction) + { + case PainThresholdTypes.PainFlinch: + CleanupSounds(nerveSys.Comp); + PlayPainSound(body, nerveSys.Comp, nerveSys.Comp.PainScreams[sex]); + + _popup.PopupPredicted(Loc.GetString("screams-and-flinches-pain", ("entity", body)), body, null, PopupType.MediumCaution); + _jitter.DoJitter(body, TimeSpan.FromSeconds(0.9), true, 24f, 1f); + + break; + case PainThresholdTypes.Agony: + CleanupSounds(nerveSys); + PlayPainSound(body, nerveSys, nerveSys.Comp.AgonyScreams[sex], AudioParams.Default.WithVolume(12f)); + + // We love violence, don't we? + + _popup.PopupPredicted(Loc.GetString("screams-in-agony", ("entity", body)), body, null, PopupType.MediumCaution); + _jitter.DoJitter(body, nerveSys.Comp.PainShockStunTime / 1.4, true, 30f, 12f); + + break; + case PainThresholdTypes.PainShock: + CleanupSounds(nerveSys); + + var screamSpecifier = nerveSys.Comp.PainShockScreams[sex]; + var scream = PlayPainSound(body, nerveSys, screamSpecifier, AudioParams.Default.WithVolume(12f)); + if (scream.HasValue) + { + var sound = nerveSys.Comp.PainShockWhimpers[sex]; + PlayPainSound(body, + nerveSys, + sound, + _IHaveNoMouthAndIMustScream.GetAudioLength(_IHaveNoMouthAndIMustScream.GetSound(screamSpecifier)) - TimeSpan.FromSeconds(2), + AudioParams.Default.WithVolume(-12f)); + } + + // This shit is NOT helpful. It breaks the multipliers, and every 21 seconds the multiplier ends, you fall into fucking crit + // and stand up AGAIN due to adrenaline. Thus trapping you in an endless cycle of pain, not funny + // TryAddPainMultiplier(nerveSys, "PainShockAdrenaline", 0.5f, nerveSys, TimeSpan.FromSeconds(21f)); + PlayPainSound(body, nerveSys, nerveSys.Comp.PainRattles, AudioParams.Default.WithVolume(-6f)); + + _popup.PopupPredicted( + _standing.IsDown(body) + ? Loc.GetString("screams-in-pain", ("entity", body)) + : Loc.GetString("screams-and-falls-pain", ("entity", body)), + body, + null, + PopupType.MediumCaution); + + _stun.TryParalyze(body, nerveSys.Comp.PainShockStunTime, true); + _jitter.DoJitter(body, nerveSys.Comp.PainShockStunTime, true, 20f, 7f); + + // For the funnies :3 + _consciousness.ForceConscious(body, nerveSys.Comp.PainShockStunTime); + nerveSys.Comp.LastThresholdType = PainThresholdTypes.None; + + break; + case PainThresholdTypes.PainPassout: + CleanupSounds(nerveSys); + + _popup.PopupPredicted(Loc.GetString("passes-out-pain", ("entity", body)), body, null, PopupType.MediumCaution); + _consciousness.ForcePassout(body, nerveSys.Comp.ForcePassoutTime); + + nerveSys.Comp.LastThresholdType = PainThresholdTypes.None; + + break; + case PainThresholdTypes.None: + break; + } + } + + private void UpdatePainThreshold(EntityUid uid, NerveSystemComponent nerveSys) + { + var painInput = nerveSys.Pain - nerveSys.LastPainThreshold; + + var nearestReflex = PainThresholdTypes.None; + foreach (var (reflex, threshold) in nerveSys.PainThresholds.OrderByDescending(kv => kv.Value)) + { + if (painInput < threshold) + continue; + + nearestReflex = reflex; + break; + } + + if (nearestReflex == PainThresholdTypes.None) + return; + + if (nerveSys.LastThresholdType == nearestReflex || _timing.CurTime < nerveSys.UpdateTime) + return; + + if (!TryComp(uid, out var organ) || !organ.Body.HasValue) + return; + + var ev1 = new PainThresholdTriggered(uid, nerveSys, nearestReflex, painInput); + RaiseLocalEvent(organ.Body.Value, ref ev1); + + if (ev1.Cancelled || _mobState.IsDead(organ.Body.Value)) + return; + + var ev2 = new PainThresholdEffected(uid, nerveSys, nearestReflex, painInput); + RaiseLocalEvent(organ.Body.Value, ref ev2); + + nerveSys.UpdateTime = _timing.CurTime + nerveSys.ThresholdUpdateTime; + nerveSys.LastThresholdType = nearestReflex; + + ApplyPainReflexesEffects(organ.Body.Value, (uid, nerveSys), nearestReflex); + } + + private FixedPoint2 ApplyModifiersToPain(EntityUid nerveUid, FixedPoint2 pain, NerveSystemComponent nerveSys, NerveComponent? nerve = null) + { + if (!Resolve(nerveUid, ref nerve, false)) + return pain; + + var modifiedPain = pain * nerve.PainMultiplier; + if (nerveSys.Multipliers.Count == 0) + return modifiedPain; + + var toMultiply = nerveSys.Multipliers.Sum(multiplier => (int) multiplier.Value.Change); + return modifiedPain * toMultiply / nerveSys.Multipliers.Count; // o(*^@^*)o + } + + #endregion +} diff --git a/Content.Shared/Backmen/Surgery/Pain/Systems/PainSystem.cs b/Content.Shared/Backmen/Surgery/Pain/Systems/PainSystem.cs new file mode 100644 index 00000000000..6902b3e9007 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Pain/Systems/PainSystem.cs @@ -0,0 +1,173 @@ +using Content.Shared.Backmen.Surgery.Body.Events; +using Content.Shared.Backmen.Surgery.Consciousness.Systems; +using Content.Shared.Backmen.Surgery.Pain.Components; +using Content.Shared.Backmen.Surgery.Wounds.Systems; +using Content.Shared.Body.Part; +using Content.Shared.Body.Systems; +using Content.Shared.Humanoid; +using Content.Shared.Jittering; +using Content.Shared.Mobs; +using Content.Shared.Mobs.Systems; +using Content.Shared.Popups; +using Content.Shared.Standing; +using Content.Shared.Stunnable; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; +using Robust.Shared.GameStates; +using Robust.Shared.Network; +using Robust.Shared.Timing; + +namespace Content.Shared.Backmen.Surgery.Pain.Systems; + +[Virtual] +public sealed partial class PainSystem : EntitySystem +{ + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + [Dependency] private readonly SharedBodySystem _body = default!; + + [Dependency] private readonly SharedAudioSystem _IHaveNoMouthAndIMustScream = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedJitteringSystem _jitter = default!; + [Dependency] private readonly SharedStunSystem _stun = default!; + + [Dependency] private readonly MobStateSystem _mobState = default!; + + [Dependency] private readonly StandingStateSystem _standing = default!; + + [Dependency] private readonly WoundSystem _wound = default!; + [Dependency] private readonly ConsciousnessSystem _consciousness = default!; + + private ISawmill _sawmill = default!; + + public override void Initialize() + { + base.Initialize(); + + _sawmill = Logger.GetSawmill("pain"); + + SubscribeLocalEvent(OnComponentHandleState); + SubscribeLocalEvent(OnComponentGet); + + SubscribeLocalEvent(OnBodyPartAdded); + SubscribeLocalEvent(OnBodyPartRemoved); + + SubscribeLocalEvent(OnMobStateChanged); + + InitAffliction(); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + _painJobQueue.Process(); + + if (!_timing.IsFirstTimePredicted) + return; + + using var query = EntityQueryEnumerator(); + while (query.MoveNext(out var ent, out var nerveSystem)) + { + _painJobQueue.EnqueueJob(new PainTimerJob(this, (ent, nerveSystem), PainJobTime)); + } + } + + private void OnComponentHandleState(EntityUid uid, NerveComponent component, ref ComponentHandleState args) + { + if (args.Current is not NerveComponentState state) + return; + + component.ParentedNerveSystem = GetEntity(state.ParentedNerveSystem); + component.PainMultiplier = state.PainMultiplier; + + component.PainFeelingModifiers.Clear(); + foreach (var ((modEntity, id), modifier) in state.PainFeelingModifiers) + { + component.PainFeelingModifiers.Add((GetEntity(modEntity), id), modifier); + } + } + + private void OnComponentGet(EntityUid uid, NerveComponent comp, ref ComponentGetState args) + { + var state = new NerveComponentState(); + + if (!TerminatingOrDeleted(comp.ParentedNerveSystem)) + state.ParentedNerveSystem = GetNetEntity(comp.ParentedNerveSystem); + state.PainMultiplier = comp.PainMultiplier; + + foreach (var ((modEntity, id), modifier) in comp.PainFeelingModifiers) + { + if (!TerminatingOrDeleted(modEntity)) + state.PainFeelingModifiers.Add((GetNetEntity(modEntity), id), modifier); + } + + args.State = state; + } + + private void OnBodyPartAdded(EntityUid uid, NerveComponent nerve, ref BodyPartAddedEvent args) + { + if (_net.IsClient) + return; + + var bodyPart = Comp(uid); + if (!bodyPart.Body.HasValue) + return; + + if (!_consciousness.TryGetNerveSystem(bodyPart.Body.Value, out var brainUid) || TerminatingOrDeleted(brainUid.Value)) + return; + + TryRemovePainMultiplier(brainUid.Value, MetaData(args.Part.Owner).EntityPrototype!.ID + "Loss"); + UpdateNerveSystemNerves(brainUid.Value, bodyPart.Body.Value, Comp(brainUid.Value)); + } + + private void OnBodyPartRemoved(EntityUid uid, NerveComponent nerve, ref BodyPartRemovedEvent args) + { + if (_net.IsClient) + return; + + var bodyPart = Comp(uid); + if (!bodyPart.Body.HasValue) + return; + + if (!_consciousness.TryGetNerveSystem(bodyPart.Body.Value, out var brainUid) || TerminatingOrDeleted(brainUid.Value)) + return; + + TryAddPainMultiplier(brainUid.Value, MetaData(args.Part.Owner).EntityPrototype!.ID + "Loss", 2); + UpdateNerveSystemNerves(brainUid.Value, bodyPart.Body.Value, Comp(brainUid.Value)); + } + + private void OnMobStateChanged(EntityUid uid, NerveSystemComponent nerveSys, MobStateChangedEvent args) + { + switch (args.NewMobState) + { + case MobState.Critical: + var sex = Sex.Unsexed; + if (TryComp(args.Target, out var humanoid)) + sex = humanoid.Sex; + + CleanupSounds(nerveSys); + PlayPainSound(args.Target, nerveSys, nerveSys.CritWhimpers[sex], AudioParams.Default.WithVolume(-12f)); + break; + default: + CleanupSounds(nerveSys); + break; + } + } + + private void UpdateNerveSystemNerves(EntityUid uid, EntityUid body, NerveSystemComponent component) + { + component.Nerves.Clear(); + foreach (var bodyPart in _body.GetBodyChildren(body)) + { + if (!TryComp(bodyPart.Id, out var nerve)) + continue; + + component.Nerves.Add(bodyPart.Id, nerve); + Dirty(uid, component); + + nerve.ParentedNerveSystem = uid; + Dirty(bodyPart.Id, nerve); // ヾ(≧▽≦*)o + } + } +} diff --git a/Content.Shared/Backmen/Surgery/SharedSurgerySystem.Steps.cs b/Content.Shared/Backmen/Surgery/SharedSurgerySystem.Steps.cs index 027e71e97bd..1ccb1a1d209 100644 --- a/Content.Shared/Backmen/Surgery/SharedSurgerySystem.Steps.cs +++ b/Content.Shared/Backmen/Surgery/SharedSurgerySystem.Steps.cs @@ -15,7 +15,6 @@ using Content.Shared.Popups; using Robust.Shared.Prototypes; using System.Linq; -using Content.Shared.Backmen.Surgery; using Content.Shared.Backmen.Mood; using Content.Shared.Backmen.Surgery.Body.Events; using Content.Shared.Backmen.Surgery.Body.Organs; @@ -24,7 +23,6 @@ using Content.Shared.Backmen.Surgery.Steps.Parts; using Content.Shared.Backmen.Surgery.Tools; using Content.Shared.Containers.ItemSlots; -using AmputateAttemptEvent = Content.Shared.Body.Events.AmputateAttemptEvent; namespace Content.Shared.Backmen.Surgery; @@ -319,7 +317,7 @@ private void OnCutLarvaRootsCheck(Entity ent, private void OnCavityStep(Entity ent, ref SurgeryStepEvent args) { - if (!TryComp(args.Part, out BodyPartComponent? partComp) || partComp.PartType != BodyPartType.Torso) + if (!TryComp(args.Part, out BodyPartComponent? partComp) || partComp.PartType != BodyPartType.Chest) return; var activeHandEntity = _hands.EnumerateHeld(args.User).FirstOrDefault(); @@ -363,8 +361,6 @@ private void OnAddPartStep(Entity ent, ref SurgeryS _body.TryCreatePartSlot(args.Part, slotName, partComp.PartType, out _); _body.AttachPart(args.Part, slotName, tool); EnsureComp(tool); - var ev = new BodyPartAttachedEvent((tool, partComp)); - RaiseLocalEvent(args.Body, ref ev); } } } @@ -375,16 +371,10 @@ private void OnAffixPartStep(Entity ent, ref Surg return; var targetPart = _body.GetBodyChildrenOfType(args.Body, removedComp.Part, symmetry: removedComp.Symmetry).FirstOrDefault(); - if (targetPart != default) { // We reward players for properly affixing the parts by healing a little bit of damage, and enabling the part temporarily. - var ev = new BodyPartEnableChangedEvent(true); - RaiseLocalEvent(targetPart.Id, ref ev); - _damageable.TryChangeDamage(args.Body, - _body.GetHealingSpecifier(targetPart.Component) * 2, - canSever: false, // Just in case we heal a brute damage specifier and the logic gets fucky lol - targetPart: _body.GetTargetBodyPart(targetPart.Component.PartType, targetPart.Component.Symmetry)); + _wounds.TryHealWoundsOnWoundable(targetPart.Id, 12f, out _); RemComp(targetPart.Id); } } @@ -414,8 +404,10 @@ private void OnRemovePartStep(Entity ent, ref Su || partComp.Body != args.Body) return; - var ev = new AmputateAttemptEvent(args.Part); - RaiseLocalEvent(args.Part, ref ev); + if (!_body.TryGetParentBodyPart(args.Part, out var parentPart, out _)) + return; + + _wounds.AmputateWoundableSafely(parentPart.Value, args.Part); _hands.TryPickupAnyHand(args.User, args.Part); } @@ -767,7 +759,8 @@ public bool CanPerformStep(EntityUid user, EntityUid body, EntityUid part, var slot = type switch { BodyPartType.Head => SlotFlags.HEAD, - BodyPartType.Torso => SlotFlags.OUTERCLOTHING | SlotFlags.INNERCLOTHING, + BodyPartType.Chest => SlotFlags.OUTERCLOTHING | SlotFlags.INNERCLOTHING, + BodyPartType.Groin => SlotFlags.OUTERCLOTHING | SlotFlags.INNERCLOTHING, BodyPartType.Arm => SlotFlags.OUTERCLOTHING | SlotFlags.INNERCLOTHING, BodyPartType.Hand => SlotFlags.GLOVES, BodyPartType.Leg => SlotFlags.OUTERCLOTHING | SlotFlags.LEGS, diff --git a/Content.Shared/Backmen/Surgery/SharedSurgerySystem.cs b/Content.Shared/Backmen/Surgery/SharedSurgerySystem.cs index 47711d80f66..a7bbca8c9b8 100644 --- a/Content.Shared/Backmen/Surgery/SharedSurgerySystem.cs +++ b/Content.Shared/Backmen/Surgery/SharedSurgerySystem.cs @@ -1,6 +1,7 @@ using System.Linq; using Content.Shared.Backmen.Surgery.Conditions; using Content.Shared.Backmen.Surgery.Steps.Parts; +using Content.Shared.Backmen.Surgery.Wounds.Systems; using Content.Shared.Medical.Surgery.Conditions; using Content.Shared.Body.Systems; using Content.Shared.Medical.Surgery.Steps; @@ -20,6 +21,7 @@ using Content.Shared.Popups; using Content.Shared.Standing; using Robust.Shared.Audio.Systems; +using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Network; using Robust.Shared.Prototypes; @@ -45,6 +47,8 @@ public abstract partial class SharedSurgerySystem : EntitySystem [Dependency] private readonly RotateToFaceSystem _rotateToFace = default!; [Dependency] private readonly StandingStateSystem _standing = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly WoundSystem _wounds = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; private readonly Dictionary _surgeries = new(); diff --git a/Content.Shared/Backmen/Surgery/Traumas/Components/BleedInflicterComponent.cs b/Content.Shared/Backmen/Surgery/Traumas/Components/BleedInflicterComponent.cs new file mode 100644 index 00000000000..8d0b5dbe694 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Traumas/Components/BleedInflicterComponent.cs @@ -0,0 +1,36 @@ +using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; + +namespace Content.Shared.Backmen.Surgery.Traumas.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class BleedInflicterComponent : Component +{ + [ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] + public bool IsBleeding = false; + + [ViewVariables(VVAccess.ReadOnly)] + public FixedPoint2 BleedingAmount => BleedingAmountRaw * Scaling; + + [ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] + public FixedPoint2 BleedingAmountRaw = 0; + + [DataField("canGrow"), ViewVariables(VVAccess.ReadOnly)] + public bool BleedingScales = true; + + // it's calculated when a wound is spawned. + [ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] + public TimeSpan ScalingFinishesAt = TimeSpan.Zero; + + [ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] + public TimeSpan ScalingStartsAt = TimeSpan.Zero; + + [ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] + public FixedPoint2 SeverityPenalty = 1f; + + [ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] + public FixedPoint2 Scaling = 1; + + [DataField, ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] + public FixedPoint2 ScalingLimit = 1.4; +} diff --git a/Content.Server/Body/Components/BloodstreamComponent.cs b/Content.Shared/Backmen/Surgery/Traumas/Components/BloodstreamComponent.cs similarity index 88% rename from Content.Server/Body/Components/BloodstreamComponent.cs rename to Content.Shared/Backmen/Surgery/Traumas/Components/BloodstreamComponent.cs index 35e76403bb6..a23468a88fd 100644 --- a/Content.Server/Body/Components/BloodstreamComponent.cs +++ b/Content.Shared/Backmen/Surgery/Traumas/Components/BloodstreamComponent.cs @@ -1,5 +1,3 @@ -using Content.Server.Body.Systems; -using Content.Server.Chemistry.EntitySystems; using Content.Shared.Alert; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; @@ -7,12 +5,13 @@ using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; using Robust.Shared.Audio; +using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -namespace Content.Server.Body.Components +namespace Content.Shared.Backmen.Surgery.Traumas.Components { - [RegisterComponent, Access(typeof(BloodstreamSystem), typeof(ReactionMixerSystem))] + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class BloodstreamComponent : Component { public static string DefaultChemicalsSolutionName = "chemicals"; @@ -41,52 +40,52 @@ public sealed partial class BloodstreamComponent : Component /// /// This generally corresponds to an amount of damage and can't go above 100. /// - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public float BleedAmount; /// /// How much should bleeding be reduced every update interval? /// - [DataField] + [DataField, AutoNetworkedField] public float BleedReductionAmount = 0.33f; /// /// How high can go? /// - [DataField] + [DataField, AutoNetworkedField] public float MaxBleedAmount = 10.0f; /// /// What percentage of current blood is necessary to avoid dealing blood loss damage? /// - [DataField] + [DataField, AutoNetworkedField] public float BloodlossThreshold = 0.9f; /// /// The base bloodloss damage to be incurred if below /// The default values are defined per mob/species in YML. /// - [DataField(required: true)] + [DataField(required: true), AutoNetworkedField] public DamageSpecifier BloodlossDamage = new(); /// /// The base bloodloss damage to be healed if above /// The default values are defined per mob/species in YML. /// - [DataField(required: true)] + [DataField(required: true), AutoNetworkedField] public DamageSpecifier BloodlossHealDamage = new(); // TODO shouldn't be hardcoded, should just use some organ simulation like bone marrow or smth. /// /// How much reagent of blood should be restored each update interval? /// - [DataField] + [DataField, AutoNetworkedField] public FixedPoint2 BloodRefreshAmount = 1.0f; /// /// How much blood needs to be in the temporary solution in order to create a puddle? /// - [DataField] + [DataField, AutoNetworkedField] public FixedPoint2 BleedPuddleThreshold = 1.0f; /// @@ -123,14 +122,14 @@ public sealed partial class BloodstreamComponent : Component /// /// Max volume of internal chemical solution storage /// - [DataField] + [DataField, AutoNetworkedField] public FixedPoint2 ChemicalMaxVolume = FixedPoint2.New(250); /// /// Max volume of internal blood storage, /// and starting level of blood. /// - [DataField] + [DataField, AutoNetworkedField] public FixedPoint2 BloodMaxVolume = FixedPoint2.New(300); /// @@ -139,19 +138,19 @@ public sealed partial class BloodstreamComponent : Component /// /// Slime-people might use slime as their blood or something like that. /// - [DataField] + [DataField, AutoNetworkedField] public ProtoId BloodReagent = "Blood"; /// Name/Key that is indexed by. - [DataField] + [DataField, AutoNetworkedField] public string BloodSolutionName = DefaultBloodSolutionName; /// Name/Key that is indexed by. - [DataField] + [DataField, AutoNetworkedField] public string ChemicalSolutionName = DefaultChemicalsSolutionName; /// Name/Key that is indexed by. - [DataField] + [DataField, AutoNetworkedField] public string BloodTemporarySolutionName = DefaultBloodTemporarySolutionName; /// @@ -180,7 +179,7 @@ public sealed partial class BloodstreamComponent : Component [ViewVariables(VVAccess.ReadWrite)] public TimeSpan StatusTime; - [DataField] + [DataField, AutoNetworkedField] public ProtoId BleedingAlert = "Bleed"; } } diff --git a/Content.Shared/Backmen/Surgery/Traumas/Components/BoneComponent.cs b/Content.Shared/Backmen/Surgery/Traumas/Components/BoneComponent.cs new file mode 100644 index 00000000000..fed8a796904 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Traumas/Components/BoneComponent.cs @@ -0,0 +1,24 @@ +using Content.Shared.FixedPoint; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Backmen.Surgery.Traumas.Components; + +[RegisterComponent, AutoGenerateComponentState, NetworkedComponent] +public sealed partial class BoneComponent : Component +{ + [DataField, AutoNetworkedField, ViewVariables] + public EntityUid? BoneWoundable; + + [DataField, AutoNetworkedField, ViewVariables] + public FixedPoint2 IntegrityCap = 40; + + [DataField, AutoNetworkedField, ViewVariables] + public FixedPoint2 BoneIntegrity = 40; + + [DataField, AutoNetworkedField, ViewVariables] + public BoneSeverity BoneSeverity = BoneSeverity.Normal; + + [DataField] + public SoundSpecifier BoneBreakSound = new SoundCollectionSpecifier("BoneGone"); +} diff --git a/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.Bones.cs b/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.Bones.cs new file mode 100644 index 00000000000..e90aa1e82a3 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.Bones.cs @@ -0,0 +1,254 @@ +using System.Linq; +using Content.Shared.Backmen.Surgery.Traumas.Components; +using Content.Shared.Backmen.Surgery.Wounds.Components; +using Content.Shared.Body.Components; +using Content.Shared.Body.Part; +using Content.Shared.FixedPoint; +using Content.Shared.Movement.Components; +using Robust.Shared.Audio; +using Robust.Shared.Random; + +namespace Content.Shared.Backmen.Surgery.Traumas.Systems; + +public partial class TraumaSystem +{ + private const float BoneDamageSeverityThreshold = 9f; + + private void InitBones() + { + SubscribeLocalEvent(OnBoneSeverityChanged); + SubscribeLocalEvent(OnBoneSeverityPointChanged); + } + + #region Event handling + + private void OnBoneSeverityChanged(EntityUid uid, BoneComponent component, BoneSeverityChangedEvent args) + { + if (_net.IsClient) + return; + + ApplyBoneDamageEffects(component); + + if (!TryComp(component.BoneWoundable, out var bodyPart) + || bodyPart.Body == null || !TryComp(bodyPart.Body, out var body)) + return; + + ProcessLegsState(bodyPart.Body.Value, body); + } + + private void OnBoneSeverityPointChanged(EntityUid uid, BoneComponent component, BoneSeverityPointChangedEvent args) + { + if (_net.IsClient) + return; + + if (!TryComp(component.BoneWoundable, out var bodyPart) || bodyPart.Body == null) + return; + + if (!_consciousness.TryGetNerveSystem(bodyPart.Body.Value, out var nerveSys)) + return; + + if (component.BoneWoundable == null) + return; + + if (!_pain.TryChangePainModifier(nerveSys.Value, + component.BoneWoundable.Value, + "BoneDamage", + args.SeverityDelta * _bonePainModifiers[component.BoneSeverity])) + { + _pain.TryAddPainModifier(nerveSys.Value, + component.BoneWoundable.Value, + "BoneDamage", + args.SeverityDelta * _bonePainModifiers[component.BoneSeverity]); + } + } + + + #endregion + + #region Public API + + public bool ApplyDamageToBone(EntityUid bone, FixedPoint2 severity, BoneComponent? boneComp = null) + { + if (!Resolve(bone, ref boneComp) || _net.IsClient) + return false; + + var newIntegrity = FixedPoint2.Clamp(boneComp.BoneIntegrity - severity, 0, boneComp.IntegrityCap); + if (boneComp.BoneIntegrity == newIntegrity) + return false; + + boneComp.BoneIntegrity = newIntegrity; + CheckBoneSeverity(bone, boneComp); + + var ev = new BoneSeverityPointChangedEvent(bone, boneComp, boneComp.BoneIntegrity, severity); + RaiseLocalEvent(bone, ref ev, true); + + Dirty(bone, boneComp); + return true; + } + + public bool RandomBoneTraumaChance(WoundableComponent woundableComp, EntityUid woundInflicter, FixedPoint2 severity) + { + var wound = Comp(woundInflicter); + var bone = Comp(woundableComp.Bone!.ContainedEntities[0]); + if (woundableComp.WoundableIntegrity <= 0 || bone.BoneIntegrity <= 0) + return true; + + if (severity < BoneDamageSeverityThreshold) + return false; + + // We do complete random to get the chance for trauma to happen, + // We combine multiple parameters and do some math, to get the chance. + // Even if we get 0.1 damage there's still a chance for injury to be applied, but with the extremely low chance. + // The more damage, the bigger is the chance. + var chance = FixedPoint2.Clamp( + (woundableComp.WoundableIntegrity / (woundableComp.WoundableIntegrity + bone.BoneIntegrity) + * _boneTraumaChanceMultipliers[woundableComp.WoundableSeverity]) + wound.TraumasChances[TraumaType.BoneDamage], + 0, + 1); + + // Some examples of how this works: + // 81 / (81 + 20) * 0.1 (Moderate) = 0.08. Or 8%: + // 57 / (57 + 12) * 0.5 (Severe) = 0.41~. Or 41%; + // 57 / (57 + 0) * 0.5 (Severe) = 0.5. Or 50%; + // Yeah lol having your bone already messed up makes the chance of it damaging again higher + + return _random.Prob((float) chance); + } + + #endregion + + #region Private API + + private void CheckBoneSeverity(EntityUid bone, BoneComponent boneComp) + { + var nearestSeverity = boneComp.BoneSeverity; + + foreach (var (severity, value) in _boneThresholds.OrderByDescending(kv => kv.Value)) + { + if (boneComp.BoneIntegrity < value) + continue; + + nearestSeverity = severity; + break; + } + + if (nearestSeverity != boneComp.BoneSeverity) + { + var ev = new BoneSeverityChangedEvent(bone, nearestSeverity); + RaiseLocalEvent(bone, ref ev, true); + + if (boneComp.BoneWoundable != null) + { + var bodyComp = Comp(boneComp.BoneWoundable.Value); + if (bodyComp.Body.HasValue) + { + if (boneComp.IntegrityCap / 1.6 > boneComp.BoneIntegrity && + nearestSeverity == BoneSeverity.Damaged && + _consciousness.TryGetNerveSystem(bodyComp.Body.Value, out var nerveSys)) + { + _pain.PlayPainSound(bodyComp.Body.Value, nerveSys, boneComp.BoneBreakSound, AudioParams.Default.WithVolume(-8f)); + } + } + } + } + boneComp.BoneSeverity = nearestSeverity; + + Dirty(bone, boneComp); + } + + private void ApplyBoneDamageEffects(BoneComponent boneComp) + { + if (boneComp.BoneWoundable == null) + return; + + var bodyPart = Comp(boneComp.BoneWoundable.Value); + + if (bodyPart.Body == null || !TryComp(bodyPart.Body, out var body)) + return; + + if (bodyPart.PartType != BodyPartType.Leg || body.RequiredLegs <= 0) + return; + + if (!TryComp(boneComp.BoneWoundable, out var movementPart)) + return; + + var modifier = boneComp.BoneSeverity switch + { + BoneSeverity.Normal => 1f, + BoneSeverity.Damaged => 0.6f, + BoneSeverity.Broken => 0f, + _ => 1f, + }; + + movementPart.WalkSpeed *= modifier; + movementPart.SprintSpeed *= modifier; + movementPart.Acceleration *= modifier; + + UpdateLegsMovementSpeed(bodyPart.Body.Value, body); + } + + private void ProcessLegsState(EntityUid body, BodyComponent bodyComp) + { + var brokenLegs = 0; + foreach (var legEntity in bodyComp.LegEntities) + { + if (!TryComp(legEntity, out var legWoundable)) + continue; + + if (Comp(legWoundable.Bone!.ContainedEntities[0]).BoneSeverity == BoneSeverity.Broken) + { + brokenLegs++; + } + } + + if (brokenLegs >= bodyComp.LegEntities.Count / 2 && brokenLegs < bodyComp.LegEntities.Count) + { + _movementSpeed.ChangeBaseSpeed(body, 2.5f * 0.4f, 4.5f * 0.4f, 20f * 0.4f); + } + else if (brokenLegs == bodyComp.LegEntities.Count) + { + _standing.Down(body); + } + else + { + _standing.Stand(body); + _movementSpeed.ChangeBaseSpeed(body, 2.5f, 4.5f, 20f); + } + } + + private void UpdateLegsMovementSpeed(EntityUid body, BodyComponent bodyComp) + { + var walkSpeed = 0f; + var sprintSpeed = 0f; + var acceleration = 0f; + + foreach (var legEntity in bodyComp.LegEntities) + { + if (!TryComp(legEntity, out var legModifier)) + continue; + + if (!TryComp(legEntity, out var bodyPart)) + continue; + + var feet = _body.GetBodyChildrenOfType(body, BodyPartType.Foot, symmetry: bodyPart.Symmetry).ToList(); + + var feetModifier = 1f; + if (feet.Count != 0 && TryComp(feet.First().Id, out var bone) && bone.BoneSeverity == BoneSeverity.Broken) + { + feetModifier = 0.2f; + } + + walkSpeed += legModifier.WalkSpeed * feetModifier; + sprintSpeed += legModifier.SprintSpeed * feetModifier; + acceleration += legModifier.Acceleration * feetModifier; + } + + walkSpeed /= bodyComp.RequiredLegs; + sprintSpeed /= bodyComp.RequiredLegs; + acceleration /= bodyComp.RequiredLegs; + + _movementSpeed.ChangeBaseSpeed(body, walkSpeed, sprintSpeed, acceleration); + } + + #endregion +} diff --git a/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.Data.cs b/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.Data.cs new file mode 100644 index 00000000000..5d24e88a5ea --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.Data.cs @@ -0,0 +1,45 @@ +using Content.Shared.Backmen.Surgery.Wounds; +using Content.Shared.FixedPoint; + +namespace Content.Shared.Backmen.Surgery.Traumas.Systems; + +public partial class TraumaSystem +{ + #region Data + + private readonly Dictionary _boneThresholds = new() + { + { BoneSeverity.Normal, 40 }, + { BoneSeverity.Damaged, 20 }, + { BoneSeverity.Broken, 0 }, + }; + + private readonly Dictionary _bonePainModifiers = new() + { + { BoneSeverity.Normal, 0.5 }, + { BoneSeverity.Damaged, 0.75 }, + { BoneSeverity.Broken, 1 }, + }; + + private readonly Dictionary _boneTraumaChanceMultipliers = new() + { + { WoundableSeverity.Healthy, 0.01 }, + { WoundableSeverity.Minor, 0.1 }, + { WoundableSeverity.Moderate, 0.3 }, + { WoundableSeverity.Severe, 0.5 }, + { WoundableSeverity.Critical, 0.7 }, + { WoundableSeverity.Loss, 0.01 }, // If we lost the woundable holding this bone, I guess we don't care, if is it broken. + }; + + private readonly Dictionary _boneDamageMultipliers = new() + { + { WoundableSeverity.Healthy, 0.01 }, + { WoundableSeverity.Minor, 0.4 }, + { WoundableSeverity.Moderate, 0.6 }, + { WoundableSeverity.Severe, 0.9 }, + { WoundableSeverity.Critical, 1.25 }, + { WoundableSeverity.Loss, 1.6 }, // Fun. + }; + + #endregion +} diff --git a/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.Organs.cs b/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.Organs.cs new file mode 100644 index 00000000000..9b1a1cb63b5 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.Organs.cs @@ -0,0 +1,171 @@ +using System.Linq; +using Content.Shared.Backmen.Surgery.Wounds.Components; +using Content.Shared.Body.Organ; +using Content.Shared.Body.Part; +using Content.Shared.FixedPoint; +using Robust.Shared.Random; + +namespace Content.Shared.Backmen.Surgery.Traumas.Systems; + +public partial class TraumaSystem +{ + private const float OrganDamageSeverityThreshold = 12f; + + private void InitOrgans() + { + SubscribeLocalEvent(SomeShitHappensHere); + SubscribeLocalEvent(SomeOtherShitHappensHere); + } + + #region Event handling + + private void SomeShitHappensHere(EntityUid organ, OrganComponent comp, OrganDamageSeverityChanged args) + { + // TODO: Make those actually handled. and also make undamaged organs fall out when a woundable gets destroyed, for the funnies :3 + } + + private void SomeOtherShitHappensHere(EntityUid organ, OrganComponent comp, OrganDamagePointChangedEvent args) + { + } + + #endregion + + #region Public API + + public bool TryCreateOrganDamageModifier(EntityUid uid, + FixedPoint2 severity, + EntityUid effectOwner, + string identifier, + OrganComponent? organ = null) + { + if (!Resolve(uid, ref organ)) + return false; + + organ.IntegrityModifiers.Add((identifier, effectOwner), severity); + UpdateOrganIntegrity(uid, organ); + + return true; + } + + public bool TrySetOrganDamageModifier(EntityUid uid, + FixedPoint2 severity, + EntityUid effectOwner, + string identifier, + OrganComponent? organ = null) + { + if (!Resolve(uid, ref organ)) + return false; + + organ.IntegrityModifiers[(identifier, effectOwner)] = severity; + UpdateOrganIntegrity(uid, organ); + + return true; + } + + public bool TryChangeOrganDamageModifier(EntityUid uid, + FixedPoint2 change, + EntityUid effectOwner, + string identifier, + OrganComponent? organ = null) + { + if (!Resolve(uid, ref organ)) + return false; + + if (!organ.IntegrityModifiers.TryGetValue((identifier, effectOwner), out var value)) + return false; + + organ.IntegrityModifiers[(identifier, effectOwner)] = value + change; + UpdateOrganIntegrity(uid, organ); + + return true; + } + + public bool TryRemoveOrganDamageModifier(EntityUid uid, + EntityUid effectOwner, + string identifier, + OrganComponent? organ = null) + { + if (!Resolve(uid, ref organ)) + return false; + + if (!organ.IntegrityModifiers.Remove((identifier, effectOwner))) + return false; + + UpdateOrganIntegrity(uid, organ); + return true; + } + + public bool RandomOrganTraumaChance(EntityUid target, EntityUid woundInflicter, WoundableComponent woundable, FixedPoint2 severity) + { + var bodyPart = Comp(target); + if (!bodyPart.Body.HasValue) + return false; // No entity to apply pain to + + if (severity < OrganDamageSeverityThreshold) + return false; + + var totalIntegrity = + _body.GetPartOrgans(target, bodyPart) + .Aggregate((FixedPoint2)0, (current, organ) => current + organ.Component.OrganIntegrity); + + if (totalIntegrity <= 0) // No surviving organs + return false; + + // organ damage is like, very deadly, but not yet + // so like, like, yeah, we don't want a disabler to induce some EVIL ASS organ damage with a 0,000001% chance and ruin your round + // Very unlikely to happen if your woundables are in a good condition + var chance = + FixedPoint2.Clamp( + woundable.WoundableIntegrity / woundable.IntegrityCap / totalIntegrity + + Comp(woundInflicter).TraumasChances[TraumaType.OrganDamage], + 0, + 1); + + return _random.Prob((float) chance); + } + + #endregion + + #region Private API + + private void UpdateOrganIntegrity(EntityUid uid, OrganComponent organ) + { + var oldIntegrity = organ.OrganIntegrity; + organ.OrganIntegrity = FixedPoint2.Clamp(organ.IntegrityModifiers + .Aggregate((FixedPoint2) 0, + (current, modifier) => current + modifier.Value), + 0, + organ.IntegrityCap); + + if (oldIntegrity != organ.OrganIntegrity) + { + var ev = new OrganDamagePointChangedEvent(uid, organ.OrganIntegrity, organ.OrganIntegrity - oldIntegrity); + RaiseLocalEvent(uid, ref ev, true); + + // TODO: might want also to raise the event on the woundable. + } + + var nearestSeverity = organ.OrganSeverity; + foreach (var (severity, value) in organ.IntegrityThresholds.OrderByDescending(kv => kv.Value)) + { + if (organ.OrganIntegrity < value) + continue; + + nearestSeverity = severity; + break; + } + + if (nearestSeverity != organ.OrganSeverity) + { + var ev = new OrganDamageSeverityChanged(uid, organ.OrganSeverity, nearestSeverity); + RaiseLocalEvent(uid, ref ev, true); + + // TODO: might want also to raise the event on the woundable. + } + organ.OrganSeverity = nearestSeverity; + + Dirty(uid, organ); + } + + #endregion +} diff --git a/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.Process.cs b/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.Process.cs new file mode 100644 index 00000000000..8b6071c6074 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.Process.cs @@ -0,0 +1,238 @@ +using System.Linq; +using Content.Shared.Armor; +using Content.Shared.Backmen.Surgery.Wounds; +using Content.Shared.Backmen.Surgery.Wounds.Components; +using Content.Shared.Body.Part; +using Content.Shared.FixedPoint; +using Content.Shared.Inventory; +using Robust.Shared.Random; + +namespace Content.Shared.Backmen.Surgery.Traumas.Systems; + +public partial class TraumaSystem +{ + /// + /// СЛАВА БОГУ 42🙏❤️СЛАВА 42🙏❤️АНГЕЛА ХРАНИТЕЛЯ 42 КАЖДОМУ ИЗ ВАС🙏❤️БОЖЕ ХРАНИ 42🙏❤️СПАСИБО ВАМ НАШИ БРАТУХИ🙏🏼❤️ХРАНИ 42💯СЛАВА БОГУ 42🙏❤️СЛАВА БОГУ 42🙏❤️ + /// СЛАВА 42🙏❤️АНГЕЛА ХРАНИТЕЛЯ 42 КАЖДОМУ СЛАВА БОГУ СВО 🇷🇺❤️ СЛАВА РОССИИ 🇷🇺❤️ + /// АНГЕЛА ХРАНИТЕЛЯ КАЖДОМУ ИЗ ВАС 🇷🇺❤️БОЖЕ ХРАНИ РОССИЮ 🇷🇺❤️ СПАСИБО ВАМ НАШИ МАЛЬЧИКИ ЧТО ПОДДЕРЖИВАЕТЕ РОССИЮ 🇷🇺❤️ + /// СВОих не бросаем! 🇷🇺❤️ ZOV 🇷🇺❤️ ГОЙДА ВСЕМ 🇷🇺🇷🇺 ГОЙДА 🇷🇺❤️ ZOV 🇷🇺❤️ СПАСИБО НАШИМ РОДНЫМ 🇷🇺🇷🇺 ДАЙ БОГ БОГ ВАМ ЗДОРОВЬЯ 🇷🇺🇷🇺 СМАРТФОН VIVO 🇷🇺🇷🇺💪💪 + /// ЖЕЛАЮ ЧТОБ ПРИШЛИ ЗДОРОВЫМИ С ПОБЕДОЙ 🇷🇺🇷🇺🙏 ГОЙДА БРАТЬЯ 🇷🇺🇷🇺 + /// + private const float DismembermentChanceMultiplier = 0.042f; + private const float NerveDamageChanceMultiplier = 0.032f; + + // In seconds + private const float NerveDamageMultiplierTime = 8f; + + private const float NerveDamageSeverityThreshold = 9f; + + #region Public API + + public IEnumerable RandomTraumaChance(EntityUid target, EntityUid woundInflicter, FixedPoint2 severity, WoundableComponent? woundable = null) + { + var traumaList = new HashSet(); + if (!Resolve(target, ref woundable)) + return traumaList; + + if (RandomBoneTraumaChance(woundable, woundInflicter, severity)) + traumaList.Add(TraumaType.BoneDamage); + + if (RandomNerveDamageChance(target, woundInflicter, woundable, severity)) + traumaList.Add(TraumaType.NerveDamage); + + if (RandomOrganTraumaChance(target, woundInflicter, woundable, severity)) + traumaList.Add(TraumaType.OrganDamage); + + //if (RandomVeinsTraumaChance(woundable)) + // traumaList.Add(TraumaType.VeinsDamage); + + if (RandomDismembermentTraumaChance(target, woundInflicter, woundable, severity)) + traumaList.Add(TraumaType.Dismemberment); + + return traumaList; + } + + public bool TryApplyTrauma(EntityUid target, FixedPoint2 severity, List traumas, WoundableComponent? woundable = null) + { + if (!Resolve(target, ref woundable)) + return false; + + if (severity <= 0) + return false; + + var traumaTypes = traumas.ToList(); + if (traumaTypes.Count == 0) + return false; + + ApplyTraumas(target, traumaTypes, severity, woundable); + return true; + } + + public bool TryApplyTraumaWithRandom(EntityUid target, EntityUid woundInflicter, FixedPoint2 severity, WoundableComponent? woundable = null) + { + if (!Resolve(target, ref woundable) || _net.IsClient) + return false; + + if (severity <= 0) + return false; + + var traumas = RandomTraumaChance(target, woundInflicter, severity, woundable).ToList(); + if (traumas.Count == 0) + return false; + + ApplyTraumas(target, traumas, severity, woundable); + return true; + } + + public FixedPoint2 GetCoverageDeduction(EntityUid body, BodyPartType coverage) + { + var deduction = (FixedPoint2) 0; + + foreach (var ent in _inventory.GetHandOrInventoryEntities(body, SlotFlags.WITHOUT_POCKET)) + { + if (!TryComp(ent, out var armour)) + continue; + + if (armour.ArmorCoverage.Contains(coverage)) + { + deduction += armour.DismembermentChanceDeduction; + } + } + + return deduction; + } + + public bool RandomNerveDamageChance(EntityUid target, EntityUid woundInflicter, WoundableComponent woundable, FixedPoint2 severity) + { + var bodyPart = Comp(target); + if (!bodyPart.Body.HasValue) + return false; // No entity to apply pain to + + if (severity < NerveDamageSeverityThreshold) + return false; // to prevent shit like disablers from killing people + + // literally dismemberment chance, but lower by default + var chance = + FixedPoint2.Clamp( + woundable.WoundableIntegrity / woundable.IntegrityCap + * NerveDamageChanceMultiplier + Comp(woundInflicter).TraumasChances[TraumaType.NerveDamage], + 0, + 1); + + return _random.Prob((float) chance); + } + + public bool RandomDismembermentTraumaChance(EntityUid target, EntityUid woundInflicter, WoundableComponent woundable, FixedPoint2 severity) + { + var bodyPart = Comp(target); + if (!bodyPart.Body.HasValue) + return false; // Can't sever if already severed + + var parentWoundable = woundable.ParentWoundable; + if (!parentWoundable.HasValue) // how? + return false; + + var parentComp = Comp(parentWoundable.Value); + if ((parentComp.WoundableIntegrity == parentComp.IntegrityCap || woundable.WoundableIntegrity == woundable.IntegrityCap) && severity < 21) + return false; // just so you don't get your body part ripped out by a sneeze + + if (Comp(target).PartType == BodyPartType.Groin && parentComp.WoundableSeverity is not WoundableSeverity.Critical) + return false; + + var deduction = GetCoverageDeduction(bodyPart.Body.Value, bodyPart.PartType); + + // random-y but not so random-y like bones. Heavily depends on woundable state and damage + var chance = + FixedPoint2.Clamp( + woundable.WoundableIntegrity / woundable.IntegrityCap + * DismembermentChanceMultiplier - deduction + Comp(woundInflicter).TraumasChances[TraumaType.Dismemberment], + 0, + 1); + // getting hit again increases the chance + + return _random.Prob((float) chance); + } + + #endregion + + #region Private API + + private void ApplyTraumas(EntityUid target, IEnumerable traumas, FixedPoint2 severity, WoundableComponent woundable) + { + var traumaList = traumas.ToList(); + if (traumaList.Contains(TraumaType.BoneDamage)) + { + var damage = severity * _boneDamageMultipliers[woundable.WoundableSeverity]; + var traumaApplied = ApplyDamageToBone(woundable.Bone!.ContainedEntities[0], damage); + + var bodyPart = Comp(target); + if (bodyPart.Body.HasValue && _consciousness.TryGetNerveSystem(bodyPart.Body.Value, out var nerveSys)) + _pain.TryAddPainModifier(nerveSys.Value, target, "BoneDamageImminent", 20f, time: TimeSpan.FromSeconds(12f)); + + _sawmill.Debug(traumaApplied + ? $"A new trauma (Raw Severity: {severity}) was created on target: {target}. Type: Bone damage." + : $"Tried to create a trauma on target: {target}, but no trauma was applied. Type: Bone damage."); + } + + if (traumaList.Contains(TraumaType.NerveDamage)) + { + var bodyPart = Comp(target); + if (bodyPart.Body.HasValue && _consciousness.TryGetNerveSystem(bodyPart.Body.Value, out var nerveSys)) + { + _pain.TryAddPainMultiplier(nerveSys.Value, + "NerveDamage", + 2f, + time: TimeSpan.FromSeconds(NerveDamageMultiplierTime)); + _pain.TryAddPainFeelsModifier(nerveSys.Value, + "NerveDamage", + target, + -0.4f); + + foreach (var child in _wound.GetAllWoundableChildren(target)) + { + _pain.TryAddPainFeelsModifier(nerveSys.Value, + "NerveDamage", + child.Item1, + -0.4f); + } + + _sawmill.Debug( $"A new trauma (Caused by {severity} damage) was created on target: {target}. Type: NerveDamage."); + } + } + + // TODO: veins, would have been very lovely to integrate this into vascular system + //if (RandomVeinsTraumaChance(woundable)) + //{ + // traumaApplied = ApplyDamageToVeins(woundable.Veins!.ContainedEntities[0], severity * _veinsDamageMultipliers[woundable.WoundableSeverity]); + // _sawmill.Info(traumaApplied + // ? $"A new trauma (Raw Severity: {severity}) was created on target: {target} of type Vein damage" + // : $"Tried to create a trauma on target: {target}, but no trauma was applied. Type: Vein damage."); + //} + + if (traumaList.Contains(TraumaType.OrganDamage)) + { + var organs = _body.GetPartOrgans(target).ToList(); + _random.Shuffle(organs); + + var chosenOrgan = organs.FirstOrDefault(); + if (!TryChangeOrganDamageModifier(chosenOrgan.Id, severity, target, "WoundableDamage")) + { + TryCreateOrganDamageModifier(chosenOrgan.Id, severity, target, "WoundableDamage"); + // Do not apply pain for organ damage is already supposed to be deadly; Unless it is NOT enough. + } + + _sawmill.Debug( $"A new trauma (Caused by {severity} damage) was created on target: {target}; organ: {chosenOrgan}. Type: OrganDamage."); + } + + if (traumaList.Contains(TraumaType.Dismemberment)) + { + if (!_wound.IsWoundableRoot(target, woundable) && woundable.ParentWoundable.HasValue) + { + _wound.AmputateWoundable(woundable.ParentWoundable.Value, target, woundable); + _sawmill.Debug($"A new trauma (Caused by {severity} damage) was created on target: {target}. Type: Dismemberment."); + } + } + } + + #endregion +} diff --git a/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.cs b/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.cs new file mode 100644 index 00000000000..dfe36b5f925 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Traumas/Systems/TraumaSystem.cs @@ -0,0 +1,37 @@ +using Content.Shared.Backmen.Surgery.Consciousness.Systems; +using Content.Shared.Backmen.Surgery.Pain.Systems; +using Content.Shared.Backmen.Surgery.Wounds.Systems; +using Content.Shared.Body.Systems; +using Content.Shared.Inventory; +using Content.Shared.Movement.Systems; +using Content.Shared.Standing; +using Robust.Shared.Network; +using Robust.Shared.Random; + +namespace Content.Shared.Backmen.Surgery.Traumas.Systems; + +[Virtual] +public sealed partial class TraumaSystem : EntitySystem +{ + [Dependency] private readonly PainSystem _pain = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!; + [Dependency] private readonly StandingStateSystem _standing = default!; + [Dependency] private readonly SharedBodySystem _body = default!; + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly WoundSystem _wound = default!; + [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly ConsciousnessSystem _consciousness = default!; + + private ISawmill _sawmill = default!; + + public override void Initialize() + { + base.Initialize(); + + _sawmill = Logger.GetSawmill("traumas"); + + InitBones(); + InitOrgans(); + } +} diff --git a/Content.Shared/Backmen/Surgery/Traumas/TraumasSerializable.cs b/Content.Shared/Backmen/Surgery/Traumas/TraumasSerializable.cs new file mode 100644 index 00000000000..0f2d4c9e1e0 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Traumas/TraumasSerializable.cs @@ -0,0 +1,51 @@ +using Content.Shared.Backmen.Surgery.Traumas.Components; +using Content.Shared.FixedPoint; +using Robust.Shared.Serialization; + +namespace Content.Shared.Backmen.Surgery.Traumas; + +[Serializable, NetSerializable] +public enum TraumaType +{ + BoneDamage, + OrganDamage, + VeinsDamage, + NerveDamage, // pain + Dismemberment, +} + +#region Organs + +[Serializable, NetSerializable] +public enum OrganSeverity +{ + Normal, + Damaged, + Destroyed, // obliterated +} + +[ByRefEvent] +public record struct OrganDamagePointChangedEvent(EntityUid Organ, FixedPoint2 CurrentSeverity, FixedPoint2 SeverityDelta); + +[ByRefEvent] +public record struct OrganDamageSeverityChanged(EntityUid Organ, OrganSeverity OldSeverity, OrganSeverity NewSeverity); + +#endregion + +#region Bones + +[Serializable, NetSerializable] +public enum BoneSeverity +{ + Normal, + Damaged, + Broken, // Ha-ha. +} + +[ByRefEvent] +public record struct BoneSeverityPointChangedEvent(EntityUid Bone, BoneComponent BoneComponent, FixedPoint2 CurrentSeverity, FixedPoint2 SeverityDelta); + +[ByRefEvent] +public record struct BoneSeverityChangedEvent(EntityUid Bone, BoneSeverity NewSeverity); + +#endregion diff --git a/Content.Shared/Backmen/Surgery/Wounds/Components/WoundComponent.cs b/Content.Shared/Backmen/Surgery/Wounds/Components/WoundComponent.cs new file mode 100644 index 00000000000..47ae8d86bbe --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Wounds/Components/WoundComponent.cs @@ -0,0 +1,110 @@ +using Content.Shared.Backmen.Surgery.Traumas; +using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; + +namespace Content.Shared.Backmen.Surgery.Wounds.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class WoundComponent : Component +{ + /// + /// 'Parent' of wound. Basically the entity to which the wound was applied. + /// + [AutoNetworkedField] + [ViewVariables(VVAccess.ReadOnly)] + public EntityUid HoldingWoundable; + + /// + /// Actually, severity of the wound. The more the worse. + /// Directly depends on + /// + [AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite)] + public FixedPoint2 WoundSeverityPoint; + + /// + /// How much damage this wound does to it's parent woundable? + /// + [AutoNetworkedField] + [ViewVariables(VVAccess.ReadOnly), DataField("integrityMultiplier")] + public FixedPoint2 WoundableIntegrityMultiplier = 1; + + /// + /// maybe some cool mechanical stuff to treat those wounds later. I genuinely have no idea + /// Wound type. External/Internal basically. + /// + [DataField, AutoNetworkedField] + [ViewVariables(VVAccess.ReadOnly)] + public WoundType WoundType = WoundType.External; + + /// + /// Damage group of this wound. + /// + [DataField, AutoNetworkedField] + [ViewVariables(VVAccess.ReadOnly)] + public string? DamageGroup; + + /// + /// Scar wound prototype, what will be spawned upon healing this wound. + /// If null - no scar wound will be spawned. + /// + [DataField, AutoNetworkedField] + [ViewVariables(VVAccess.ReadOnly)] + public string? ScarWound; + + /// + /// Well, name speaks for this. + /// + [DataField, AutoNetworkedField] + [ViewVariables(VVAccess.ReadOnly)] + public bool IsScar; + + /// + /// Wound severity. Has six severities: Healed/Minor/Moderate/Severe/Critical and Loss. + /// Directly depends on + /// + [DataField, AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite)] + public WoundSeverity WoundSeverity; + + /// + /// When wound is visible. Always/HandScanner/AdvancedScanner. + /// + [DataField, AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite)] + public WoundVisibility WoundVisibility = WoundVisibility.Always; + + /// + /// "Can be healed". + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public bool CanBeHealed = true; + + /// + /// Should this bleed? + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public bool CanBleed = true; + + [DataField("bleedsScaling"), ViewVariables(VVAccess.ReadOnly)] + public FixedPoint2 BleedingScalingMultiplier = 1f; + + /// + /// Should this apply trauma to the parent woundable when wound is opened / continued? + /// + [DataField] + public bool CanApplyTrauma = true; + + /// + /// Additional chance (-1, 0, 1) that is added in chance calculation + /// + [DataField] + public Dictionary TraumasChances = new() + { + { TraumaType.Dismemberment, 0 }, + { TraumaType.OrganDamage, 0 }, + { TraumaType.BoneDamage, 0 }, + { TraumaType.NerveDamage, 0 }, + { TraumaType.VeinsDamage, 0 }, + }; +} diff --git a/Content.Shared/Backmen/Surgery/Wounds/Components/WoundableComponent.cs b/Content.Shared/Backmen/Surgery/Wounds/Components/WoundableComponent.cs new file mode 100644 index 00000000000..4c79abf62be --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Wounds/Components/WoundableComponent.cs @@ -0,0 +1,111 @@ +using Content.Shared.FixedPoint; +using Robust.Shared.Audio; +using Robust.Shared.Containers; +using Robust.Shared.GameStates; + +namespace Content.Shared.Backmen.Surgery.Wounds.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class WoundableComponent : Component +{ + /// + /// UID of the parent woundable entity. Can be null. + /// + [ViewVariables, AutoNetworkedField] + public EntityUid? ParentWoundable; + + /// + /// UID of the root woundable entity. + /// + [ViewVariables, AutoNetworkedField] + public EntityUid RootWoundable; + + /// + /// Set of UIDs representing child woundable entities. + /// + [ViewVariables, AutoNetworkedField] + public HashSet ChildWoundables = []; + + /// + /// Indicates whether wounds are allowed. + /// + [DataField] + [ViewVariables, AutoNetworkedField] + public bool AllowWounds = true; + + /// + /// Integrity points of this woundable. + /// + [DataField] + [ViewVariables, AutoNetworkedField] + public FixedPoint2 IntegrityCap; + + /// + /// How big is the Woundable Entity, mostly used for trauma calculation, dodging and targeting + /// + [DataField] + [ViewVariables, AutoNetworkedField] + public FixedPoint2 DodgeChance = 0.1; + + /// + /// Integrity points of this woundable. + /// + [DataField("integrity")] + [ViewVariables, AutoNetworkedField] + public FixedPoint2 WoundableIntegrity; + + /// + /// yeah + /// + [DataField(required: true)] + public Dictionary Thresholds = new(); + + /// + /// How much damage will be healed ACROSS all limb, for example if there are 2 wounds, + /// Healing will be shared across those 2 wounds. + /// + [DataField] + [ViewVariables, AutoNetworkedField] + public FixedPoint2 HealAbility = 0.1; + + /// + /// Multipliers of severity applied to this wound. + /// + public Dictionary SeverityMultipliers = new(); + + /// + /// Multipliers applied to healing rate. + /// + public Dictionary HealingMultipliers = new(); + + [DataField] + public SoundSpecifier WoundableDestroyedSound = new SoundCollectionSpecifier("WoundableDestroyed"); + + [DataField] + public SoundSpecifier WoundableDelimbedSound = new SoundCollectionSpecifier("WoundableDelimbed"); + + /// + /// State of the woundable. Severity basically. + /// + [DataField] + [ViewVariables, AutoNetworkedField] + public WoundableSeverity WoundableSeverity; + + /// + /// How much time in seconds had this woundable accumulated from the last healing tick. + /// + [ViewVariables, AutoNetworkedField] + public float HealingRateAccumulated; + + /// + /// Container potentially holding wounds. + /// + [ViewVariables] + public Container? Wounds; + + /// + /// Container holding this woundables bone. + /// + [ViewVariables] + public Container? Bone; +} diff --git a/Content.Shared/Backmen/Surgery/Wounds/Systems/WoundSystem.Data.cs b/Content.Shared/Backmen/Surgery/Wounds/Systems/WoundSystem.Data.cs new file mode 100644 index 00000000000..826ca5c82e7 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Wounds/Systems/WoundSystem.Data.cs @@ -0,0 +1,20 @@ +using Content.Shared.FixedPoint; + +namespace Content.Shared.Backmen.Surgery.Wounds.Systems; + +public partial class WoundSystem +{ + #region Data + + private readonly Dictionary _woundThresholds = new() + { + { WoundSeverity.Healed, 0 }, + { WoundSeverity.Minor, 1 }, + { WoundSeverity.Moderate, 25 }, + { WoundSeverity.Severe, 50 }, + { WoundSeverity.Critical, 80 }, + { WoundSeverity.Loss, 100 }, + }; + + #endregion +} diff --git a/Content.Shared/Backmen/Surgery/Wounds/Systems/WoundSystem.Healing.cs b/Content.Shared/Backmen/Surgery/Wounds/Systems/WoundSystem.Healing.cs new file mode 100644 index 00000000000..1d966590c7c --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Wounds/Systems/WoundSystem.Healing.cs @@ -0,0 +1,262 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Content.Shared.Backmen.Surgery.Traumas.Components; +using Content.Shared.Backmen.Surgery.Wounds.Components; +using Content.Shared.Damage.Prototypes; +using Content.Shared.FixedPoint; +using Robust.Shared.CPUJob.JobQueues; +using Robust.Shared.CPUJob.JobQueues.Queues; +using Robust.Shared.Timing; + +namespace Content.Shared.Backmen.Surgery.Wounds.Systems; + +public partial class WoundSystem +{ + private const double WoundableJobTime = 0.005; + private readonly JobQueue _woundableJobQueue = new(WoundableJobTime); + public sealed class IntegrityJob : Job + { + private readonly WoundSystem _self; + private readonly Entity _ent; + public IntegrityJob(WoundSystem self, Entity ent, double maxTime, CancellationToken cancellation = default) : base(maxTime, cancellation) + { + _self = self; + _ent = ent; + } + + public IntegrityJob(WoundSystem self, Entity ent, double maxTime, IStopwatch stopwatch, CancellationToken cancellation = default) : base(maxTime, stopwatch, cancellation) + { + _self = self; + _ent = ent; + } + + protected override Task Process() + { + _self.ProcessHealing(_ent); + return Task.FromResult(null); + } + } + private void ProcessHealing(Entity ent) + { + if (_net.IsClient) + return; + + var healableWounds = ent.Comp.Wounds!.ContainedEntities.Select(Comp).Count(comp => comp.CanBeHealed); + var healAmount = -ent.Comp.HealAbility / healableWounds; + + foreach (var wound in ent.Comp.Wounds!.ContainedEntities.ToList()) + { + var comp = Comp(wound); + if (!comp.CanBeHealed) + continue; + + ApplyWoundSeverity(wound, ApplyHealingRateMultipliers(wound, ent.Owner, healAmount, ent.Comp), comp); + } + + // That's it! o(( >ω< ))o + } + + #region Public API + + public bool TryHaltAllBleeding(EntityUid woundable, WoundableComponent? component = null) + { + if (!Resolve(woundable, ref component) || component.Wounds!.Count == 0) + return false; + + foreach (var wound in GetWoundableWounds(woundable, component)) + { + if (!TryComp(wound.Item1, out var bleeds)) + continue; + + bleeds.BleedingScales = false; + bleeds.IsBleeding = false; + + wound.Item2.CanBleed = false; + wound.Item2.CanBeHealed = true; + } + + return true; + } + + public void ForceHealWoundsOnWoundable(EntityUid woundable, + out FixedPoint2 healed, + string? damageGroup = null, + WoundableComponent? component = null) + { + healed = 0; + if (!Resolve(woundable, ref component)) + return; + + var woundsToHeal = + GetWoundableWounds(woundable, component) + .Where(wound => damageGroup == null || wound.Item2.DamageGroup == damageGroup) + .Select(wound => (Entity) wound) + .ToList(); + + foreach (var wound in woundsToHeal) + { + healed += wound.Comp.WoundSeverityPoint; + RemoveWound(wound); + } + + UpdateWoundableIntegrity(woundable, component); + CheckWoundableSeverityThresholds(woundable, component); + } + + public bool TryHealWoundsOnWoundable(EntityUid woundable, + FixedPoint2 healAmount, + out FixedPoint2 healed, + WoundableComponent? component = null, + string? damageGroup = null, + bool ignoreMultipliers = false) + { + healed = 0; + if (!Resolve(woundable, ref component)) + return false; + + var woundsToHeal = + (from wound in component.Wounds!.ContainedEntities + let woundComp = Comp(wound) + where woundComp.CanBeHealed + where damageGroup == null || damageGroup == woundComp.DamageGroup + select (wound, woundComp)).Select(dummy => (Entity) dummy) + .ToList(); // that's what I call LINQ. + + if (woundsToHeal.Count == 0) + return false; + + var healNumba = healAmount / woundsToHeal.Count; + var actualHeal = (FixedPoint2) 0; + foreach (var wound in woundsToHeal) + { + var heal = ignoreMultipliers + ? ApplyHealingRateMultipliers(wound, woundable, -healNumba, component) + : -healNumba; + + actualHeal += -heal; + ApplyWoundSeverity(wound, heal, wound); + } + + UpdateWoundableIntegrity(woundable, component); + CheckWoundableSeverityThresholds(woundable, component); + + healed = actualHeal; + return actualHeal > 0; + } + + public bool TryHealWoundsOnWoundable(EntityUid woundable, + FixedPoint2 healAmount, + string damageType, + out FixedPoint2 healed, + WoundableComponent? component = null, + bool ignoreMultipliers = false) + { + healed = 0; + if (!Resolve(woundable, ref component)) + return false; + + var woundsToHeal = + (from wound in component.Wounds!.ContainedEntities + let woundComp = Comp(wound) + where woundComp.CanBeHealed + where damageType == MetaData(wound).EntityPrototype!.ID + select (wound, woundComp)).Select(dummy => (Entity) dummy) + .ToList(); + + if (woundsToHeal.Count == 0) + return false; + + var healNumba = healAmount / woundsToHeal.Count; + var actualHeal = (FixedPoint2) 0; + foreach (var wound in woundsToHeal) + { + var heal = ignoreMultipliers + ? ApplyHealingRateMultipliers(wound, woundable, -healNumba, component) + : -healNumba; + + actualHeal += -heal; + ApplyWoundSeverity(wound, heal, wound); + } + + UpdateWoundableIntegrity(woundable, component); + CheckWoundableSeverityThresholds(woundable, component); + + healed = actualHeal; + return actualHeal > 0; + } + + public bool TryGetWoundableWithMostDamage( + EntityUid body, + [NotNullWhen(true)] out Entity? woundable, + string? damageGroup = null, + bool healable = false) + { + var biggestDamage = (FixedPoint2) 0; + + woundable = null; + foreach (var bodyPart in _body.GetBodyChildren(body)) + { + if (!TryComp(bodyPart.Id, out var woundableComp)) + continue; + + var woundableDamage = GetWoundableSeverityPoint(bodyPart.Id, woundableComp, damageGroup, healable); + if (woundableDamage <= biggestDamage) + continue; + + biggestDamage = woundableDamage; + woundable = (bodyPart.Id, woundableComp); + } + + return woundable != null; + } + + public bool HasDamageOfType( + EntityUid woundable, + string damageType) + { + return GetWoundableWounds(woundable).Any(wound => MetaData(wound.Item1).EntityPrototype!.ID == damageType); + } + + public bool HasDamageOfGroup( + EntityUid woundable, + string damageGroup) + { + return GetWoundableWounds(woundable).Any(wound => wound.Item2.DamageGroup == damageGroup); + } + + public FixedPoint2 ApplyHealingRateMultipliers(EntityUid wound, EntityUid woundable, FixedPoint2 severity, WoundableComponent? component = null) + { + if (!Resolve(woundable, ref component)) + return severity; + + var woundHealingMultiplier = + _prototype.Index(MetaData(wound).EntityPrototype!.ID).WoundHealingMultiplier; + + if (component.HealingMultipliers.Count == 0) + return severity * woundHealingMultiplier; + + var toMultiply = + component.HealingMultipliers.Sum(multiplier => (float) multiplier.Value.Change) / component.HealingMultipliers.Count; + return severity * toMultiply * woundHealingMultiplier; + } + + public bool TryAddHealingRateMultiplier(EntityUid owner, EntityUid woundable, string identifier, FixedPoint2 change, WoundableComponent? component = null) + { + if (!Resolve(woundable, ref component) || !_net.IsServer) + return false; + + return component.HealingMultipliers.TryAdd(owner, new WoundableHealingMultiplier(change, identifier)); + } + + public bool TryRemoveHealingRateMultiplier(EntityUid owner, EntityUid woundable, WoundableComponent? component = null) + { + if (!Resolve(woundable, ref component) || !_net.IsServer) + return false; + + return component.HealingMultipliers.Remove(owner); + } + + #endregion +} diff --git a/Content.Shared/Backmen/Surgery/Wounds/Systems/WoundSystem.Wounding.cs b/Content.Shared/Backmen/Surgery/Wounds/Systems/WoundSystem.Wounding.cs new file mode 100644 index 00000000000..2074a2614ac --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Wounds/Systems/WoundSystem.Wounding.cs @@ -0,0 +1,1253 @@ +using System.Linq; +using Content.Shared.Backmen.Surgery.CCVar; +using Content.Shared.Backmen.Surgery.Pain.Components; +using Content.Shared.Backmen.Surgery.Traumas; +using Content.Shared.Backmen.Surgery.Traumas.Components; +using Content.Shared.Backmen.Surgery.Wounds.Components; +using Content.Shared.Backmen.Targeting; +using Content.Shared.Body.Components; +using Content.Shared.Body.Part; +using Content.Shared.Damage; +using Content.Shared.FixedPoint; +using Content.Shared.Gibbing.Events; +using Content.Shared.Humanoid; +using Content.Shared.Inventory; +using Content.Shared.Popups; +using Robust.Shared.Containers; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Shared.Backmen.Surgery.Wounds.Systems; + +public sealed partial class WoundSystem +{ + private const string WoundContainerId = "Wounds"; + private const string BoneContainerId = "Bone"; + + private const string BoneEntityId = "Bone"; + + private void InitWounding() + { + SubscribeLocalEvent(OnWoundableInit); + + SubscribeLocalEvent(OnWoundableInserted); + SubscribeLocalEvent(OnWoundableRemoved); + + SubscribeLocalEvent(OnWoundInserted); + SubscribeLocalEvent(OnWoundRemoved); + + SubscribeLocalEvent(OnWoundableContentsGibAttempt); + + SubscribeLocalEvent(OnWoundSeverityChanged); + SubscribeLocalEvent(OnWoundableSeverityChanged); + + SubscribeLocalEvent(DudeItsJustLikeMatrix); + } + + #region Event Handling + + private void OnWoundableInit(EntityUid uid, WoundableComponent comp, MapInitEvent args) + { + // Set root to itself. + comp.RootWoundable = uid; + + // Create container for wounds. + comp.Wounds = _container.EnsureContainer(uid, WoundContainerId); + comp.Bone = _container.EnsureContainer(uid, BoneContainerId); + + InsertBoneIntoWoundable(uid, comp); + } + + private void OnWoundInserted(EntityUid uid, WoundComponent comp, EntGotInsertedIntoContainerMessage args) + { + if (comp.HoldingWoundable == EntityUid.Invalid) + return; + + var parentWoundable = Comp(comp.HoldingWoundable); + var woundableRoot = Comp(parentWoundable.RootWoundable); + + var ev = new WoundAddedEvent(comp, parentWoundable, woundableRoot); + RaiseLocalEvent(uid, ref ev); + + var ev1 = new WoundAddedEvent(comp, parentWoundable, woundableRoot); + RaiseLocalEvent(comp.HoldingWoundable, ref ev1); + + var bodyPart = Comp(comp.HoldingWoundable); + if (bodyPart.Body.HasValue) + { + var ev2 = new WoundAddedOnBodyEvent(uid, comp, parentWoundable, woundableRoot); + RaiseLocalEvent(bodyPart.Body.Value, ref ev2, true); + } + } + + private void OnWoundRemoved(EntityUid woundableEntity, WoundComponent wound, EntGotRemovedFromContainerMessage args) + { + if (wound.HoldingWoundable == EntityUid.Invalid) + return; + + if (!TryComp(wound.HoldingWoundable, out WoundableComponent? oldParentWoundable) || + !TryComp(oldParentWoundable.RootWoundable, out WoundableComponent? oldWoundableRoot)) + return; + + wound.HoldingWoundable = EntityUid.Invalid; + + var ev = new WoundRemovedEvent(args.Entity, wound, oldParentWoundable, oldWoundableRoot); + RaiseLocalEvent(args.Entity, ref ev); + + var ev2 = new WoundRemovedEvent(args.Entity, wound, oldParentWoundable, oldWoundableRoot); + RaiseLocalEvent(wound.HoldingWoundable, ref ev2, true); + + if (_net.IsServer && !TerminatingOrDeleted(woundableEntity)) + Del(woundableEntity); + } + + private void OnWoundableInserted(EntityUid parentEntity, WoundableComponent parentWoundable, EntInsertedIntoContainerMessage args) + { + if (_net.IsClient || !TryComp(args.Entity, out var childWoundable)) + return; + + InternalAddWoundableToParent(parentEntity, args.Entity, parentWoundable, childWoundable); + } + + private void OnWoundableRemoved(EntityUid parentEntity, WoundableComponent parentWoundable, EntRemovedFromContainerMessage args) + { + if (_net.IsClient || !TryComp(args.Entity, out var childWoundable)) + return; + + InternalRemoveWoundableFromParent(parentEntity, args.Entity, parentWoundable, childWoundable); + } + + private void OnWoundableSeverityChanged(EntityUid uid, WoundableComponent component, WoundableSeverityChangedEvent args) + { + if (args.NewSeverity != WoundableSeverity.Loss || TerminatingOrDeleted(uid)) + return; + + if (IsWoundableRoot(uid, component)) + { + DestroyWoundable(uid, uid, component); + // We can call DestroyWoundable instead of ProcessBodyPartLoss, because the body will be gibbed, and we may not process body part loss. + } + else + { + if (component.ParentWoundable != null && Comp(uid).Body != null) + { + ProcessBodyPartLoss(uid, component.ParentWoundable.Value, component); + } + else + { + // it will be destroyed. + DestroyWoundable(uid, uid, component); + } + } + } + + private void OnWoundableContentsGibAttempt(EntityUid uid, WoundableComponent comp, ref AttemptEntityContentsGibEvent args) + { + args.ExcludedContainers = new List { WoundContainerId, BoneContainerId }; + } + + private void DudeItsJustLikeMatrix(EntityUid uid, WoundableComponent comp, BeforeDamageChangedEvent args) + { + if (!args.CanBeCancelled) + return; + + var chance = comp.DodgeChance; + + var bodyPart = Comp(uid); + if (args.Origin != null) + { + if (bodyPart.Body != null) + { + var bodyTransform = _transform.GetWorldPosition(bodyPart.Body.Value); + var originTransform = _transform.GetWorldPosition(args.Origin.Value); + + var distance = (originTransform - bodyTransform).Length(); + var additionalChance = distance / _cfg.GetCVar(SurgeryCvars.DodgeDistanceChance) * _cfg.GetCVar(SurgeryCvars.DodgeDistanceChange); + + chance += additionalChance; + } + } + + if (!_random.Prob(Math.Clamp((float) chance, 0, 1))) + return; + + if (bodyPart.Body.HasValue) + _popup.PopupEntity(Loc.GetString("woundable-dodged", ("entity", bodyPart.Body.Value)), bodyPart.Body.Value, PopupType.Medium); + + args.Cancelled = true; + } + + private void ProcessBodyPartLoss(EntityUid uid, EntityUid parentUid, WoundableComponent component) + { + var bodyPart = Comp(uid); + if (bodyPart.Body == null) + return; + + foreach (var wound in component.Wounds!.ContainedEntities) + { + Comp(wound).CanBeHealed = false; + + TransferWoundDamage(parentUid, wound, Comp(wound)); + } + + DestroyWoundable(parentUid, uid, component); + } + + private void OnWoundSeverityChanged(EntityUid wound, WoundComponent woundComponent, WoundSeverityChangedEvent args) + { + if (args.NewSeverity != WoundSeverity.Healed || _net.IsClient) + return; + + TryMakeScar(woundComponent); + RemoveWound(wound); + } + + #endregion + + #region Public API + + /// + /// Opens a new wound on a requested woundable. + /// + /// UID of the woundable (body part). + /// Wound prototype. + /// Severity for wound to apply. + /// Damage group. + /// Woundable component. + /// Trauma list to set, if you wanna + public bool TryCreateWound( + EntityUid uid, + string woundProtoId, + FixedPoint2 severity, + string damageGroup, + WoundableComponent? woundable = null, + List? traumaList = null) + { + if (!IsWoundPrototypeValid(woundProtoId) || _net.IsClient) + return false; + + if (!Resolve(uid, ref woundable)) + return false; + + var wound = Spawn(woundProtoId); + + return AddWound(uid, wound, severity, damageGroup, traumaList: traumaList); + } + + /// + /// Continues wound with specific type, if there's any. Adds severity to it basically. + /// + /// Woundable entity's UID. + /// Wound entity's ID. + /// Severity to apply. + /// Woundable for wound to add. + /// Returns true, if wound was continued. + public bool TryContinueWound(EntityUid uid, string id, FixedPoint2 severity, WoundableComponent? woundable = null) + { + if (!IsWoundPrototypeValid(id) || _net.IsClient) + return false; + + if (!Resolve(uid, ref woundable, false)) + return false; + + var proto = _prototype.Index(id); + foreach (var wound in woundable.Wounds!.ContainedEntities) + { + if (proto.ID != MetaData(wound).EntityPrototype!.ID) + continue; + ApplyWoundSeverity(wound, severity); + + return true; + } + + return false; + } + + /// + /// Tries to create a scar on a woundable entity. Takes scar proto from WoundComponent. + /// + /// The WoundComponent representing a specific wound. + public void TryMakeScar(WoundComponent woundComponent) + { + if (_net.IsServer && _random.Prob(_cfg.GetCVar(SurgeryCvars.WoundScarChance)) && woundComponent is { ScarWound: not null, DamageGroup: not null, IsScar: false }) + { + TryCreateWound(woundComponent.HoldingWoundable, woundComponent.ScarWound, 1, woundComponent.DamageGroup); + } + } + + /// + /// Sets severity of a wound. + /// + /// UID of the wound. + /// Severity to set. + /// Wound to which severity is applied. + public void SetWoundSeverity(EntityUid uid, FixedPoint2 severity, WoundComponent? wound = null) + { + if (!Resolve(uid, ref wound) || _net.IsClient) + return; + + var oldBody = (FixedPoint2) 0; + + var bodyPart = Comp(wound.HoldingWoundable); + if (bodyPart.Body.HasValue) + { + var rootPart = Comp(bodyPart.Body.Value).RootContainer.ContainedEntity; + if (rootPart.HasValue) + { + foreach (var (_, woundable) in GetAllWoundableChildren(rootPart.Value)) + { + oldBody = + woundable.Wounds!.ContainedEntities.Aggregate(oldBody, (current, woundId) => current + Comp(woundId).WoundSeverityPoint); + } + } + } + + var old = wound.WoundSeverityPoint; + wound.WoundSeverityPoint = + FixedPoint2.Clamp(ApplySeverityModifiers(wound.HoldingWoundable, severity), 0, _cfg.GetCVar(SurgeryCvars.MaxWoundSeverity)); + + if (wound.WoundSeverityPoint != old) + { + var ev = new WoundSeverityPointChangedEvent(wound, old, wound.WoundSeverityPoint); + RaiseLocalEvent(uid, ref ev); + + var bodySeverity = (FixedPoint2) 0; + + if (bodyPart.Body.HasValue) + { + var rootPart = Comp(bodyPart.Body.Value).RootContainer.ContainedEntity; + if (rootPart.HasValue) + { + foreach (var (_, woundable) in GetAllWoundableChildren(rootPart.Value)) + { + bodySeverity = + woundable.Wounds!.ContainedEntities.Aggregate( + bodySeverity, + (current, woundId) => current + Comp(woundId).WoundSeverityPoint); + } + } + + if (bodySeverity != oldBody) + { + var ev1 = new WoundSeverityPointChangedOnBodyEvent(uid, wound, oldBody, bodySeverity); + RaiseLocalEvent(bodyPart.Body.Value, ref ev1); + } + } + } + + CheckSeverityThresholds(uid, wound); + Dirty(uid, wound); + + UpdateWoundableIntegrity(wound.HoldingWoundable); + CheckWoundableSeverityThresholds(wound.HoldingWoundable); + } + + /// + /// Applies severity to a wound + /// + /// UID of the wound. + /// Severity to add. + /// Wound to which severity is applied. + /// Traumas to apply when applying severity.. Please use _trauma.RandomTraumaChance if you expect your thing to apply traumas. + public void ApplyWoundSeverity( + EntityUid uid, + FixedPoint2 severity, + WoundComponent? wound = null, + IEnumerable? traumaList = null) + { + if (!Resolve(uid, ref wound) || _net.IsClient) + return; + + var oldBody = (FixedPoint2) 0; + + var bodyPart = Comp(wound.HoldingWoundable); + if (bodyPart.Body.HasValue) + { + var rootPart = Comp(bodyPart.Body.Value).RootContainer.ContainedEntity; + if (rootPart.HasValue) + { + foreach (var (_, woundable) in GetAllWoundableChildren(rootPart.Value)) + { + oldBody = + woundable.Wounds!.ContainedEntities.Aggregate(oldBody, (current, woundId) => current + Comp(woundId).WoundSeverityPoint); + } + } + } + + var old = wound.WoundSeverityPoint; + wound.WoundSeverityPoint = severity > 0 + ? FixedPoint2.Clamp(old + ApplySeverityModifiers(wound.HoldingWoundable, severity), 0, _cfg.GetCVar(SurgeryCvars.MaxWoundSeverity)) + : FixedPoint2.Clamp(old + severity, 0, _cfg.GetCVar(SurgeryCvars.MaxWoundSeverity)); + + if (wound.WoundSeverityPoint != old) + { + var ev = new WoundSeverityPointChangedEvent(wound, old, wound.WoundSeverityPoint); + RaiseLocalEvent(uid, ref ev); + + var bodySeverity = (FixedPoint2) 0; + + if (bodyPart.Body.HasValue) + { + var rootPart = Comp(bodyPart.Body.Value).RootContainer.ContainedEntity; + if (rootPart.HasValue) + { + foreach (var (_, woundable) in GetAllWoundableChildren(rootPart.Value)) + { + bodySeverity = + woundable.Wounds!.ContainedEntities.Aggregate( + bodySeverity, + (current, woundId) => current + Comp(woundId).WoundSeverityPoint); + } + } + + if (bodySeverity != oldBody) + { + var ev1 = new WoundSeverityPointChangedOnBodyEvent(uid, wound, oldBody, bodySeverity); + RaiseLocalEvent(bodyPart.Body.Value, ref ev1); + } + } + } + + // if the said wound didn't open with a trauma-inducing effect, we can't make it inflict a trauma.. so yeah + if (wound.CanApplyTrauma && severity > 0) + { + var traumasToApply = traumaList ?? _trauma.RandomTraumaChance(wound.HoldingWoundable, uid, severity); + wound.WoundType = + _trauma.TryApplyTrauma(wound.HoldingWoundable, severity, traumasToApply.ToList()) + ? WoundType.Internal + : WoundType.External; + } + // wounds that cause traumas are separated from those that don't. + + CheckSeverityThresholds(uid, wound); + Dirty(uid, wound); + + UpdateWoundableIntegrity(wound.HoldingWoundable); + CheckWoundableSeverityThresholds(wound.HoldingWoundable); + } + + public FixedPoint2 ApplySeverityModifiers( + EntityUid woundable, + FixedPoint2 severity, + WoundableComponent? component = null) + { + if (!Resolve(woundable, ref component)) + return severity; + + if (component.SeverityMultipliers.Count == 0) + return severity; + + var toMultiply = + component.SeverityMultipliers.Sum(multiplier => (float) multiplier.Value.Change) / component.SeverityMultipliers.Count; + return severity * toMultiply; + } + + /// + /// Applies severity multiplier to a wound. + /// + /// UID of the woundable. + /// UID of the multiplier owner. + /// The severity multiplier itself + /// A string to defy this multiplier from others. + /// Woundable to which severity multiplier is applied. + public bool TryAddWoundableSeverityMultiplier( + EntityUid uid, + EntityUid owner, + FixedPoint2 change, + string identifier, + WoundableComponent? component = null) + { + if (!Resolve(uid, ref component) || !_net.IsServer) + return false; + + if (!component.SeverityMultipliers.TryAdd(owner, new WoundableSeverityMultiplier(change, identifier))) + return false; + + foreach (var wound in component.Wounds!.ContainedEntities) + { + CheckSeverityThresholds(wound); + } + + UpdateWoundableIntegrity(uid, component); + CheckWoundableSeverityThresholds(uid, component); + + return true; + } + + /// + /// Removes a multiplier from a woundable. + /// + /// UID of the woundable. + /// Identifier of the said multiplier. + /// Woundable to which severity multiplier is applied. + public bool TryRemoveWoundableSeverityMultiplier( + EntityUid uid, + string identifier, + WoundableComponent? component = null) + { + if (!Resolve(uid, ref component) || !_net.IsServer) + return false; + + foreach (var multiplier in component.SeverityMultipliers.Where(multiplier => multiplier.Value.Identifier == identifier)) + { + if (!component.SeverityMultipliers.Remove(multiplier.Key, out _)) + return false; + + foreach (var wound in component.Wounds!.ContainedEntities) + { + CheckSeverityThresholds(wound); + } + + UpdateWoundableIntegrity(uid, component); + CheckWoundableSeverityThresholds(uid, component); + + return true; + } + + return false; + } + + /// + /// Changes a multiplier's change in a specified woundable. + /// + /// UID of the woundable. + /// Identifier of the said multiplier. + /// The new multiplier fixed point. + /// Woundable to which severity multiplier is applied. + public bool TryChangeWoundableSeverityMultiplier( + EntityUid uid, + string identifier, + FixedPoint2 change, + WoundableComponent? component = null) + { + if (!Resolve(uid, ref component) || !_net.IsServer) + return false; + + foreach (var multiplier in component.SeverityMultipliers.Where(multiplier => multiplier.Value.Identifier == identifier).ToList()) + { + component.SeverityMultipliers.Remove(multiplier.Key, out var value); + + value.Change = change; + component.SeverityMultipliers.Add(multiplier.Key, value); + + foreach (var wound in component.Wounds!.ContainedEntities.ToList()) + { + CheckSeverityThresholds(wound); + } + + UpdateWoundableIntegrity(uid, component); + + return true; + } + + return false; + } + + /// + /// Destroys an entity's body part if conditions are met. + /// + /// Parent of the woundable entity. Yes. + /// The entity containing the vulnerable body part + /// Woundable component of woundableEntity. + public void DestroyWoundable(EntityUid parentWoundableEntity, EntityUid woundableEntity, WoundableComponent woundableComp) + { + var bodyPart = Comp(woundableEntity); + if (bodyPart.Body == null) + { + QueueDel(woundableEntity); + // TODO: Some cool effect when the limb gets destroyed + } + else + { + var key = bodyPart.ToHumanoidLayers(); + if (key == null) + return; + + // if wounds amount somehow changes it triggers an enumeration error. owch + woundableComp.AllowWounds = false; + woundableComp.WoundableSeverity = WoundableSeverity.Loss; + + if (TryComp(bodyPart.Body.Value, out var targeting) && _net.IsServer) + { + targeting.BodyStatus = GetWoundableStatesOnBodyPainFeels(bodyPart.Body.Value); + Dirty(bodyPart.Body.Value, targeting); + + RaiseNetworkEvent(new TargetIntegrityChangeEvent(GetNetEntity(bodyPart.Body.Value)), bodyPart.Body.Value); + } + + Dirty(woundableEntity, woundableComp); + + _audio.PlayPvs(woundableComp.WoundableDestroyedSound, bodyPart.Body.Value); + _appearance.SetData(woundableEntity, + WoundableVisualizerKeys.Wounds, + new WoundVisualizerGroupData(GetWoundableWounds(woundableEntity).Select(ent => GetNetEntity(ent.Item1)).ToList())); + + if (IsWoundableRoot(woundableEntity, woundableComp)) + { + DestroyWoundableChildren(woundableEntity, woundableComp); + _body.GibBody(bodyPart.Body.Value); + + QueueDel(woundableEntity); // More blood for the blood God! + } + else + { + if (!_container.TryGetContainingContainer(parentWoundableEntity, woundableEntity, out var container)) + return; + + if (bodyPart.Body is not null + && TryComp(bodyPart.Body, out var inventory) // Prevent error for non-humanoids + && _body.GetBodyPartCount(bodyPart.Body.Value, bodyPart.PartType) == 1 + && _body.TryGetPartSlotContainerName(bodyPart.PartType, out var containerNames)) + { + foreach (var containerName in containerNames) + { + _inventory.DropSlotContents(bodyPart.Body.Value, containerName, inventory); + } + } + var bodyPartId = container.ID; + + DestroyWoundableChildren(woundableEntity, woundableComp); + + _body.DetachPart(parentWoundableEntity, bodyPartId.Remove(0, 15), woundableEntity); + QueueDel(woundableEntity); + } + } + } + + /// + /// Amputates (not destroys) an entity's body part if conditions are met. + /// + /// Parent of the woundable entity. Yes. + /// The entity containing the vulnerable body part + /// Woundable component of woundableEntity. + public void AmputateWoundable(EntityUid parentWoundableEntity, EntityUid woundableEntity, WoundableComponent? woundableComp = null) + { + if (!Resolve(woundableEntity, ref woundableComp)) + return; + + var bodyPart = Comp(parentWoundableEntity); + if (!bodyPart.Body.HasValue) + return; + + AmputateWoundableSafely(parentWoundableEntity, woundableEntity); + + _audio.PlayPvs(woundableComp.WoundableDelimbedSound, bodyPart.Body.Value); + _throwing.TryThrow(woundableEntity, _random.NextAngle().ToWorldVec() * 7f, _random.Next(8, 24)); + } + + /// + /// Does whatever AmputateWoundable does, but does it without pain and the other mess. + /// + /// Parent of the woundable entity. Yes. + /// The entity containing the vulnerable body part + /// Woundable component of woundableEntity. + public void AmputateWoundableSafely(EntityUid parentWoundableEntity, + EntityUid woundableEntity, + WoundableComponent? woundableComp = null) + { + if (!Resolve(woundableEntity, ref woundableComp)) + return; + + var bodyPart = Comp(parentWoundableEntity); + if (!bodyPart.Body.HasValue) + return; + + if (!_container.TryGetContainingContainer(parentWoundableEntity, woundableEntity, out var container)) + return; + + foreach (var wound in woundableComp.Wounds!.ContainedEntities) + { + Comp(wound).CanBeHealed = false; + } + + var bodyPartId = container.ID; + woundableComp.WoundableSeverity = WoundableSeverity.Loss; + + if (TryComp(bodyPart.Body.Value, out var targeting) && _net.IsServer) + { + targeting.BodyStatus = GetWoundableStatesOnBodyPainFeels(bodyPart.Body.Value); + Dirty(bodyPart.Body.Value, targeting); + + RaiseNetworkEvent(new TargetIntegrityChangeEvent(GetNetEntity(bodyPart.Body.Value)), bodyPart.Body.Value); + } + + if (bodyPart.Body is not null + && TryComp(bodyPart.Body, out var inventory) // Prevent error for non-humanoids + && _body.GetBodyPartCount(bodyPart.Body.Value, bodyPart.PartType) == 1 + && _body.TryGetPartSlotContainerName(bodyPart.PartType, out var containerNames)) + { + foreach (var containerName in containerNames) + { + _inventory.DropSlotContents(bodyPart.Body.Value, containerName, inventory); + } + } + + Dirty(woundableEntity, woundableComp); + _appearance.SetData(woundableEntity, + WoundableVisualizerKeys.Wounds, + new WoundVisualizerGroupData(GetWoundableWounds(woundableEntity).Select(ent => GetNetEntity(ent.Item1)).ToList())); + + // Still does the funny popping, if the children are critted. for the funny :3 + DestroyWoundableChildren(woundableEntity, woundableComp); + _body.DetachPart(parentWoundableEntity, bodyPartId.Remove(0, 15), woundableEntity); + } + + #endregion + + #region Private API + + private void InsertBoneIntoWoundable(EntityUid uid, WoundableComponent? comp = null) + { + if (!Resolve(uid, ref comp, false) || _net.IsClient) + return; + + var bone = Spawn(BoneEntityId); + if (!TryComp(bone, out var boneComp)) + return; + + _transform.SetParent(bone, uid); + _container.Insert(bone, comp.Bone!); + + boneComp.BoneWoundable = uid; + } + + private void TransferWoundDamage(EntityUid parent, EntityUid wound, WoundComponent woundComp, WoundableComponent? woundableComp = null) + { + if (!Resolve(parent, ref woundableComp)) + return; + + if (!TryContinueWound( + parent, + MetaData(wound).EntityPrototype!.ID, + woundComp.WoundSeverityPoint * _cfg.GetCVar(SurgeryCvars.WoundTransferPart), + woundableComp)) + { + TryCreateWound( + parent, + MetaData(wound).EntityPrototype!.ID, + woundComp.WoundSeverityPoint * _cfg.GetCVar(SurgeryCvars.WoundTransferPart), + woundComp.DamageGroup!, + woundableComp); + } + } + + private void UpdateWoundableIntegrity(EntityUid uid, WoundableComponent? component = null) + { + if (!Resolve(uid, ref component, false)) + return; + + // Ignore scars for woundable integrity.. Unless you want to confuse people with minor woundable state + var damage = component.Wounds!.ContainedEntities.Where(wound => !Comp(wound).IsScar) + .Aggregate((FixedPoint2) 0, + (current, wound) + => current + Comp(wound).WoundSeverityPoint * Comp(wound).WoundableIntegrityMultiplier); + + var newIntegrity = FixedPoint2.Clamp(component.IntegrityCap - damage, 0, component.IntegrityCap); + if (newIntegrity == component.WoundableIntegrity) + return; + + component.WoundableIntegrity = newIntegrity; + Dirty(uid, component); + + var ev = new WoundableIntegrityChangedEvent(uid, component.WoundableIntegrity); + RaiseLocalEvent(uid, ref ev); + } + + protected bool AddWound( + EntityUid target, + EntityUid wound, + FixedPoint2 woundSeverity, + string damageGroup, + WoundableComponent? woundableComponent = null, + WoundComponent? woundComponent = null, + List? traumaList = null) + { + if (!Resolve(target, ref woundableComponent) + || !Resolve(wound, ref woundComponent) + || woundableComponent.Wounds!.Contains(wound)) + return false; + + if (!woundableComponent.AllowWounds) + return false; + + _transform.SetParent(wound, target); + woundComponent.HoldingWoundable = target; + woundComponent.DamageGroup = damageGroup; + + if (!_container.Insert(wound, woundableComponent.Wounds)) + return false; + + SetWoundSeverity(wound, woundSeverity, woundComponent); + if (woundComponent.CanApplyTrauma) + { + var traumasToApply = traumaList ?? _trauma.RandomTraumaChance(target, wound, woundSeverity, woundableComponent); + woundComponent.WoundType = + _trauma.TryApplyTrauma(target, woundSeverity, traumasToApply.ToList()) + ? WoundType.Internal + : WoundType.External; + } + + var woundMeta = MetaData(wound); + var targetMeta = MetaData(target); + + _sawmill.Info($"Wound: {woundMeta.EntityPrototype!.ID}({wound}) created on {targetMeta.EntityPrototype!.ID}({target})"); + + Dirty(wound, woundComponent); + Dirty(target, woundableComponent); + + return true; + } + + protected bool RemoveWound(EntityUid woundEntity, WoundComponent? wound = null) + { + if (!Resolve(woundEntity, ref wound, false) + || !TryComp(wound.HoldingWoundable, out WoundableComponent? woundable) + || woundable.Wounds == null) + return false; + + _sawmill.Info($"Wound: {MetaData(woundEntity).EntityPrototype!.ID}({woundEntity}) removed on {MetaData(wound.HoldingWoundable).EntityPrototype!.ID}({wound.HoldingWoundable})"); + + UpdateWoundableIntegrity(wound.HoldingWoundable, woundable); + CheckWoundableSeverityThresholds(wound.HoldingWoundable, woundable); + + Dirty(wound.HoldingWoundable, woundable); + + return _container.Remove(woundEntity, woundable.Wounds); + } + + protected void InternalAddWoundableToParent( + EntityUid parentEntity, + EntityUid childEntity, + WoundableComponent parentWoundable, + WoundableComponent childWoundable) + { + parentWoundable.ChildWoundables.Add(childEntity); + childWoundable.ParentWoundable = parentEntity; + childWoundable.RootWoundable = parentWoundable.RootWoundable; + + FixWoundableRoots(childEntity, childWoundable); + + var woundableRoot = Comp(parentWoundable.RootWoundable); + var woundableAttached = new WoundableAttachedEvent(parentEntity, parentWoundable); + + RaiseLocalEvent(childEntity, ref woundableAttached, true); + + foreach (var (woundId, wound) in GetAllWounds(childEntity, childWoundable)) + { + var ev = new WoundAddedEvent(wound, parentWoundable, woundableRoot); + RaiseLocalEvent(woundId, ref ev); + + var bodyPart = Comp(childEntity); + if (bodyPart.Body.HasValue) + { + var ev2 = new WoundAddedOnBodyEvent(woundId, wound, parentWoundable, woundableRoot); + RaiseLocalEvent(bodyPart.Body.Value, ref ev2, true); + } + } + + Dirty(childEntity, childWoundable); + } + + protected void InternalRemoveWoundableFromParent( + EntityUid parentEntity, + EntityUid childEntity, + WoundableComponent parentWoundable, + WoundableComponent childWoundable) + { + if (TerminatingOrDeleted(childEntity) || TerminatingOrDeleted(parentEntity)) + return; + + parentWoundable.ChildWoundables.Remove(childEntity); + childWoundable.ParentWoundable = null; + childWoundable.RootWoundable = childEntity; + + FixWoundableRoots(childEntity, childWoundable); + + var oldWoundableRoot = Comp(parentWoundable.RootWoundable); + var woundableDetached = new WoundableDetachedEvent(parentEntity, parentWoundable); + + RaiseLocalEvent(childEntity, ref woundableDetached, true); + + foreach (var (woundId, wound) in GetAllWounds(childEntity, childWoundable)) + { + var ev = new WoundRemovedEvent(woundId, wound, childWoundable, oldWoundableRoot); + RaiseLocalEvent(woundId, ref ev); + + var ev2 = new WoundRemovedEvent(woundId, wound, childWoundable, oldWoundableRoot); + RaiseLocalEvent(childWoundable.RootWoundable, ref ev2, true); + } + + Dirty(childEntity, childWoundable); + } + + private void FixWoundableRoots(EntityUid targetEntity, WoundableComponent targetWoundable) + { + if (targetWoundable.ChildWoundables.Count == 0) + return; + + foreach (var (childEntity, childWoundable) in GetAllWoundableChildren(targetEntity, targetWoundable)) + { + childWoundable.RootWoundable = targetWoundable.RootWoundable; + Dirty(childEntity, childWoundable); + } + + Dirty(targetEntity, targetWoundable); + } + + private void CheckSeverityThresholds(EntityUid wound, WoundComponent? component = null) + { + if (!Resolve(wound, ref component) || !_net.IsServer) + return; + + var nearestSeverity = component.WoundSeverity; + foreach (var (severity, value) in _woundThresholds.OrderByDescending(kv => kv.Value)) + { + if (component.WoundSeverityPoint < value) + continue; + + if (severity == WoundSeverity.Healed && component.WoundSeverityPoint > 0) + continue; + + nearestSeverity = severity; + break; + } + + if (nearestSeverity != component.WoundSeverity) + { + var ev = new WoundSeverityChangedEvent(wound, nearestSeverity); + RaiseLocalEvent(wound, ref ev, true); + } + component.WoundSeverity = nearestSeverity; + + Dirty(wound, component); + + if (!TerminatingOrDeleted(component.HoldingWoundable)) + { + _appearance.SetData(component.HoldingWoundable, + WoundableVisualizerKeys.Wounds, + new WoundVisualizerGroupData(GetWoundableWounds(component.HoldingWoundable).Select(ent => GetNetEntity(ent.Item1)).ToList())); + } + } + + private void CheckWoundableSeverityThresholds(EntityUid woundable, WoundableComponent? component = null) + { + if (!Resolve(woundable, ref component, false) || !_net.IsServer) + return; + + var nearestSeverity = component.WoundableSeverity; + foreach (var (severity, value) in component.Thresholds.OrderByDescending(kv => kv.Value)) + { + if (component.WoundableIntegrity >= component.IntegrityCap) + { + nearestSeverity = WoundableSeverity.Healthy; + break; + } + + if (component.WoundableIntegrity < value) + continue; + + nearestSeverity = severity; + break; + } + + if (nearestSeverity != component.WoundableSeverity) + { + var ev = new WoundableSeverityChangedEvent(woundable, nearestSeverity); + RaiseLocalEvent(woundable, ref ev, true); + } + component.WoundableSeverity = nearestSeverity; + + Dirty(woundable, component); + + var bodyPart = Comp(woundable); + if (bodyPart.Body == null) + return; + + if (TryComp(bodyPart.Body.Value, out var targeting)) + { + targeting.BodyStatus = GetWoundableStatesOnBodyPainFeels(bodyPart.Body.Value); + Dirty(bodyPart.Body.Value, targeting); + + RaiseNetworkEvent(new TargetIntegrityChangeEvent(GetNetEntity(bodyPart.Body.Value)), bodyPart.Body.Value); + } + + _appearance.SetData(woundable, + WoundableVisualizerKeys.Wounds, + new WoundVisualizerGroupData(GetWoundableWounds(woundable).Select(ent => GetNetEntity(ent.Item1)).ToList())); + } + + #endregion + + #region Helpers + + /// + /// Validates the wound prototype based on the given prototype ID. + /// Checks if the specified prototype ID corresponds to a valid EntityPrototype in the collection, + /// ensuring it contains the necessary WoundComponent. + /// + /// The prototype ID to be validated. + /// True if the wound prototype is valid, otherwise false. + private bool IsWoundPrototypeValid(string protoId) + { + return _prototype.TryIndex(protoId, out var woundPrototype) + && woundPrototype.TryGetComponent(out _, _factory); + } + + private void DestroyWoundableChildren(EntityUid woundableEntity, WoundableComponent? woundableComp = null) + { + if (!Resolve(woundableEntity, ref woundableComp)) + return; + + foreach (var child in woundableComp.ChildWoundables) + { + var childWoundable = Comp(child); + if (childWoundable.WoundableSeverity is WoundableSeverity.Critical) + { + DestroyWoundable(woundableEntity, child, childWoundable); + continue; + } + + AmputateWoundable(woundableEntity, child, childWoundable); + } + } + + public Dictionary GetWoundableStatesOnBody(EntityUid body) + { + var result = new Dictionary(); + + foreach (var part in SharedTargetingSystem.GetValidParts()) + { + result[part] = WoundableSeverity.Loss; + } + + foreach (var (id, bodyPart) in _body.GetBodyChildren(body)) + { + var target = _body.GetTargetBodyPart(bodyPart); + if (target == null) + continue; + + if (!TryComp(id, out var woundable)) + continue; + + result[target.Value] = woundable.WoundableSeverity; + } + + return result; + } + + public Dictionary GetWoundableStatesOnBodyPainFeels(EntityUid body) + { + var result = new Dictionary(); + + foreach (var part in SharedTargetingSystem.GetValidParts()) + { + result[part] = WoundableSeverity.Loss; + } + + foreach (var (id, bodyPart) in _body.GetBodyChildren(body)) + { + var target = _body.GetTargetBodyPart(bodyPart); + if (target == null) + continue; + + if (!TryComp(id, out var woundable) || !TryComp(id, out var nerve)) + continue; + + var damageFeeling = woundable.WoundableIntegrity * nerve.PainFeels; + + var nearestSeverity = woundable.WoundableSeverity; + foreach (var (severity, value) in woundable.Thresholds.OrderByDescending(kv => kv.Value)) + { + if (damageFeeling >= woundable.IntegrityCap) + { + nearestSeverity = WoundableSeverity.Healthy; + break; + } + + if (damageFeeling < value) + continue; + + nearestSeverity = severity; + break; + } + + result[target.Value] = nearestSeverity; + } + + return result; + } + + /// + /// Check if this woundable is root + /// + /// Owner of the woundable + /// woundable component + /// true if the woundable is the root of the hierarchy + public bool IsWoundableRoot(EntityUid woundableEntity, WoundableComponent? woundable = null) + { + return Resolve(woundableEntity, ref woundable) && woundable.RootWoundable == woundableEntity; + } + + /// + /// Retrieves all wounds associated with a specified entity. + /// + /// The UID of the target entity. + /// Optional: The WoundableComponent of the target entity. + /// An enumerable collection of tuples containing EntityUid and WoundComponent pairs. + public IEnumerable<(EntityUid, WoundComponent)> GetAllWounds(EntityUid targetEntity, + WoundableComponent? targetWoundable = null) + { + if (!Resolve(targetEntity, ref targetWoundable)) + yield break; + + foreach (var (_, childWoundable) in GetAllWoundableChildren(targetEntity, targetWoundable)) + { + foreach (var woundEntity in childWoundable.Wounds!.ContainedEntities) + { + yield return (woundEntity, Comp(woundEntity)); + } + } + } + + /// + /// Gets all woundable children of a specified woundable + /// + /// Owner of the woundable + /// + /// Enumerable to the found children + public IEnumerable<(EntityUid, WoundableComponent)> GetAllWoundableChildren(EntityUid targetEntity, + WoundableComponent? targetWoundable = null) + { + if (!Resolve(targetEntity, ref targetWoundable)) + yield break; + + foreach (var childEntity in targetWoundable.ChildWoundables) + { + if (!TryComp(childEntity, out WoundableComponent? childWoundable)) + continue; + foreach (var value in GetAllWoundableChildren(childEntity, childWoundable)) + { + yield return value; + } + } + + yield return (targetEntity, targetWoundable); + } + + /// + /// Parents a woundable to another + /// + /// Owner of the new parent + /// Owner of the woundable we want to attach + /// The new parent woundable component + /// The woundable we are attaching + /// true if successful + public bool AddWoundableToParent( + EntityUid parentEntity, + EntityUid childEntity, + WoundableComponent? parentWoundable = null, + WoundableComponent? childWoundable = null) + { + if (!Resolve(parentEntity, ref parentWoundable) || _net.IsClient + || !Resolve(childEntity, ref childWoundable) || childWoundable.ParentWoundable == null) + return false; + + InternalAddWoundableToParent(parentEntity, childEntity, parentWoundable, childWoundable); + return true; + } + + /// + /// Removes a woundable from its parent (if present) + /// + /// Owner of the parent woundable + /// Owner of the child woundable + /// + /// + /// true if successful + public bool RemoveWoundableFromParent( + EntityUid parentEntity, + EntityUid childEntity, + WoundableComponent? parentWoundable = null, + WoundableComponent? childWoundable = null) + { + if (!Resolve(parentEntity, ref parentWoundable) || _net.IsClient + || !Resolve(childEntity, ref childWoundable) || childWoundable.ParentWoundable == null) + return false; + + InternalRemoveWoundableFromParent(parentEntity, childEntity, parentWoundable, childWoundable); + return true; + } + + + /// + /// Finds all children of a specified woundable that have a specific component + /// + /// + /// + /// the type of the component we want to find + /// Enumerable to the found children + public IEnumerable<(EntityUid, WoundableComponent, T)> GetAllWoundableChildrenWithComp(EntityUid targetEntity, + WoundableComponent? targetWoundable = null) where T: Component, new() + { + if (!Resolve(targetEntity, ref targetWoundable)) + yield break; + + foreach (var childEntity in targetWoundable.ChildWoundables) + { + if (!TryComp(childEntity, out WoundableComponent? childWoundable)) + continue; + + foreach (var value in GetAllWoundableChildrenWithComp(childEntity, childWoundable)) + { + yield return value; + } + } + + if (!TryComp(targetEntity, out T? foundComp)) + yield break; + + yield return (targetEntity, targetWoundable,foundComp); + } + + /// + /// Get the wounds present on a specific woundable + /// + /// Entity that owns the woundable + /// Woundable component + /// An enumerable pointing to one of the found wounds + public IEnumerable<(EntityUid, WoundComponent)> GetWoundableWounds(EntityUid targetEntity, + WoundableComponent? targetWoundable = null) + { + if (!Resolve(targetEntity, ref targetWoundable) || targetWoundable.Wounds!.Count == 0) + yield break; + + foreach (var woundEntity in targetWoundable.Wounds!.ContainedEntities) + { + yield return (woundEntity, Comp(woundEntity)); + } + } + + public FixedPoint2 GetWoundableSeverityPoint( + EntityUid targetEntity, + WoundableComponent? targetWoundable = null, + string? damageGroup = null, + bool healable = false) + { + if (!Resolve(targetEntity, ref targetWoundable) || targetWoundable.Wounds!.Count == 0) + return 0; + + if (healable) + { + return GetWoundableWounds(targetEntity, targetWoundable) + .Where(wound => wound.Item2.DamageGroup == damageGroup || damageGroup == null) + .Where(wound => wound.Item2.CanBeHealed) + .Aggregate((FixedPoint2) 0, (current, wound) => current + wound.Item2.WoundSeverityPoint); + } + + return GetWoundableWounds(targetEntity, targetWoundable) + .Where(wound => wound.Item2.DamageGroup == damageGroup || damageGroup == null) + .Aggregate((FixedPoint2) 0, (current, wound) => current + wound.Item2.WoundSeverityPoint); + } + + #endregion +} diff --git a/Content.Shared/Backmen/Surgery/Wounds/Systems/WoundSystem.cs b/Content.Shared/Backmen/Surgery/Wounds/Systems/WoundSystem.cs new file mode 100644 index 00000000000..ad1153ffe9d --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Wounds/Systems/WoundSystem.cs @@ -0,0 +1,75 @@ +using Content.Shared.Backmen.Surgery.CCVar; +using Content.Shared.Backmen.Surgery.Traumas.Systems; +using Content.Shared.Backmen.Surgery.Wounds.Components; +using Content.Shared.Body.Systems; +using Content.Shared.Inventory; +using Content.Shared.Popups; +using Content.Shared.Throwing; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Configuration; +using Robust.Shared.Containers; +using Robust.Shared.Network; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Robust.Shared.Timing; + +namespace Content.Shared.Backmen.Surgery.Wounds.Systems; + +[Virtual] +public partial class WoundSystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly IComponentFactory _factory = default!; + + [Dependency] private readonly IRobustRandom _random = default!; + + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + [Dependency] private readonly SharedBodySystem _body = default!; + + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + + [Dependency] private readonly SharedAudioSystem _audio = default!; + + // I'm the one.... who throws........ + [Dependency] private readonly ThrowingSystem _throwing = default!; + [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly TraumaSystem _trauma = default!; + + private ISawmill _sawmill = default!; + + public override void Initialize() + { + base.Initialize(); + + _sawmill = Logger.GetSawmill("wounds"); + + InitWounding(); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + _woundableJobQueue.Process(); + + if (!_timing.IsFirstTimePredicted) + return; + + var timeToHeal = 1 / _cfg.GetCVar(SurgeryCvars.MedicalHealingTickrate); + using var query = EntityQueryEnumerator(); + while (query.MoveNext(out var ent, out var woundable)) + { + woundable.HealingRateAccumulated += frameTime; + if (woundable.HealingRateAccumulated < timeToHeal) + continue; + + woundable.HealingRateAccumulated -= timeToHeal; + _woundableJobQueue.EnqueueJob(new IntegrityJob(this, (ent, woundable), WoundableJobTime)); + } + } +} diff --git a/Content.Shared/Backmen/Surgery/Wounds/WoundsSerializable.cs b/Content.Shared/Backmen/Surgery/Wounds/WoundsSerializable.cs new file mode 100644 index 00000000000..14a24598612 --- /dev/null +++ b/Content.Shared/Backmen/Surgery/Wounds/WoundsSerializable.cs @@ -0,0 +1,107 @@ +using Content.Shared.Backmen.Surgery.Wounds.Components; +using Content.Shared.FixedPoint; +using Robust.Shared.Serialization; + +namespace Content.Shared.Backmen.Surgery.Wounds; + +[Serializable, NetSerializable] +public enum WoundType +{ + External, + Internal, +} + +[Serializable, NetSerializable] +public enum WoundSeverity +{ + Healed, + Minor, + Moderate, + Severe, + Critical, + Loss, +} + +[Serializable, NetSerializable] +public enum BleedingSeverity +{ + Minor, + Severe, +} + +[Serializable, NetSerializable] +public enum WoundableSeverity : byte +{ + Healthy, + Minor, + Moderate, + Severe, + Critical, + Loss, +} + +[Serializable, NetSerializable] +public enum WoundVisibility +{ + Always, + HandScanner, + AdvancedScanner, +} + +[Serializable, NetSerializable] +public enum WoundableVisualizerKeys +{ + Wounds, +} + +[Serializable, NetSerializable] +public sealed class WoundVisualizerGroupData : ICloneable +{ + public List GroupList; + + public WoundVisualizerGroupData(List groupList) + { + GroupList = groupList; + } + + public object Clone() + { + return new WoundVisualizerGroupData(new List(GroupList)); + } +} + +[ByRefEvent] +public record struct WoundAddedEvent(WoundComponent Component, WoundableComponent Woundable, WoundableComponent RootWoundable); + +[ByRefEvent] +public record struct WoundAddedOnBodyEvent(EntityUid WoundEntity, WoundComponent Component, WoundableComponent Woundable, WoundableComponent RootWoundable); + +[ByRefEvent] +public record struct WoundRemovedEvent(EntityUid WoundEntity, WoundComponent Component, WoundableComponent OldWoundable, WoundableComponent OldRootWoundable); + +[ByRefEvent] +public record struct WoundableAttachedEvent(EntityUid ParentWoundableEntity, WoundableComponent Component); + +[ByRefEvent] +public record struct WoundableDetachedEvent(EntityUid ParentWoundableEntity, WoundableComponent Component); + +[ByRefEvent] +public record struct WoundSeverityPointChangedEvent(WoundComponent Component, FixedPoint2 OldSeverity, FixedPoint2 NewSeverity); + +[ByRefEvent] +public record struct WoundSeverityPointChangedOnBodyEvent(EntityUid WoundEntity, WoundComponent Component, FixedPoint2 OldSeverity, FixedPoint2 NewSeverity); + +[ByRefEvent] +public record struct WoundSeverityChangedEvent(EntityUid WoundEntity, WoundSeverity NewSeverity); + +[ByRefEvent] +public record struct WoundableIntegrityChangedEvent(EntityUid Woundable, FixedPoint2 CurrentIntegrity); + +[ByRefEvent] +public record struct WoundableSeverityChangedEvent(EntityUid Woundable, WoundableSeverity NewSeverity); + +[Serializable, DataRecord] +public record struct WoundableSeverityMultiplier(FixedPoint2 Change, string Identifier = "Unspecified"); + +[Serializable, DataRecord] +public record struct WoundableHealingMultiplier(FixedPoint2 Change, string Identifier = "Unspecified"); diff --git a/Content.Shared/Backmen/Targeting/SharedTargetingSystem.cs b/Content.Shared/Backmen/Targeting/SharedTargetingSystem.cs index 2cdd3018520..a850c9714a8 100644 --- a/Content.Shared/Backmen/Targeting/SharedTargetingSystem.cs +++ b/Content.Shared/Backmen/Targeting/SharedTargetingSystem.cs @@ -1,3 +1,5 @@ +using Content.Shared.Humanoid; + namespace Content.Shared.Backmen.Targeting; public abstract class SharedTargetingSystem : EntitySystem @@ -10,8 +12,8 @@ public static TargetBodyPart[] GetValidParts() var parts = new[] { TargetBodyPart.Head, - TargetBodyPart.Torso, - //TargetBodyPart.Groin, + TargetBodyPart.Chest, + TargetBodyPart.Groin, TargetBodyPart.LeftArm, TargetBodyPart.LeftHand, TargetBodyPart.LeftLeg, @@ -24,4 +26,35 @@ public static TargetBodyPart[] GetValidParts() return parts; } + + public static HumanoidVisualLayers ToVisualLayers(TargetBodyPart targetBodyPart) + { + switch (targetBodyPart) + { + case TargetBodyPart.Head: + return HumanoidVisualLayers.Head; + case TargetBodyPart.Chest: + return HumanoidVisualLayers.Chest; + case TargetBodyPart.Groin: + return HumanoidVisualLayers.Groin; + case TargetBodyPart.LeftArm: + return HumanoidVisualLayers.LArm; + case TargetBodyPart.LeftHand: + return HumanoidVisualLayers.LHand; + case TargetBodyPart.RightArm: + return HumanoidVisualLayers.RArm; + case TargetBodyPart.RightHand: + return HumanoidVisualLayers.RHand; + case TargetBodyPart.LeftLeg: + return HumanoidVisualLayers.LLeg; + case TargetBodyPart.LeftFoot: + return HumanoidVisualLayers.LFoot; + case TargetBodyPart.RightLeg: + return HumanoidVisualLayers.RLeg; + case TargetBodyPart.RightFoot: + return HumanoidVisualLayers.RFoot; + default: + return HumanoidVisualLayers.Chest; + } + } } diff --git a/Content.Shared/Backmen/Targeting/TargetBodyPart.cs b/Content.Shared/Backmen/Targeting/TargetBodyPart.cs index b00306d95a1..014c3498dd3 100644 --- a/Content.Shared/Backmen/Targeting/TargetBodyPart.cs +++ b/Content.Shared/Backmen/Targeting/TargetBodyPart.cs @@ -11,7 +11,7 @@ namespace Content.Shared.Backmen.Targeting; public enum TargetBodyPart : ushort { Head = 1, - Torso = 1 << 1, + Chest = 1 << 1, Groin = 1 << 2, LeftArm = 1 << 3, LeftHand = 1 << 4, @@ -35,7 +35,8 @@ public enum TargetBodyPart : ushort FullArms = Arms | Hands, FullLegs = Feet | Legs, - BodyMiddle = Torso | Groin | FullArms, + BodyMiddle = Chest | Groin | FullArms, + FullLegsGroin = FullLegs | Groin, - All = Head | Torso | Groin | LeftArm | LeftHand | RightArm | RightHand | LeftLeg | LeftFoot | RightLeg | RightFoot, + All = Head | Chest | Groin | LeftArm | LeftHand | RightArm | RightHand | LeftLeg | LeftFoot | RightLeg | RightFoot, } diff --git a/Content.Shared/Backmen/Targeting/TargetIntegrity.cs b/Content.Shared/Backmen/Targeting/TargetIntegrity.cs deleted file mode 100644 index b87720da06e..00000000000 --- a/Content.Shared/Backmen/Targeting/TargetIntegrity.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Content.Shared.Backmen.Targeting; -public enum TargetIntegrity -{ - Healthy = 0, - LightlyWounded = 1, - SomewhatWounded = 2, - ModeratelyWounded = 3, - HeavilyWounded = 4, - CriticallyWounded = 5, - Severed = 6, - Dead = 7, - Disabled = 8, -} diff --git a/Content.Shared/Backmen/Targeting/TargetingComponent.cs b/Content.Shared/Backmen/Targeting/TargetingComponent.cs index 6a2b5b61de4..cc62e805ac2 100644 --- a/Content.Shared/Backmen/Targeting/TargetingComponent.cs +++ b/Content.Shared/Backmen/Targeting/TargetingComponent.cs @@ -1,4 +1,6 @@ +using Content.Shared.Backmen.Surgery.Wounds; using Robust.Shared.GameStates; +using SixLabors.ImageSharp.Formats.Tiff.Constants; namespace Content.Shared.Backmen.Targeting; @@ -9,44 +11,123 @@ namespace Content.Shared.Backmen.Targeting; public sealed partial class TargetingComponent : Component { [ViewVariables, AutoNetworkedField] - public TargetBodyPart Target = TargetBodyPart.Torso; + public TargetBodyPart Target = TargetBodyPart.Chest; /// - /// What odds does the entity have of targeting each body part? + /// What odds are there for every part targeted to be hit? /// [DataField] - public Dictionary TargetOdds = new() + public Dictionary> TargetOdds = new() { - { TargetBodyPart.Head, 0.1f }, - { TargetBodyPart.Torso, 0.3f }, - { TargetBodyPart.Groin, 0.1f }, - { TargetBodyPart.LeftArm, 0.1f }, - { TargetBodyPart.LeftHand, 0.05f }, - { TargetBodyPart.RightArm, 0.1f }, - { TargetBodyPart.RightHand, 0.05f }, - { TargetBodyPart.LeftLeg, 0.1f }, - { TargetBodyPart.LeftFoot, 0.05f }, - { TargetBodyPart.RightLeg, 0.1f }, - { TargetBodyPart.RightFoot, 0.05f } + { + TargetBodyPart.Head, new Dictionary + { + { TargetBodyPart.Head, 0.34f }, + { TargetBodyPart.Chest, 0.27f }, + { TargetBodyPart.LeftArm, 0.23f }, + { TargetBodyPart.RightArm, 0.23f }, + } + }, + { + TargetBodyPart.Chest, new Dictionary + { + { TargetBodyPart.Chest, 0.34f }, + { TargetBodyPart.Groin, 0.34f }, + { TargetBodyPart.Head, 0.12f }, + { TargetBodyPart.RightArm, 0.24f }, + { TargetBodyPart.LeftArm, 0.24f }, + } + }, + { + TargetBodyPart.Groin, new Dictionary + { + { TargetBodyPart.Groin, 0.34f }, + { TargetBodyPart.Chest, 0.34f }, + { TargetBodyPart.RightLeg, 0.17f }, + { TargetBodyPart.LeftLeg, 0.17f }, + { TargetBodyPart.RightArm, 0.11f }, + { TargetBodyPart.LeftArm, 0.11f }, + } + }, + { + TargetBodyPart.RightArm, new Dictionary + { + { TargetBodyPart.RightArm, 0.45f }, + { TargetBodyPart.RightHand, 0.27f }, + { TargetBodyPart.Chest, 0.22f }, + } + }, + { + TargetBodyPart.LeftArm, new Dictionary + { + { TargetBodyPart.LeftArm, 0.45f }, + { TargetBodyPart.LeftHand, 0.27f }, + { TargetBodyPart.Chest, 0.22f }, + } + }, + { + TargetBodyPart.RightHand, new Dictionary + { + { TargetBodyPart.RightHand, 0.75f }, + { TargetBodyPart.RightArm, 0.25f }, + } + }, + { + TargetBodyPart.LeftHand, new Dictionary + { + { TargetBodyPart.LeftHand, 0.75f }, + { TargetBodyPart.LeftArm, 0.25f }, + } + }, + { + TargetBodyPart.RightLeg, new Dictionary + { + { TargetBodyPart.RightLeg, 0.67f }, + { TargetBodyPart.RightFoot, 0.23f }, + { TargetBodyPart.Groin, 0.1f }, + } + }, + { + TargetBodyPart.LeftLeg, new Dictionary + { + { TargetBodyPart.LeftLeg, 0.67f }, + { TargetBodyPart.LeftFoot, 0.23f }, + { TargetBodyPart.Groin, 0.1f }, + } + }, + { + TargetBodyPart.RightFoot, new Dictionary + { + { TargetBodyPart.RightFoot, 0.75f }, + { TargetBodyPart.RightLeg, 0.25f }, + } + }, + { + TargetBodyPart.LeftFoot, new Dictionary + { + { TargetBodyPart.LeftFoot, 0.75f }, + { TargetBodyPart.LeftLeg, 0.25f }, + } + }, }; /// /// What is the current integrity of each body part? /// [ViewVariables, AutoNetworkedField] - public Dictionary BodyStatus = new() + public Dictionary BodyStatus = new() { - { TargetBodyPart.Head, TargetIntegrity.Healthy }, - { TargetBodyPart.Torso, TargetIntegrity.Healthy }, - { TargetBodyPart.Groin, TargetIntegrity.Healthy }, - { TargetBodyPart.LeftArm, TargetIntegrity.Healthy }, - { TargetBodyPart.LeftHand, TargetIntegrity.Healthy }, - { TargetBodyPart.RightArm, TargetIntegrity.Healthy }, - { TargetBodyPart.RightHand, TargetIntegrity.Healthy }, - { TargetBodyPart.LeftLeg, TargetIntegrity.Healthy }, - { TargetBodyPart.LeftFoot, TargetIntegrity.Healthy }, - { TargetBodyPart.RightLeg, TargetIntegrity.Healthy }, - { TargetBodyPart.RightFoot, TargetIntegrity.Healthy } + { TargetBodyPart.Head, WoundableSeverity.Healthy }, + { TargetBodyPart.Chest, WoundableSeverity.Healthy }, + { TargetBodyPart.Groin, WoundableSeverity.Healthy }, + { TargetBodyPart.LeftArm, WoundableSeverity.Healthy }, + { TargetBodyPart.LeftHand, WoundableSeverity.Healthy }, + { TargetBodyPart.RightArm, WoundableSeverity.Healthy }, + { TargetBodyPart.RightHand, WoundableSeverity.Healthy }, + { TargetBodyPart.LeftLeg, WoundableSeverity.Healthy }, + { TargetBodyPart.LeftFoot, WoundableSeverity.Healthy }, + { TargetBodyPart.RightLeg, WoundableSeverity.Healthy }, + { TargetBodyPart.RightFoot, WoundableSeverity.Healthy }, }; /// diff --git a/Content.Shared/Body/Components/BodyComponent.cs b/Content.Shared/Body/Components/BodyComponent.cs index 481e22150b0..d7b4c13cb39 100644 --- a/Content.Shared/Body/Components/BodyComponent.cs +++ b/Content.Shared/Body/Components/BodyComponent.cs @@ -41,4 +41,8 @@ public sealed partial class BodyComponent : Component [ViewVariables] [DataField, AutoNetworkedField] public HashSet LegEntities = new(); + + [ViewVariables] + [DataField, AutoNetworkedField] + public HashSet DroppedBodyParts = new(); } diff --git a/Content.Shared/Body/Organ/OrganComponent.cs b/Content.Shared/Body/Organ/OrganComponent.cs index 7c72e6ae47b..2fa6d02f1de 100644 --- a/Content.Shared/Body/Organ/OrganComponent.cs +++ b/Content.Shared/Body/Organ/OrganComponent.cs @@ -1,12 +1,15 @@ using Content.Shared.Backmen.Surgery.Tools; +using Content.Shared.Backmen.Surgery.Traumas; +using Content.Shared.Backmen.Surgery.Traumas.Systems; using Content.Shared.Body.Systems; +using Content.Shared.FixedPoint; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; namespace Content.Shared.Body.Organ; [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -[Access(typeof(SharedBodySystem))] +[Access(typeof(SharedBodySystem), typeof(TraumaSystem))] public sealed partial class OrganComponent : Component, ISurgeryToolComponent { /// @@ -22,6 +25,35 @@ public sealed partial class OrganComponent : Component, ISurgeryToolComponent [DataField] public EntityUid? OriginalBody; + /// + /// Maximal organ integrity, do keep in mind that Organs are supposed to be VERY and VERY damage sensitive + /// + [DataField("intCap"), AutoNetworkedField] + public FixedPoint2 IntegrityCap = 15; + + /// + /// Current organ HP, or integrity, whatever you prefer to say + /// + [DataField("integrity"), AutoNetworkedField] + public FixedPoint2 OrganIntegrity = 15; + + /// + /// Current Organ severity, dynamically updated based on organ integrity + /// + [DataField, AutoNetworkedField] + public OrganSeverity OrganSeverity = OrganSeverity.Normal; + + /// + /// All the modifiers that are currently modifying the OrganIntegrity + /// + public Dictionary<(string, EntityUid), FixedPoint2> IntegrityModifiers = new(); + + /// + /// The name's self-explanatory, thresholds. for states. of integrity. of this god fucking damn organ. + /// + [DataField(required: true)] + public Dictionary IntegrityThresholds = new(); + /// /// Shitcodey solution to not being able to know what name corresponds to each organ's slot ID /// without referencing the prototype or hardcoding. diff --git a/Content.Shared/Body/Part/BodyPartComponent.cs b/Content.Shared/Body/Part/BodyPartComponent.cs index b674789a516..96c7c6159c5 100644 --- a/Content.Shared/Body/Part/BodyPartComponent.cs +++ b/Content.Shared/Body/Part/BodyPartComponent.cs @@ -1,5 +1,5 @@ using Content.Shared.Backmen.Surgery.Tools; -using Content.Shared.Backmen.Targeting; +using Content.Shared.Backmen.Surgery.Wounds; using Content.Shared.Body.Components; using Content.Shared.Body.Systems; using Content.Shared.Containers.ItemSlots; @@ -124,26 +124,14 @@ public sealed partial class BodyPartComponent : Component, ISurgeryToolComponent public string? BaseLayerId; /// - /// Shitmed Change: On what TargetIntegrity we should re-enable the part. + /// Shitmed Change: On what WoundableSeverity we should re-enable the part. /// [DataField, AutoNetworkedField] - public TargetIntegrity EnableIntegrity = TargetIntegrity.ModeratelyWounded; - - [DataField, AutoNetworkedField] - public Dictionary IntegrityThresholds = new() - { - { TargetIntegrity.CriticallyWounded, 75 }, - { TargetIntegrity.HeavilyWounded, 60 }, - { TargetIntegrity.ModeratelyWounded, 50 }, - { TargetIntegrity.SomewhatWounded, 35 }, - { TargetIntegrity.LightlyWounded, 20 }, - { TargetIntegrity.Healthy, 10 }, - }; + public WoundableSeverity EnableIntegrity = WoundableSeverity.Severe; [DataField, AutoNetworkedField] //, AlwaysPushInheritance public BodyPartType PartType = BodyPartType.Other; - // TODO BODY Replace with a simulation of organs /// /// Whether or not the owning will die if all diff --git a/Content.Shared/Body/Part/BodyPartType.cs b/Content.Shared/Body/Part/BodyPartType.cs index acaee76fd85..b43496d9f65 100644 --- a/Content.Shared/Body/Part/BodyPartType.cs +++ b/Content.Shared/Body/Part/BodyPartType.cs @@ -7,15 +7,16 @@ namespace Content.Shared.Body.Part /// Defines the type of a . /// [Serializable, NetSerializable] - public enum BodyPartType + public enum BodyPartType : byte { Other = 0, - Torso, + Chest, + Groin, Head, Arm, Hand, Leg, Foot, - Tail + Tail, } } diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Body.cs b/Content.Shared/Body/Systems/SharedBodySystem.Body.cs index 88354b33463..eb1e720b51b 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Body.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Body.cs @@ -1,14 +1,14 @@ using System.Linq; using System.Numerics; -using Content.Shared.Backmen.Targeting; +using Content.Shared.Backmen.Surgery.Consciousness.Systems; +using Content.Shared.Backmen.Surgery.Wounds.Components; +using Content.Shared.Backmen.Surgery.Wounds.Systems; using Content.Shared.Body.Components; using Content.Shared.Body.Organ; using Content.Shared.Body.Part; using Content.Shared.Body.Prototypes; using Content.Shared.Containers.ItemSlots; -using Content.Shared.Damage; using Content.Shared.DragDrop; -using Content.Shared.FixedPoint; using Content.Shared.Gibbing.Components; using Content.Shared.Gibbing.Events; using Content.Shared.Gibbing.Systems; @@ -16,6 +16,7 @@ using Content.Shared.Humanoid.Events; using Content.Shared.Inventory; using Content.Shared.Inventory.Events; +using Content.Shared.Popups; using Content.Shared.Rejuvenate; using Content.Shared.Silicons.Borgs.Components; using Content.Shared.Standing; @@ -24,7 +25,6 @@ using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Utility; -using Robust.Shared.Timing; namespace Content.Shared.Body.Systems; @@ -37,11 +37,11 @@ public partial class SharedBodySystem * - Each "connection" is a body part (e.g. arm, hand, etc.) and each part can also contain organs. */ - [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly WoundSystem _woundSystem = default!; [Dependency] private readonly ItemSlotsSystem _slots = default!; [Dependency] private readonly GibbingSystem _gibbingSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; private const float GibletLaunchImpulse = 8; private const float GibletLaunchImpulseVariance = 3; @@ -57,6 +57,9 @@ private void InitializeBody() SubscribeLocalEvent(OnStandAttempt); SubscribeLocalEvent(OnProfileLoadFinished); SubscribeLocalEvent(OnBeingEquippedAttempt); + + // to prevent people from falling immediately as rejuvenated + SubscribeLocalEvent(OnRejuvenate); } private void OnBodyInserted(Entity ent, ref EntInsertedIntoContainerMessage args) @@ -238,6 +241,107 @@ private void SetupOrgans(Entity ent, Dictionary(); + frontier.Enqueue(rootSlot); + + var cameFrom = new Dictionary(); + cameFrom[rootSlot] = rootSlot; + + var cameFromEntities = new Dictionary(); + cameFromEntities[rootSlot] = rootPart.Value.Entity; + + while (frontier.TryDequeue(out var currentSlotId)) + { + var currentSlot = prototype.Slots[currentSlotId]; + + foreach (var connection in currentSlot.Connections) + { + if (!cameFrom.TryAdd(connection, currentSlotId)) + continue; + + var connectionSlot = prototype.Slots[connection]; + var parentEntity = cameFromEntities[currentSlotId]; + var parentPartComponent = Comp(parentEntity); + + if (Containers.TryGetContainer(parentEntity, GetPartSlotContainerId(connection), out var container)) + { + if (container.ContainedEntities.Count > 0) + { + cameFromEntities[connection] = container.ContainedEntities[0]; + } + else + { + var childPart = Spawn(connectionSlot.Part, new EntityCoordinates(parentEntity, Vector2.Zero)); + cameFromEntities[connection] = childPart; + + var childPartComponent = Comp(childPart); + + var partSlot = new BodyPartSlot(connection, childPartComponent.PartType); + childPartComponent.ParentSlot = partSlot; + parentPartComponent.Children.TryAdd(connection, partSlot); + + Dirty(parentEntity, parentPartComponent); + Dirty(childPart, childPartComponent); + + Containers.Insert(childPart, container); + + SetupOrgans((childPart, childPartComponent), connectionSlot.Organs); + } + } + else + { + var childPart = Spawn(connectionSlot.Part, new EntityCoordinates(parentEntity, Vector2.Zero)); + cameFromEntities[connection] = childPart; + + var childPartComponent = Comp(childPart); + + var partSlot = CreatePartSlot(parentEntity, connection, childPartComponent.PartType, parentPartComponent); + childPartComponent.ParentSlot = partSlot; + + Dirty(parentEntity, parentPartComponent); + Dirty(childPart, childPartComponent); + + if (partSlot is null) + { + Log.Error($"Could not create slot for connection {connection} in body {prototype.ID}"); + QueueDel(childPart); + continue; + } + + container = Containers.GetContainer(parentEntity, GetPartSlotContainerId(connection)); + Containers.Insert(childPart, container); + + SetupOrgans((childPart, childPartComponent), connectionSlot.Organs); + } + + frontier.Enqueue(connection); + } + } + + foreach (var bodyPart in GetBodyChildren(ent, body)) + { + if (!TryComp(bodyPart.Id, out var woundable)) + continue; + + _woundSystem.TryHaltAllBleeding(bodyPart.Id, woundable); + _woundSystem.ForceHealWoundsOnWoundable(bodyPart.Id, out _); + } + } + /// /// Gets all body containers on this entity including the root one. /// @@ -331,7 +435,9 @@ public virtual HashSet GibBody( Angle splatCone = default, SoundSpecifier? gibSoundOverride = null, GibType gib = GibType.Gib, - GibContentsOption contents = GibContentsOption.Drop) + GibContentsOption contents = GibContentsOption.Drop, + List? allowedContainers = null, + List? excludedContainers = null) { var gibs = new HashSet(); @@ -348,9 +454,10 @@ public virtual HashSet GibBody( foreach (var part in parts) { - _gibbingSystem.TryGibEntityWithRef(bodyId, part.Id, gib, contents, ref gibs, - playAudio: false, launchGibs: true, launchDirection: splatDirection, launchImpulse: GibletLaunchImpulse * splatModifier, - launchImpulseVariance: GibletLaunchImpulseVariance, launchCone: splatCone); + _gibbingSystem.TryGibEntityWithRef(bodyId, part.Id, gib, contents, ref gibs, playAudio: false, + launchGibs: true, launchDirection: splatDirection, launchImpulse: GibletLaunchImpulse * splatModifier, + launchImpulseVariance: GibletLaunchImpulseVariance, launchCone: splatCone, + allowedContainers: allowedContainers, excludedContainers: excludedContainers); if (!gibOrgans) continue; @@ -359,14 +466,15 @@ public virtual HashSet GibBody( { _gibbingSystem.TryGibEntityWithRef(bodyId, organ.Id, GibType.Drop, GibContentsOption.Skip, ref gibs, playAudio: false, launchImpulse: GibletLaunchImpulse * splatModifier, - launchImpulseVariance: GibletLaunchImpulseVariance, launchCone: splatCone); + launchImpulseVariance: GibletLaunchImpulseVariance, launchCone: splatCone, + allowedContainers: allowedContainers, excludedContainers: excludedContainers); } } var bodyTransform = Transform(bodyId); if (TryComp(bodyId, out var inventory)) { - foreach (var item in _inventory.GetHandOrInventoryEntities(bodyId)) + foreach (var item in _inventorySystem.GetHandOrInventoryEntities(bodyId)) { SharedTransform.DropNextTo(item, (bodyId, bodyTransform)); gibs.Add(item); @@ -396,7 +504,6 @@ public virtual HashSet GibPart( return gibs; DropSlotContents((partId, part)); - RemovePartChildren((partId, part), bodyEnt); foreach (var organ in GetPartOrgans(partId, part)) { _gibbingSystem.TryGibEntityWithRef(bodyEnt, organ.Id, GibType.Drop, GibContentsOption.Skip, @@ -412,7 +519,7 @@ public virtual HashSet GibPart( if (HasComp(partId)) { - foreach (var item in _inventory.GetHandOrInventoryEntities(partId)) + foreach (var item in _inventorySystem.GetHandOrInventoryEntities(partId)) { SharedTransform.AttachToGridOrMap(item); gibs.Add(item); @@ -434,7 +541,6 @@ public virtual bool BurnPart(EntityUid partId, return false; DropSlotContents((partId, part)); - RemovePartChildren((partId, part), bodyEnt); QueueDel(partId); return true; } diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs b/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs index f6f31a6e6e7..e5d5a7adcab 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs @@ -2,30 +2,23 @@ using Content.Shared.Body.Events; using Content.Shared.Body.Organ; using Content.Shared.Body.Part; -using Content.Shared.Damage; -using Content.Shared.Damage.Prototypes; using Content.Shared.Humanoid; using Content.Shared.Inventory; using Content.Shared.Movement.Components; -using Content.Shared.Random; -using Content.Shared.Backmen.Targeting; using Robust.Shared.Containers; using Robust.Shared.Utility; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; -using Content.Shared.Backmen.Mood; using Content.Shared.Backmen.Surgery.Body.Events; using Content.Shared.Backmen.Surgery.Body.Organs; -using AmputateAttemptEvent = Content.Shared.Body.Events.AmputateAttemptEvent; +using Content.Shared.Backmen.Targeting; +using Robust.Shared.Random; namespace Content.Shared.Body.Systems; public partial class SharedBodySystem { - [Dependency] private readonly RandomHelperSystem _randomHelper = default!; - [Dependency] private readonly InventorySystem _inventorySystem = default!; - private void InitializeParts() { // TODO: This doesn't handle comp removal on child ents. @@ -37,13 +30,11 @@ private void InitializeParts() // Shitmed Change Start SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnBodyPartRemove); - SubscribeLocalEvent(OnAmputateAttempt); - SubscribeLocalEvent(OnPartEnableChanged); } private void OnMapInit(Entity ent, ref MapInitEvent args) { - if (ent.Comp.PartType == BodyPartType.Torso) + if (ent.Comp.PartType == BodyPartType.Chest) { _slots.AddItemSlot(ent, ent.Comp.ContainerName, ent.Comp.ItemInsertionSlot); Dirty(ent, ent.Comp); @@ -60,104 +51,29 @@ private void OnMapInit(Entity ent, ref MapInitEvent args) private void OnBodyPartRemove(Entity ent, ref ComponentRemove args) { - if (ent.Comp.PartType == BodyPartType.Torso) + if (ent.Comp.PartType == BodyPartType.Chest) _slots.RemoveItemSlot(ent, ent.Comp.ItemInsertionSlot); } - private void OnPartEnableChanged(Entity partEnt, ref BodyPartEnableChangedEvent args) - { - if (!partEnt.Comp.CanEnable && args.Enabled) - return; - - partEnt.Comp.Enabled = args.Enabled; - - if (args.Enabled) - { - EnablePart(partEnt); - if (partEnt.Comp.Body is { Valid: true } bodyEnt) - RaiseLocalEvent(partEnt, new BodyPartComponentsModifyEvent(bodyEnt, true)); - } - else - { - DisablePart(partEnt); - if (partEnt.Comp.Body is { Valid: true } bodyEnt) - RaiseLocalEvent(partEnt, new BodyPartComponentsModifyEvent(bodyEnt, false)); - } - - Dirty(partEnt, partEnt.Comp); - } - /// /// Shitmed Change: This function handles dropping the items in an entity's slots if they lose all of a given part. /// Such as their hands, feet, head, etc. /// public void DropSlotContents(Entity partEnt) { - if (partEnt.Comp.Body is not null - && TryComp(partEnt.Comp.Body, out var inventory) // Prevent error for non-humanoids - && GetBodyPartCount(partEnt.Comp.Body.Value, partEnt.Comp.PartType) == 1 - && TryGetPartSlotContainerName(partEnt.Comp.PartType, out var containerNames)) - { - foreach (var containerName in containerNames) - _inventorySystem.DropSlotContents(partEnt.Comp.Body.Value, containerName, inventory); - } - - } - - // TODO: Refactor this crap. I hate it so much. - private void RemovePartEffect(Entity partEnt, Entity bodyEnt) - { - if (TerminatingOrDeleted(bodyEnt) - || !Resolve(bodyEnt, ref bodyEnt.Comp, logMissing: false)) - return; - - RemovePartChildren(partEnt, bodyEnt, bodyEnt.Comp); - } - - protected void RemovePartChildren(Entity partEnt, EntityUid bodyEnt, BodyComponent? body = null) - { - if (!Resolve(bodyEnt, ref body, logMissing: false)) + if (partEnt.Comp.Body is null + || !TryComp(partEnt.Comp.Body, out var inventory) || // Prevent error for non-humanoids + GetBodyPartCount(partEnt.Comp.Body.Value, partEnt.Comp.PartType) != 1 + || !TryGetPartSlotContainerName(partEnt.Comp.PartType, out var containerNames)) return; - if (partEnt.Comp.Children.Any()) + foreach (var containerName in containerNames) { - foreach (var slotId in partEnt.Comp.Children.Keys) - { - if (Containers.TryGetContainer(partEnt, GetPartSlotContainerId(slotId), out var container) && - container is ContainerSlot slot && - slot.ContainedEntity is { } childEntity && - TryComp(childEntity, out BodyPartComponent? childPart)) - { - var ev = new BodyPartEnableChangedEvent(false); - RaiseLocalEvent(childEntity, ref ev); - DropPart((childEntity, childPart)); - } - } - - Dirty(bodyEnt, body); + _inventorySystem.DropSlotContents(partEnt.Comp.Body.Value, containerName, inventory); } - } - protected virtual void DropPart(Entity partEnt) - { - DropSlotContents(partEnt); - // I don't know if this can cause issues, since any part that's being detached HAS to have a Body. - // though I really just want the compiler to shut the fuck up. - var body = partEnt.Comp.Body.GetValueOrDefault(); - if (TryComp(partEnt, out TransformComponent? transform) && _gameTiming.IsFirstTimePredicted) - { - var enableEvent = new BodyPartEnableChangedEvent(false); - RaiseLocalEvent(partEnt, ref enableEvent); - var droppedEvent = new BodyPartDroppedEvent(partEnt); - RaiseLocalEvent(body, ref droppedEvent); - SharedTransform.AttachToGridOrMap(partEnt, transform); - _randomHelper.RandomOffset(partEnt, 0.5f); - } } - private void OnAmputateAttempt(Entity partEnt, ref AmputateAttemptEvent args) => - DropPart(partEnt); - // Shitmed Change End private void OnBodyPartInserted(Entity ent, ref EntInsertedIntoContainerMessage args) { @@ -165,34 +81,34 @@ private void OnBodyPartInserted(Entity ent, ref EntInsertedIn var insertedUid = args.Entity; var slotId = args.Container.ID; - if (ent.Comp.Body is null) + var body = ent.Comp.Body; + if (body is null) return; if (TryComp(insertedUid, out BodyPartComponent? part) && slotId.Contains(PartSlotContainerIdPrefix + GetSlotFromBodyPart(part))) // Shitmed Change { - AddPart(ent.Comp.Body.Value, (insertedUid, part), slotId); - RecursiveBodyUpdate((insertedUid, part), ent.Comp.Body.Value); - CheckBodyPart((insertedUid, part), GetTargetBodyPart(part), false); // Shitmed Change + AddPart(body.Value, (insertedUid, part), slotId); + RecursiveBodyUpdate((insertedUid, part), body.Value); } #if DEBUG else if(HasComp(insertedUid)) { DebugTools.Assert( slotId.Contains(PartSlotContainerIdPrefix + GetSlotFromBodyPart(part)), - $"BodyPartComponent has not been inserted ({Prototype(args.Entity)?.ID}) into {Prototype(ent.Comp.Body.Value)?.ID}" + + $"BodyPartComponent has not been inserted ({Prototype(args.Entity)?.ID}) into {Prototype(ent.Comp.Body!.Value)?.ID}" + $" прототип должен иметь подключение начиная с {GetSlotFromBodyPart(part)} (сейчас {slotId.Replace(PartSlotContainerIdPrefix,"")})"); } #endif if (TryComp(insertedUid, out OrganComponent? organ) && slotId.Contains(OrganSlotContainerIdPrefix + organ.SlotId.ToLower(CultureInfo.InvariantCulture))) // Shitmed Change { - AddOrgan((insertedUid, organ), ent.Comp.Body.Value, ent); + AddOrgan((insertedUid, organ), body.Value, ent); } #if DEBUG else if(HasComp(insertedUid)) { - DebugTools.Assert($"OrganComponent has not been inserted ({Prototype(args.Entity)?.ID}) into {Prototype(ent.Comp.Body.Value)?.ID}"); + DebugTools.Assert($"OrganComponent has not been inserted ({Prototype(args.Entity)?.ID}) into {Prototype(ent.Comp.Body!.Value)?.ID}"); } #endif } @@ -213,7 +129,6 @@ private void OnBodyPartRemoved(Entity ent, ref EntRemovedFrom if (part.Body is not null) { - CheckBodyPart((removedUid, part), GetTargetBodyPart(part), true); RemovePart(part.Body.Value, (removedUid, part), slotId); RecursiveBodyUpdate((removedUid, part), null); } @@ -286,12 +201,12 @@ protected virtual void AddPart( Dirty(partEnt, partEnt.Comp); partEnt.Comp.Body = bodyEnt; - if (partEnt.Comp.Enabled && partEnt.Comp.Body is { Valid: true } body) // Shitmed Change - RaiseLocalEvent(partEnt, new BodyPartComponentsModifyEvent(body, true)); - var ev = new BodyPartAddedEvent(slotId, partEnt); RaiseLocalEvent(bodyEnt, ref ev); + var ev1 = new BodyPartAddedEvent(slotId, partEnt); + RaiseLocalEvent(partEnt, ref ev1); + AddLeg(partEnt, bodyEnt); } @@ -303,17 +218,13 @@ protected virtual void RemovePart( Resolve(bodyEnt, ref bodyEnt.Comp, logMissing: false); Dirty(partEnt, partEnt.Comp); - // Shitmed Change Start - if (partEnt.Comp.Body is { Valid: true } body) - RaiseLocalEvent(partEnt, new BodyPartComponentsModifyEvent(body, false)); - partEnt.Comp.ParentSlot = null; - // Shitmed Change End - var ev = new BodyPartRemovedEvent(slotId, partEnt); RaiseLocalEvent(bodyEnt, ref ev); + + var ev1 = new BodyPartRemovedEvent(slotId, partEnt); + RaiseLocalEvent(partEnt, ref ev1); + RemoveLeg(partEnt, bodyEnt); - RemovePartEffect(partEnt, bodyEnt); - PartRemoveDamage(bodyEnt, partEnt); } private void AddLeg(Entity legEnt, Entity bodyEnt) @@ -321,112 +232,26 @@ private void AddLeg(Entity legEnt, Entity bod if (!Resolve(bodyEnt, ref bodyEnt.Comp, logMissing: false)) return; - if (legEnt.Comp.PartType == BodyPartType.Leg) - { - bodyEnt.Comp.LegEntities.Add(legEnt); - UpdateMovementSpeed(bodyEnt); - Dirty(bodyEnt, bodyEnt.Comp); - } - } - - private void RemoveLeg(Entity legEnt, Entity bodyEnt) - { - if (!Resolve(bodyEnt, ref bodyEnt.Comp, logMissing: false)) + if (legEnt.Comp.PartType != BodyPartType.Leg) return; - if (legEnt.Comp.PartType == BodyPartType.Leg) - { - bodyEnt.Comp.LegEntities.Remove(legEnt); - UpdateMovementSpeed(bodyEnt); - Dirty(bodyEnt, bodyEnt.Comp); - Standing.Down(bodyEnt); - } + bodyEnt.Comp.LegEntities.Add(legEnt); + UpdateMovementSpeed(bodyEnt); + Dirty(bodyEnt, bodyEnt.Comp); } - private void PartRemoveDamage(Entity bodyEnt, Entity partEnt) + private void RemoveLeg(Entity legEnt, Entity bodyEnt) { if (!Resolve(bodyEnt, ref bodyEnt.Comp, logMissing: false)) return; - if (!_timing.ApplyingState - && partEnt.Comp.IsVital - && !GetBodyChildrenOfType(bodyEnt, partEnt.Comp.PartType, bodyEnt.Comp).Any() - ) - { - var damage = new DamageSpecifier(Prototypes.Index("Bloodloss"), partEnt.Comp.VitalDamage); - Damageable.TryChangeDamage(bodyEnt, damage, partMultiplier: 0f); - } - } - - private void EnablePart(Entity partEnt) - { - if (!TryComp(partEnt.Comp.Body, out BodyComponent? body)) - return; - - // I hate having to hardcode these checks so much. - if (partEnt.Comp.PartType == BodyPartType.Leg) - { - AddLeg(partEnt, (partEnt.Comp.Body.Value, body)); - RaiseLocalEvent(partEnt.Comp.Body.Value, new MoodRemoveEffectEvent("SurgeryNoLeg")); - } - - if (partEnt.Comp.PartType == BodyPartType.Arm) - { - var hand = GetBodyChildrenOfType(partEnt.Comp.Body.Value, BodyPartType.Hand, symmetry: partEnt.Comp.Symmetry).FirstOrDefault(); - if (hand != default) - { - var ev = new BodyPartEnabledEvent(hand); - RaiseLocalEvent(partEnt.Comp.Body.Value, ref ev); - } - } - - if (partEnt.Comp.PartType == BodyPartType.Hand) - { - var ev = new BodyPartEnabledEvent(partEnt); - RaiseLocalEvent(partEnt.Comp.Body.Value, ref ev); - // Remove this effect only when we have full arm - RaiseLocalEvent(partEnt.Comp.Body.Value, new MoodRemoveEffectEvent("SurgeryNoHand")); - } - - if (partEnt.Comp.PartType == BodyPartType.Torso) - { - RaiseLocalEvent(partEnt.Comp.Body.Value, new MoodRemoveEffectEvent("SurgeryNoTorso")); - } - } - - private void DisablePart(Entity partEnt) - { - if (!TryComp(partEnt.Comp.Body, out BodyComponent? body)) + if (legEnt.Comp.PartType != BodyPartType.Leg) return; - if (partEnt.Comp.PartType == BodyPartType.Leg) - { - RemoveLeg(partEnt, (partEnt.Comp.Body.Value, body)); - RaiseLocalEvent(partEnt.Comp.Body.Value, new MoodEffectEvent("SurgeryNoLeg")); - } - - if (partEnt.Comp.PartType == BodyPartType.Arm) - { - var hand = GetBodyChildrenOfType(partEnt.Comp.Body.Value, BodyPartType.Hand, symmetry: partEnt.Comp.Symmetry).FirstOrDefault(); - if (hand != default) - { - var ev = new BodyPartDisabledEvent(hand); - RaiseLocalEvent(partEnt.Comp.Body.Value, ref ev); - RaiseLocalEvent(partEnt.Comp.Body.Value, new MoodEffectEvent("SurgeryNoHand")); - } - } - - if (partEnt.Comp.PartType == BodyPartType.Hand) - { - var ev = new BodyPartDisabledEvent(partEnt); - RaiseLocalEvent(partEnt.Comp.Body.Value, ref ev); - RaiseLocalEvent(partEnt.Comp.Body.Value, new MoodEffectEvent("SurgeryNoHand")); - } - - if (partEnt.Comp.PartType == BodyPartType.Torso) - { - RaiseLocalEvent(partEnt.Comp.Body.Value, new MoodEffectEvent("SurgeryNoTorso")); - } + bodyEnt.Comp.LegEntities.Remove(legEnt); + UpdateMovementSpeed(bodyEnt); + Dirty(bodyEnt, bodyEnt.Comp); + Standing.Down(bodyEnt); } /// @@ -659,6 +484,39 @@ public bool CanAttachToSlot( && parentPart.Children.ContainsKey(slotId); } + /// + /// Returns true if the partId can be detached from the parentId in the specified slot. + /// + public bool CanDetachPart( + EntityUid parentId, + BodyPartSlot slot, + EntityUid partId, + BodyPartComponent? parentPart = null, + BodyPartComponent? part = null) + { + return Resolve(partId, ref part, logMissing: false) + && Resolve(parentId, ref parentPart, logMissing: false) + && CanDetachPart(parentId, slot.Id, partId, parentPart, part); + } + + /// + /// Returns true if we can detach the specified partId from the parentId in the specified slot. + /// + public bool CanDetachPart( + EntityUid parentId, + string slotId, + EntityUid partId, + BodyPartComponent? parentPart = null, + BodyPartComponent? part = null) + { + return Resolve(partId, ref part, logMissing: false) + && Resolve(parentId, ref parentPart, logMissing: false) + && parentPart.Children.TryGetValue(slotId, out var parentSlotData) + && part.PartType == parentSlotData.Type + && Containers.TryGetContainer(parentId, GetPartSlotContainerId(slotId), out var container) + && Containers.CanRemove(partId, container); + } + #endregion #region Attach/Detach @@ -696,7 +554,6 @@ public bool AttachPart( return false; } - if (!Containers.TryGetContainer(parentPartId, GetPartSlotContainerId(slot.Id), out var container)) { DebugTools.Assert($"Unable to find body slot {slot.Id} for {ToPrettyString(parentPartId)}"); @@ -706,7 +563,7 @@ public bool AttachPart( part.ParentSlot = slot; // start-backmen: surgery - if (TryComp(part.Body, out HumanoidAppearanceComponent? bodyAppearance) + if (HasComp(part.Body) && !HasComp(partId) && !TerminatingOrDeleted(parentPartId) && !TerminatingOrDeleted(partId)) // Saw some exceptions involving these due to the spawn menu. @@ -715,6 +572,58 @@ public bool AttachPart( return Containers.Insert(partId, container); } + /// + /// Detaches a body part from the specified body part parent. + /// + public bool DetachPart( + EntityUid parentPartId, + string slotId, + EntityUid partId, + BodyPartComponent? parentPart = null, + BodyPartComponent? part = null) + { + return Resolve(parentPartId, ref parentPart, logMissing: false) + && parentPart.Children.TryGetValue(slotId, out var slot) + && DetachPart(parentPartId, slot, partId, parentPart, part); + } + + /// + /// Detaches a body part from the specified body part parent. + /// + public bool DetachPart( + EntityUid parentPartId, + BodyPartSlot slot, + EntityUid partId, + BodyPartComponent? parentPart = null, + BodyPartComponent? part = null) + { + if (!Resolve(parentPartId, ref parentPart, logMissing: false) + || !Resolve(partId, ref part, logMissing: false) + || !CanDetachPart(parentPartId, slot.Id, partId, parentPart, part) + || !parentPart.Children.ContainsKey(slot.Id)) + { + return false; + } + + if (!Containers.TryGetContainer(parentPartId, GetPartSlotContainerId(slot.Id), out var container)) + { + DebugTools.Assert($"Unable to find body slot {slot.Id} for {ToPrettyString(parentPartId)}"); + return false; + } + + // TODO: Might break something. but fixes surgery! + //parentPart.Children.Remove(slot.Id); + + // start-backmen: surgery + if (HasComp(part.Body) + && !HasComp(partId) + && !TerminatingOrDeleted(parentPartId) + && !TerminatingOrDeleted(partId)) // Saw some exceptions involving these due to the spawn menu. + EnsureComp(partId); + + return Containers.Remove(partId, container); + } + #endregion #region Misc @@ -748,6 +657,107 @@ public void UpdateMovementSpeed( Movement.ChangeBaseSpeed(bodyId, walkSpeed, sprintSpeed, acceleration, movement); } + public TargetBodyPart? GetRandomBodyPart(EntityUid target, + EntityUid attacker, + TargetingComponent? targetComp = null, + TargetingComponent? attackerComp = null) + { + if (!Resolve(target, ref targetComp) || !Resolve(attacker, ref attackerComp)) + return null; + + var totalWeight = targetComp.TargetOdds[attackerComp.Target].Values.Sum(); + var randomValue = _random.NextFloat() * totalWeight; + + foreach (var (part, weight) in targetComp.TargetOdds[attackerComp.Target]) + { + if (randomValue <= weight) + return part; + randomValue -= weight; + } + + return TargetBodyPart.Chest; // Default to torso if something goes wrong + } + + public TargetBodyPart? GetRandomBodyPart(EntityUid target, + TargetBodyPart targetPart = TargetBodyPart.Chest, + TargetingComponent? targetComp = null) + { + if (!Resolve(target, ref targetComp)) + return null; + + var totalWeight = targetComp.TargetOdds[targetPart].Values.Sum(); + var randomValue = _random.NextFloat() * totalWeight; + + foreach (var (part, weight) in targetComp.TargetOdds[targetPart]) + { + if (randomValue <= weight) + return part; + randomValue -= weight; + } + + return targetPart; + } + + public TargetBodyPart? GetRandomBodyPart(EntityUid target) + { + return GetTargetBodyPart(_random.PickAndTake(GetBodyChildren(target).ToList())); + } + + public TargetBodyPart? GetTargetBodyPart(Entity part) + { + return GetTargetBodyPart(part.Comp.PartType, part.Comp.Symmetry); + } + + public TargetBodyPart? GetTargetBodyPart(BodyPartComponent part) + { + return GetTargetBodyPart(part.PartType, part.Symmetry); + } + + /// + /// Converts Enums from BodyPartType to their Targeting system equivalent. + /// + public TargetBodyPart? GetTargetBodyPart(BodyPartType type, BodyPartSymmetry symmetry) + { + return (type, symmetry) switch + { + (BodyPartType.Head, _) => TargetBodyPart.Head, + (BodyPartType.Chest, _) => TargetBodyPart.Chest, + (BodyPartType.Groin, _) => TargetBodyPart.Groin, + (BodyPartType.Arm, BodyPartSymmetry.Left) => TargetBodyPart.LeftArm, + (BodyPartType.Arm, BodyPartSymmetry.Right) => TargetBodyPart.RightArm, + (BodyPartType.Hand, BodyPartSymmetry.Left) => TargetBodyPart.LeftHand, + (BodyPartType.Hand, BodyPartSymmetry.Right) => TargetBodyPart.RightHand, + (BodyPartType.Leg, BodyPartSymmetry.Left) => TargetBodyPart.LeftLeg, + (BodyPartType.Leg, BodyPartSymmetry.Right) => TargetBodyPart.RightLeg, + (BodyPartType.Foot, BodyPartSymmetry.Left) => TargetBodyPart.LeftFoot, + (BodyPartType.Foot, BodyPartSymmetry.Right) => TargetBodyPart.RightFoot, + _ => null, + }; + } + + /// + /// Converts Enums from Targeting system to their BodyPartType equivalent. + /// + public (BodyPartType Type, BodyPartSymmetry Symmetry) ConvertTargetBodyPart(TargetBodyPart? targetPart) + { + return targetPart switch + { + TargetBodyPart.Head => (BodyPartType.Head, BodyPartSymmetry.None), + TargetBodyPart.Chest => (BodyPartType.Chest, BodyPartSymmetry.None), + TargetBodyPart.Groin => (BodyPartType.Groin, BodyPartSymmetry.None), + TargetBodyPart.LeftArm => (BodyPartType.Arm, BodyPartSymmetry.Left), + TargetBodyPart.LeftHand => (BodyPartType.Hand, BodyPartSymmetry.Left), + TargetBodyPart.RightArm => (BodyPartType.Arm, BodyPartSymmetry.Right), + TargetBodyPart.RightHand => (BodyPartType.Hand, BodyPartSymmetry.Right), + TargetBodyPart.LeftLeg => (BodyPartType.Leg, BodyPartSymmetry.Left), + TargetBodyPart.LeftFoot => (BodyPartType.Foot, BodyPartSymmetry.Left), + TargetBodyPart.RightLeg => (BodyPartType.Leg, BodyPartSymmetry.Right), + TargetBodyPart.RightFoot => (BodyPartType.Foot, BodyPartSymmetry.Right), + _ => (BodyPartType.Chest, BodyPartSymmetry.None) + }; + + } + #endregion #region Queries @@ -760,10 +770,8 @@ public void UpdateMovementSpeed( if (!Resolve(partId, ref part, logMissing: false)) yield break; - foreach (var slotId in part.Organs.Keys) + foreach (var containerSlotId in part.Organs.Keys.Select(GetOrganContainerId)) { - var containerSlotId = GetOrganContainerId(slotId); - if (!Containers.TryGetContainer(partId, containerSlotId, out var container)) continue; @@ -962,7 +970,7 @@ public bool BodyHasChild( } /// - /// Tries to get a list of ValueTuples of and OrganComponent on each organs + /// Tries to get a list of ValueTuples of and OrganComponent on each organ /// in the given part. /// /// The part entity id to check on. @@ -997,11 +1005,12 @@ public bool TryGetBodyPartOrganComponents( /// /// The part entity id to check on. /// The type of component to check for. + /// Organs found in a body part. /// The part to check for organs on. /// Whether any were found. /// - /// This method is somewhat of a copout to the fact that we can't use reflection to generically - /// get the type of a component on runtime due to sandboxing. So we simply do a HasComp check for each organ. + /// This method is somewhat of a cop out to the fact that we can't use reflection to generically + /// get the type of component on runtime due to sandboxing. So we simply do a HasComp check for each organ. /// public bool TryGetBodyPartOrgans( EntityUid uid, @@ -1033,42 +1042,33 @@ public bool TryGetBodyPartOrgans( return false; } - private bool TryGetPartSlotContainerName(BodyPartType partType, out HashSet containerNames) + public bool TryGetPartSlotContainerName(BodyPartType partType, out HashSet containerNames) { containerNames = partType switch { - BodyPartType.Hand => new() { "gloves" }, - BodyPartType.Foot => new() { "shoes" }, - BodyPartType.Head => new() { "eyes", "ears", "head", "mask" }, - _ => new() + BodyPartType.Hand => ["gloves"], + BodyPartType.Foot => ["shoes"], + BodyPartType.Head => ["eyes", "ears", "head", "mask"], + _ => [], }; return containerNames.Count > 0; } - private bool TryGetPartFromSlotContainer(string slot, out BodyPartType? partType) + public bool TryGetPartFromSlotContainer(string slot, out BodyPartType? partType) { partType = slot switch { "gloves" => BodyPartType.Hand, "shoes" => BodyPartType.Foot, "eyes" or "ears" or "head" or "mask" => BodyPartType.Head, - _ => null + _ => null, }; return partType is not null; } public int GetBodyPartCount(EntityUid bodyId, BodyPartType partType, BodyComponent? body = null) { - if (!Resolve(bodyId, ref body, logMissing: false)) - return 0; - - int count = 0; - foreach (var part in GetBodyChildren(bodyId, body)) - { - if (part.Component.PartType == partType) - count++; - } - return count; + return !Resolve(bodyId, ref body, logMissing: false) ? 0 : GetBodyChildren(bodyId, body).Count(part => part.Component.PartType == partType); } public string GetSlotFromBodyPart(BodyPartComponent? part) @@ -1078,15 +1078,8 @@ public string GetSlotFromBodyPart(BodyPartComponent? part) if (part is null) return slotName; - if (part.SlotId != "") - slotName = part.SlotId; - else - slotName = part.PartType.ToString().ToLower(); - - if (part.Symmetry != BodyPartSymmetry.None) - return $"{part.Symmetry.ToString().ToLower()} {slotName}"; - else - return slotName; + slotName = part.SlotId != "" ? part.SlotId : part.PartType.ToString().ToLower(); + return part.Symmetry != BodyPartSymmetry.None ? $"{part.Symmetry.ToString().ToLower()} {slotName}" : slotName; } // Shitmed Change End @@ -1104,14 +1097,9 @@ public IEnumerable GetBodyPartAdjacentParts( if (TryGetParentBodyPart(partId, out var parentUid, out _)) yield return parentUid.Value; - foreach (var slotId in part.Children.Keys) + foreach (var containedEnt in part.Children.Keys.Select(slotId => Containers.GetContainer(partId, GetPartSlotContainerId(slotId))).SelectMany(container => container.ContainedEntities)) { - var container = Containers.GetContainer(partId, GetPartSlotContainerId(slotId)); - - foreach (var containedEnt in container.ContainedEntities) - { - yield return containedEnt; - } + yield return containedEnt; } } diff --git a/Content.Shared/Body/Systems/SharedBodySystem.cs b/Content.Shared/Body/Systems/SharedBodySystem.cs index 3a5a7940561..f9e8e441504 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.cs @@ -1,9 +1,9 @@ -using Content.Shared.Body.Part; // Shitmed Change -using Content.Shared.Damage; +using Content.Shared.Inventory; using Content.Shared.Movement.Systems; using Content.Shared.Standing; using Robust.Shared.Containers; using Robust.Shared.Prototypes; +using Robust.Shared.Random; using Robust.Shared.Timing; namespace Content.Shared.Body.Systems; @@ -25,13 +25,14 @@ public abstract partial class SharedBodySystem : EntitySystem public const string BodyRootContainerId = "body_root_part"; /// - /// Container ID prefix for any body organs. + /// Container ID prefix for anybody organs. /// public const string OrganSlotContainerIdPrefix = "body_organ_slot_"; + [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; [Dependency] protected readonly IPrototypeManager Prototypes = default!; - [Dependency] protected readonly DamageableSystem Damageable = default!; [Dependency] protected readonly MovementSpeedModifierSystem Movement = default!; [Dependency] protected readonly SharedContainerSystem Containers = default!; [Dependency] protected readonly SharedTransformSystem SharedTransform = default!; @@ -43,7 +44,6 @@ public override void Initialize() InitializeBody(); InitializeParts(); - InitializeBkm(); // backmen InitializeOrgans(); // To try and mitigate the server load due to integrity checks, we set up a Job Queue. InitializePartAppearances(); @@ -65,7 +65,7 @@ public override void Initialize() } /// - /// Gets the container Id for the specified slotId. + /// Gets the container ID for the specified slotId. /// public static string GetPartSlotContainerId(string slotId) { @@ -73,7 +73,7 @@ public static string GetPartSlotContainerId(string slotId) } /// - /// Gets the container Id for the specified slotId. + /// Gets the container ID for the specified slotId. /// public static string GetOrganContainerId(string slotId) { diff --git a/Content.Shared/Chat/SharedSuicideSystem.cs b/Content.Shared/Chat/SharedSuicideSystem.cs index 2906147081e..aaceb210b40 100644 --- a/Content.Shared/Chat/SharedSuicideSystem.cs +++ b/Content.Shared/Chat/SharedSuicideSystem.cs @@ -3,7 +3,11 @@ using Content.Shared.Mobs.Components; using Robust.Shared.Prototypes; using System.Linq; +using Content.Shared.Backmen.Surgery.Consciousness; +using Content.Shared.Backmen.Surgery.Consciousness.Components; +using Content.Shared.Backmen.Surgery.Consciousness.Systems; using Content.Shared.Backmen.Targeting; +using Content.Shared.Body.Components; namespace Content.Shared.Chat; @@ -11,6 +15,7 @@ public sealed class SharedSuicideSystem : EntitySystem { [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly ConsciousnessSystem _consciousness = default!; /// /// Applies lethal damage spread out across the damage types given. @@ -65,4 +70,23 @@ public void ApplyLethalDamage(Entity target, ProtoId + /// kills a consciousness. lol + /// + public void KillConsciousness(Entity target) + { + foreach (var modifier in target.Comp.Modifiers) + { + _consciousness.RemoveConsciousnessModifier(target, modifier.Key.Item1, modifier.Key.Item2); + } + + foreach (var multiplier in target.Comp.Multipliers) + { + _consciousness.RemoveConsciousnessMultiplier(target, multiplier.Key.Item1, multiplier.Key.Item2, target); + } + + _consciousness.AddConsciousnessModifier(target, target, -target.Comp.Cap, target, "Suicide", ConsciousnessModType.Pain); + _consciousness.AddConsciousnessMultiplier(target, target, 0f, "Suicide", target, ConsciousnessModType.Pain); + } } diff --git a/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs b/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs index dba2ba03a3f..ba525edd94c 100644 --- a/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs +++ b/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs @@ -190,6 +190,7 @@ public void ReactionPlant(EntityUid? plantHolder, ReagentQuantity amount, Soluti } [Serializable, NetSerializable] + public struct ReagentGuideEntry { public string ReagentPrototype; diff --git a/Content.Shared/Damage/Prototypes/DamageTypePrototype.cs b/Content.Shared/Damage/Prototypes/DamageTypePrototype.cs index a1ae23ef676..b6af2e8f0fb 100644 --- a/Content.Shared/Damage/Prototypes/DamageTypePrototype.cs +++ b/Content.Shared/Damage/Prototypes/DamageTypePrototype.cs @@ -1,3 +1,4 @@ +using Content.Shared.FixedPoint; using Robust.Shared.Prototypes; namespace Content.Shared.Damage.Prototypes @@ -17,6 +18,12 @@ public sealed partial class DamageTypePrototype : IPrototype [ViewVariables(VVAccess.ReadOnly)] public string LocalizedName => Loc.GetString(Name); + /// + /// Wounds with the said damage type will be having this multiplier + /// + [DataField, ViewVariables(VVAccess.ReadOnly)] + public FixedPoint2 WoundHealingMultiplier { get; set; } = 1; + /// /// The price for each 1% damage reduction in armors /// diff --git a/Content.Shared/Damage/Systems/DamageOnAttackedSystem.cs b/Content.Shared/Damage/Systems/DamageOnAttackedSystem.cs index c511a0cab2e..baa343be658 100644 --- a/Content.Shared/Damage/Systems/DamageOnAttackedSystem.cs +++ b/Content.Shared/Damage/Systems/DamageOnAttackedSystem.cs @@ -73,7 +73,7 @@ private void OnAttacked(Entity entity, ref AttackedEv } } - totalDamage = _damageableSystem.TryChangeDamage(args.User, totalDamage, entity.Comp.IgnoreResistances, origin: entity, canEvade: true); + totalDamage = _damageableSystem.TryChangeDamage(args.User, totalDamage, entity.Comp.IgnoreResistances, origin: entity, canBeCancelled: true); if (totalDamage != null && totalDamage.AnyPositive()) { diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs index 9d0ae9b6bbc..d33ae236fa7 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.cs @@ -1,16 +1,21 @@ using System.Linq; +using Content.Shared.Backmen.Surgery.Consciousness.Components; +using Content.Shared.Backmen.Surgery.Wounds.Components; +using Content.Shared.Backmen.Surgery.Wounds.Systems; using Content.Shared.CCVar; using Content.Shared.Chemistry; using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; using Content.Shared.Inventory; -using Content.Shared.Mind.Components; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Body.Systems; using Content.Shared.Radiation.Events; using Content.Shared.Rejuvenate; using Content.Shared.Backmen.Targeting; +using Content.Shared.Body.Components; +using Content.Shared.Body.Part; +using Content.Shared.Mind.Components; using Robust.Shared.Configuration; using Robust.Shared.GameStates; using Robust.Shared.Network; @@ -27,12 +32,19 @@ public sealed class DamageableSystem : EntitySystem [Dependency] private readonly INetManager _netMan = default!; [Dependency] private readonly MobThresholdSystem _mobThreshold = default!; [Dependency] private readonly SharedBodySystem _body = default!; + [Dependency] private readonly WoundSystem _wounds = default!; + [Dependency] private readonly IRobustRandom _LETSGOGAMBLINGEXCLAMATIONMARKEXCLAMATIONMARK = default!; + + [Dependency] private readonly IComponentFactory _factory = default!; [Dependency] private readonly IConfigurationManager _config = default!; [Dependency] private readonly SharedChemistryGuideDataSystem _chemistryGuideData = default!; private EntityQuery _appearanceQuery; private EntityQuery _damageableQuery; + private EntityQuery _bodyQuery; + private EntityQuery _consciousnessQuery; private EntityQuery _mindContainerQuery; + private EntityQuery _woundableQuery; public float UniversalAllDamageModifier { get; private set; } = 1f; public float UniversalAllHealModifier { get; private set; } = 1f; @@ -55,6 +67,9 @@ public override void Initialize() _appearanceQuery = GetEntityQuery(); _damageableQuery = GetEntityQuery(); + _bodyQuery = GetEntityQuery(); + _consciousnessQuery = GetEntityQuery(); + _woundableQuery = GetEntityQuery(); _mindContainerQuery = GetEntityQuery(); // Damage modifier CVars are updated and stored here to be queried in other systems. @@ -94,8 +109,7 @@ public override void Initialize() private void DamageableInit(EntityUid uid, DamageableComponent component, ComponentInit _) { if (component.DamageContainerID != null && - _prototypeManager.TryIndex(component.DamageContainerID, - out var damageContainerPrototype)) + _prototypeManager.TryIndex(component.DamageContainerID, out var damageContainerPrototype)) { // Initialize damage dictionary, using the types and groups from the damage // container prototype @@ -130,7 +144,7 @@ private void DamageableInit(EntityUid uid, DamageableComponent component, Compon /// Directly sets the damage specifier of a damageable component. /// /// - /// Useful for some unfriendly folk. Also ensures that cached values are updated and that a damage changed + /// Useful for some unfriendly folk. Also ensures that cached values are updated and that damage changed /// event is raised. /// public void SetDamage(EntityUid uid, DamageableComponent damageable, DamageSpecifier damage) @@ -143,11 +157,14 @@ public void SetDamage(EntityUid uid, DamageableComponent damageable, DamageSpeci /// If the damage in a DamageableComponent was changed, this function should be called. /// /// - /// This updates cached damage information, flags the component as dirty, and raises a damage changed event. + /// This updates cached damage information, flags the component as dirty, and raises damage changed event. /// The damage changed event is used by other systems, such as damage thresholds. /// - public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSpecifier? damageDelta = null, - bool interruptsDoAfters = true, EntityUid? origin = null, bool? canSever = null) + public void DamageChanged(EntityUid uid, + DamageableComponent component, + DamageSpecifier? damageDelta = null, + bool interruptsDoAfters = true, + EntityUid? origin = null) { component.Damage.GetDamagePerGroup(_prototypeManager, component.DamagePerGroup); @@ -159,7 +176,7 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp var data = new DamageVisualizerGroupData(component.DamagePerGroup.Keys.ToList()); _appearance.SetData(uid, DamageVisualizerKeys.DamageUpdateGroups, data, appearance); } - RaiseLocalEvent(uid, new DamageChangedEvent(component, damageDelta, interruptsDoAfters, origin, canSever ?? true)); + RaiseLocalEvent(uid, new DamageChangedEvent(component, damageDelta, interruptsDoAfters, origin)); } /// @@ -174,47 +191,160 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp /// Returns a with information about the actual damage changes. This will be /// null if the user had no applicable components that can take damage. /// - public DamageSpecifier? TryChangeDamage(EntityUid? uid, DamageSpecifier damage, bool ignoreResistances = false, - bool interruptsDoAfters = true, DamageableComponent? damageable = null, EntityUid? origin = null, - bool? canSever = true, bool? canEvade = false, float? partMultiplier = 1.00f, TargetBodyPart? targetPart = null) + public DamageSpecifier? TryChangeDamage(EntityUid? uid, + DamageSpecifier damage, + bool ignoreResistances = false, + bool interruptsDoAfters = true, + DamageableComponent? damageable = null, + EntityUid? origin = null, + bool canBeCancelled = false, + float partMultiplier = 1.00f, + TargetBodyPart? targetPart = null) { - if (!uid.HasValue || !_damageableQuery.Resolve(uid.Value, ref damageable, false)) - { - // TODO BODY SYSTEM pass damage onto body system - return null; - } - if (damage.Empty) { return damage; } - var before = new BeforeDamageChangedEvent(damage, origin, targetPart); // Shitmed Change + if (!uid.HasValue) + return null; + + var before = new BeforeDamageChangedEvent(damage, origin, canBeCancelled); // heheheha RaiseLocalEvent(uid.Value, ref before); if (before.Cancelled) return null; - // Shitmed Change Start - var partDamage = new TryChangePartDamageEvent(damage, origin, targetPart, canSever ?? true, canEvade ?? false, partMultiplier ?? 1.00f); - RaiseLocalEvent(uid.Value, ref partDamage); + if (!_damageableQuery.Resolve(uid.Value, ref damageable, false)) + return null; + + if (_woundableQuery.TryComp(uid.Value, out var woundable)) + { + var damageDict = new Dictionary(); + foreach (var (type, severity) in damage.DamageDict) + { + // some wounds like Asphyxiation and Bloodloss aren't supposed to be created. + if (!_prototypeManager.TryIndex(type, out var woundPrototype) + || !woundPrototype.TryGetComponent(out _, _factory)) + continue; + + damageDict.Add(type, severity); + } + + if (damageDict.Count == 0) + return null; + + foreach (var (damageType, severity) in damageDict) + { + var actualDamage = severity * partMultiplier; + if (!_wounds.TryContinueWound(uid.Value, damageType, actualDamage, woundable)) + _wounds.TryCreateWound(uid.Value, damageType, actualDamage, GetDamageGroupByType(damageType)); + } - if (partDamage.Evaded || partDamage.Cancelled) return null; + } - // Shitmed Change End + // I added a check for consciousness, because pain is directly hardwired into + // woundables, pain and other stuff. things having a body and no consciousness comp + // are impossible to kill... So yeah. + if (_bodyQuery.HasComp(uid.Value) && _consciousnessQuery.HasComp(uid.Value)) + { + var target = targetPart ?? _body.GetRandomBodyPart(uid.Value); + if (origin.HasValue && TryComp(origin.Value, out var targeting)) + target = _body.GetRandomBodyPart(uid.Value, origin.Value, attackerComp: targeting); + + var (partType, symmetry) = _body.ConvertTargetBodyPart(target); + var possibleTargets = _body.GetBodyChildrenOfType(uid.Value, partType, symmetry: symmetry).ToList(); + + if (possibleTargets.Count == 0) + possibleTargets = _body.GetBodyChildren(uid.Value).ToList(); + + // No body parts at all? + if (possibleTargets.Count == 0) + return null; + + var damageDict = new Dictionary(); + foreach (var (type, severity) in damage.DamageDict) + { + // some wounds like Asphyxiation and Bloodloss aren't supposed to be created. + if (!_prototypeManager.TryIndex(type, out var woundPrototype) + || !woundPrototype.TryGetComponent(out _, _factory)) + continue; + + damageDict.Add(type, severity * partMultiplier); + } + + var chosenTarget = _LETSGOGAMBLINGEXCLAMATIONMARKEXCLAMATIONMARK.PickAndTake(possibleTargets); + if (targetPart == TargetBodyPart.All && damage.GetTotal() < 0) + { + if (_wounds.TryGetWoundableWithMostDamage( + uid.Value, + out var damageWoundable, + GetDamageGroupByType(damageDict.FirstOrDefault().Key))) + { + chosenTarget = (damageWoundable.Value.Owner, Comp(damageWoundable.Value.Owner)); + } + } + + var beforePart = new BeforeDamageChangedEvent(damage, origin); + RaiseLocalEvent(chosenTarget.Id, ref before); + + if (beforePart.Cancelled) + return null; + + if (damageDict.Count == 0) + return null; + + if (!ignoreResistances) + { + if (damageable.DamageModifierSetId != null && + _prototypeManager.TryIndex(damageable.DamageModifierSetId, out var modifierSet)) + { + // lol bozo + var spec = new DamageSpecifier + { + DamageDict = damageDict, + }; + + damage = DamageSpecifier.ApplyModifierSet(spec, modifierSet); + } + + var ev = new DamageModifyEvent(damage, origin, targetPart); + RaiseLocalEvent(uid.Value, ev); + damage = ev.Damage; + + if (damage.Empty) + { + return damage; + } + + foreach (var (type, _) in damageDict) + { + if (damage.DamageDict.TryGetValue(type, out var value)) + damageDict[type] = value; + } + } + + foreach (var (damageType, severity) in damageDict) + { + if (!_wounds.TryContinueWound(chosenTarget.Id, damageType, severity)) + _wounds.TryCreateWound(chosenTarget.Id, damageType, severity, GetDamageGroupByType(damageType)); + } + + return damage; + } // Apply resistances if (!ignoreResistances) { if (damageable.DamageModifierSetId != null && - _prototypeManager.TryIndex(damageable.DamageModifierSetId, out var modifierSet)) + _prototypeManager.TryIndex(damageable.DamageModifierSetId, out var modifierSet)) { // TODO DAMAGE PERFORMANCE // use a local private field instead of creating a new dictionary here.. - // TODO: We need to add a check to see if the given armor covers the targeted part (if any) to modify or not. damage = DamageSpecifier.ApplyModifierSet(damage, modifierSet); } + var ev = new DamageModifyEvent(damage, origin, targetPart); RaiseLocalEvent(uid.Value, ev); damage = ev.Damage; @@ -249,7 +379,7 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp } if (delta.DamageDict.Count > 0) - DamageChanged(uid.Value, damageable, delta, interruptsDoAfters, origin, canSever); + DamageChanged(uid.Value, damageable, delta, interruptsDoAfters, origin); return delta; } @@ -288,9 +418,9 @@ public DamageSpecifier ApplyUniversalAllModifiers(DamageSpecifier damage) /// /// Sets all damage types supported by a to the specified value. /// - /// + /// /// Does nothing If the given damage value is negative. - /// + /// public void SetAllDamage(EntityUid uid, DamageableComponent component, FixedPoint2 newValue) { if (newValue < 0) @@ -309,14 +439,18 @@ public void SetAllDamage(EntityUid uid, DamageableComponent component, FixedPoin DamageChanged(uid, component, new DamageSpecifier()); // Shitmed Change Start - if (HasComp(uid)) + if (!HasComp(uid)) + return; + + foreach (var (part, _) in _body.GetBodyChildren(uid)) { - foreach (var (part, _) in _body.GetBodyChildren(uid)) - { - if (!TryComp(part, out DamageableComponent? damageComp)) - continue; + if (!TryComp(part, out WoundableComponent? woundable)) + continue; - SetAllDamage(part, damageComp, newValue); + foreach (var (type, severity) in component.Damage.DamageDict) + { + if (!_wounds.TryContinueWound(part, type, severity, woundable)) + _wounds.TryCreateWound(part, type, severity, GetDamageGroupByType(type), woundable); } } // Shitmed Change End @@ -331,6 +465,11 @@ public void SetDamageModifierSetId(EntityUid uid, string damageModifierSetId, Da Dirty(uid, comp); } + private string GetDamageGroupByType(string id) + { + return (from @group in _prototypeManager.EnumeratePrototypes() where @group.DamageTypes.Contains(id) select @group.ID).FirstOrDefault()!; + } + private void DamageableGetState(EntityUid uid, DamageableComponent component, ref ComponentGetState args) { if (_netMan.IsServer) @@ -360,6 +499,9 @@ private void OnIrradiated(EntityUid uid, DamageableComponent component, OnIrradi private void OnRejuvenate(EntityUid uid, DamageableComponent component, RejuvenateEvent args) { + if (HasComp(uid)) + return; + TryComp(uid, out var thresholds); _mobThreshold.SetAllowRevives(uid, true, thresholds); // do this so that the state changes when we set the damage SetAllDamage(uid, component, 0); @@ -382,11 +524,11 @@ private void DamageableHandleState(EntityUid uid, DamageableComponent component, var delta = component.Damage - newDamage; delta.TrimZeros(); - if (!delta.Empty) - { - component.Damage = newDamage; - DamageChanged(uid, component, delta); - } + if (delta.Empty) + return; + + component.Damage = newDamage; + DamageChanged(uid, component, delta); } } @@ -397,21 +539,7 @@ private void DamageableHandleState(EntityUid uid, DamageableComponent component, public record struct BeforeDamageChangedEvent( DamageSpecifier Damage, EntityUid? Origin = null, - TargetBodyPart? TargetPart = null, // Shitmed Change - bool Cancelled = false); - - /// - /// Shitmed Change: Raised on parts before damage is done so we can cancel the damage if they evade. - /// - [ByRefEvent] - public record struct TryChangePartDamageEvent( - DamageSpecifier Damage, - EntityUid? Origin = null, - TargetBodyPart? TargetPart = null, - bool CanSever = true, - bool CanEvade = false, - float PartMultiplier = 1.00f, - bool Evaded = false, + bool CanBeCancelled = true, bool Cancelled = false); /// @@ -474,17 +602,11 @@ public sealed class DamageChangedEvent : EntityEventArgs /// public readonly EntityUid? Origin; - /// - /// Can this damage event sever parts? - /// - public readonly bool CanSever; - - public DamageChangedEvent(DamageableComponent damageable, DamageSpecifier? damageDelta, bool interruptsDoAfters, EntityUid? origin, bool canSever = true) + public DamageChangedEvent(DamageableComponent damageable, DamageSpecifier? damageDelta, bool interruptsDoAfters, EntityUid? origin) { Damageable = damageable; DamageDelta = damageDelta; Origin = origin; - CanSever = canSever; if (DamageDelta == null) return; diff --git a/Content.Shared/Damage/Systems/SharedGodmodeSystem.cs b/Content.Shared/Damage/Systems/SharedGodmodeSystem.cs index e5ce90eca2f..ec288e90260 100644 --- a/Content.Shared/Damage/Systems/SharedGodmodeSystem.cs +++ b/Content.Shared/Damage/Systems/SharedGodmodeSystem.cs @@ -53,9 +53,6 @@ public virtual void EnableGodmode(EntityUid uid, GodmodeComponent? godmode = nul // Rejuv to cover other stuff RaiseLocalEvent(uid, new RejuvenateEvent()); - - foreach (var (id, _) in _bodySystem.GetBodyChildren(uid)) // Shitmed Change - EnableGodmode(id); } public virtual void DisableGodmode(EntityUid uid, GodmodeComponent? godmode = null) diff --git a/Content.Shared/Gibbing/Systems/GibbingSystem.cs b/Content.Shared/Gibbing/Systems/GibbingSystem.cs index f3d982977a7..c511f5a04f4 100644 --- a/Content.Shared/Gibbing/Systems/GibbingSystem.cs +++ b/Content.Shared/Gibbing/Systems/GibbingSystem.cs @@ -122,10 +122,10 @@ public bool TryGibEntityWithRef( foreach (var container in _containerSystem.GetAllContainers(gibbable)) { var valid = true; - if (allowedContainers != null) - valid = allowedContainers.Contains(container.ID); - if (excludedContainers != null) - valid = valid && !excludedContainers.Contains(container.ID); + if (gibContentsAttempt.AllowedContainers != null) + valid = gibContentsAttempt.AllowedContainers.Contains(container.ID); + if (gibContentsAttempt.ExcludedContainers != null) + valid = valid && !gibContentsAttempt.ExcludedContainers.Contains(container.ID); if (valid) validContainers.Add(container); } diff --git a/Content.Shared/Humanoid/HumanoidVisualLayers.cs b/Content.Shared/Humanoid/HumanoidVisualLayers.cs index ac002bddd35..1b1febb6bc9 100644 --- a/Content.Shared/Humanoid/HumanoidVisualLayers.cs +++ b/Content.Shared/Humanoid/HumanoidVisualLayers.cs @@ -11,6 +11,7 @@ public enum HumanoidVisualLayers : byte Hair, FacialHair, Chest, + Groin, Head, Snout, HeadSide, // side parts (i.e., frills) diff --git a/Content.Shared/Humanoid/HumanoidVisualLayersExtension.cs b/Content.Shared/Humanoid/HumanoidVisualLayersExtension.cs index 17912e400a5..da4fbaf2780 100644 --- a/Content.Shared/Humanoid/HumanoidVisualLayersExtension.cs +++ b/Content.Shared/Humanoid/HumanoidVisualLayersExtension.cs @@ -86,8 +86,10 @@ public static IEnumerable Sublayers(HumanoidVisualLayers l { case BodyPartType.Other: break; - case BodyPartType.Torso: + case BodyPartType.Chest: return HumanoidVisualLayers.Chest; + case BodyPartType.Groin: + return HumanoidVisualLayers.Groin; case BodyPartType.Tail: return HumanoidVisualLayers.Tail; case BodyPartType.Head: diff --git a/Content.Shared/Input/ContentKeyFunctions.cs b/Content.Shared/Input/ContentKeyFunctions.cs index c6de1e88074..781157d55a1 100644 --- a/Content.Shared/Input/ContentKeyFunctions.cs +++ b/Content.Shared/Input/ContentKeyFunctions.cs @@ -63,7 +63,8 @@ public static class ContentKeyFunctions public static readonly BoundKeyFunction ResetZoom = "ResetZoom"; public static readonly BoundKeyFunction LookUp = "LookUp"; // BACKMEN EDIT public static readonly BoundKeyFunction TargetHead = "TargetHead"; - public static readonly BoundKeyFunction TargetTorso = "TargetTorso"; + public static readonly BoundKeyFunction TargetChest = "TargetChest"; + public static readonly BoundKeyFunction TargetGroin = "TargetGroin"; public static readonly BoundKeyFunction TargetLeftArm = "TargetLeftArm"; public static readonly BoundKeyFunction TargetLeftHand = "TargetLeftHand"; public static readonly BoundKeyFunction TargetRightArm = "TargetRightArm"; diff --git a/Content.Shared/MedicalScanner/HealthAnalyzerScannedUserMessage.cs b/Content.Shared/MedicalScanner/HealthAnalyzerScannedUserMessage.cs index 4ebce75991b..f0c05015322 100644 --- a/Content.Shared/MedicalScanner/HealthAnalyzerScannedUserMessage.cs +++ b/Content.Shared/MedicalScanner/HealthAnalyzerScannedUserMessage.cs @@ -1,5 +1,5 @@ +using Content.Shared.Backmen.Surgery.Wounds; using Content.Shared.Backmen.Targeting; -using Content.Shared.Body.Components; using Robust.Shared.Serialization; namespace Content.Shared.MedicalScanner; @@ -16,10 +16,10 @@ public sealed class HealthAnalyzerScannedUserMessage : BoundUserInterfaceMessage public bool? ScanMode; public bool? Bleeding; public bool? Unrevivable; - public Dictionary? Body; // backmen: surgery + public Dictionary? Body; // backmen: surgery public NetEntity? Part; // backmen: surgery - public HealthAnalyzerScannedUserMessage(NetEntity? targetEntity, float temperature, float bloodLevel, bool? scanMode, bool? bleeding, bool? unrevivable, Dictionary? body, NetEntity? part = null) + public HealthAnalyzerScannedUserMessage(NetEntity? targetEntity, float temperature, float bloodLevel, bool? scanMode, bool? bleeding, bool? unrevivable, Dictionary? body, NetEntity? part = null) { TargetEntity = targetEntity; Temperature = temperature; diff --git a/Content.Shared/Mobs/Systems/MobStateSystem.StateMachine.cs b/Content.Shared/Mobs/Systems/MobStateSystem.StateMachine.cs index fe6d36a23b5..e2e150147bb 100644 --- a/Content.Shared/Mobs/Systems/MobStateSystem.StateMachine.cs +++ b/Content.Shared/Mobs/Systems/MobStateSystem.StateMachine.cs @@ -114,6 +114,15 @@ private void ChangeState(EntityUid target, MobStateComponent component, MobState var ev = new MobStateChangedEvent(target, component, oldState, newState, origin); OnStateChanged(target, component, oldState, newState); RaiseLocalEvent(target, ev, true); + + if (_consciousness.TryGetNerveSystem(target, out var nerveSys)) + { + var ev1 = new MobStateChangedEvent(target, component, oldState, newState, origin); + RaiseLocalEvent(nerveSys.Value, ev1, true); + + // to handle consciousness related stuff. sorry + } + _adminLogger.Add(LogType.Damaged, oldState == MobState.Alive ? LogImpact.Low : LogImpact.Medium, $"{ToPrettyString(target):user} state changed from {oldState} to {newState}"); Dirty(target, component); diff --git a/Content.Shared/Mobs/Systems/MobStateSystem.cs b/Content.Shared/Mobs/Systems/MobStateSystem.cs index d3e55f0d698..8ac0470f643 100644 --- a/Content.Shared/Mobs/Systems/MobStateSystem.cs +++ b/Content.Shared/Mobs/Systems/MobStateSystem.cs @@ -1,8 +1,8 @@ using Content.Shared.ActionBlocker; using Content.Shared.Administration.Logs; +using Content.Shared.Backmen.Surgery.Consciousness.Systems; using Content.Shared.Mobs.Components; using Content.Shared.Standing; -using Robust.Shared.Physics.Systems; using Robust.Shared.Timing; namespace Content.Shared.Mobs.Systems; @@ -16,6 +16,7 @@ public partial class MobStateSystem : EntitySystem [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly ILogManager _logManager = default!; [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly ConsciousnessSystem _consciousness = default!; private ISawmill _sawmill = default!; private EntityQuery _mobStateQuery; diff --git a/Content.Shared/Mobs/Systems/MobThresholdSystem.cs b/Content.Shared/Mobs/Systems/MobThresholdSystem.cs index a059c18dd8f..6ba8d647459 100644 --- a/Content.Shared/Mobs/Systems/MobThresholdSystem.cs +++ b/Content.Shared/Mobs/Systems/MobThresholdSystem.cs @@ -1,11 +1,15 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Shared.Alert; +using Content.Shared.Backmen.Surgery.Wounds; +using Content.Shared.Backmen.Surgery.Wounds.Systems; +using Content.Shared.Body.Components; using Content.Shared.Damage; using Content.Shared.FixedPoint; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Events; using Robust.Shared.GameStates; +using Robust.Shared.Serialization; namespace Content.Shared.Mobs.Systems; @@ -14,6 +18,8 @@ public sealed class MobThresholdSystem : EntitySystem [Dependency] private readonly MobStateSystem _mobStateSystem = default!; [Dependency] private readonly AlertsSystem _alerts = default!; + [Dependency] private readonly WoundSystem _wound = default!; + public override void Initialize() { SubscribeLocalEvent(OnGetState); @@ -22,6 +28,7 @@ public override void Initialize() SubscribeLocalEvent(MobThresholdShutdown); SubscribeLocalEvent(MobThresholdStartup); SubscribeLocalEvent(OnDamaged); + SubscribeLocalEvent(OnWoundableDamage); SubscribeLocalEvent(OnUpdateMobState); SubscribeLocalEvent(OnThresholdsMobState); } @@ -306,17 +313,18 @@ public void SetMobStateThreshold(EntityUid target, FixedPoint2 damage, MobState /// Threshold Component owned by the Target /// MobState Component owned by the Target /// Damageable Component owned by the Target + /// Body Component owned by the Target public void VerifyThresholds(EntityUid target, MobThresholdsComponent? threshold = null, - MobStateComponent? mobState = null, DamageableComponent? damageable = null) + MobStateComponent? mobState = null, DamageableComponent? damageable = null, BodyComponent? body = null) { - if (!Resolve(target, ref mobState, ref threshold, ref damageable)) + if (!Resolve(target, ref mobState, ref threshold)) return; - CheckThresholds(target, mobState, threshold, damageable); + if (damageable != null) + CheckThresholds(target, mobState, threshold, damageable); + RaiseNetworkEvent(new MobThresholdChecked(GetNetEntity(target)), target); - var ev = new MobThresholdChecked(target, mobState, threshold, damageable); - RaiseLocalEvent(target, ref ev, true); - UpdateAlerts(target, mobState.CurrentState, threshold, damageable); + UpdateAlerts(target, mobState.CurrentState, threshold, damageable, body); } public void SetAllowRevives(EntityUid uid, bool val, MobThresholdsComponent? component = null) @@ -368,9 +376,9 @@ private void TriggerThreshold( } private void UpdateAlerts(EntityUid target, MobState currentMobState, MobThresholdsComponent? threshold = null, - DamageableComponent? damageable = null) + DamageableComponent? damageable = null, BodyComponent? body = null) { - if (!Resolve(target, ref threshold, ref damageable)) + if (!Resolve(target, ref threshold)) return; // don't handle alerts if they are managed by another system... BobbySim (soon TM) @@ -391,6 +399,24 @@ private void UpdateAlerts(EntityUid target, MobState currentMobState, MobThresho if (alertPrototype.SupportsSeverity) { + var totalDamage = (FixedPoint2) 0; + switch (body) + { + case null when damageable != null: + totalDamage = damageable.TotalDamage; + break; + + case { RootContainer.ContainedEntity: not null }: + { + foreach (var (_, wound) in _wound.GetAllWounds(body.RootContainer.ContainedEntity.Value)) + { + totalDamage += wound.WoundSeverityPoint; + } + + break; + } + } + var severity = _alerts.GetMinSeverity(currentAlert); var ev = new BeforeAlertSeverityCheckEvent(currentAlert, severity); @@ -403,7 +429,7 @@ private void UpdateAlerts(EntityUid target, MobState currentMobState, MobThresho } if (TryGetNextState(target, currentMobState, out var nextState, threshold) && - TryGetPercentageForState(target, nextState.Value, damageable.TotalDamage, out var percentage)) + TryGetPercentageForState(target, nextState.Value, totalDamage, out var percentage)) { percentage = FixedPoint2.Clamp(percentage.Value, 0, 1); @@ -426,11 +452,22 @@ private void OnDamaged(EntityUid target, MobThresholdsComponent thresholds, Dama if (!TryComp(target, out var mobState)) return; CheckThresholds(target, mobState, thresholds, args.Damageable, args.Origin); - var ev = new MobThresholdChecked(target, mobState, thresholds, args.Damageable); - RaiseLocalEvent(target, ref ev, true); + RaiseNetworkEvent(new MobThresholdChecked(GetNetEntity(target)), target); + UpdateAlerts(target, mobState.CurrentState, thresholds, args.Damageable); } + private void OnWoundableDamage(EntityUid body, MobThresholdsComponent thresholds, WoundSeverityPointChangedOnBodyEvent args) + { + if (!TryComp(body, out var mobState)) + return; + + // mob states are handled by consciousness. so we fine here + RaiseNetworkEvent(new MobThresholdChecked(GetNetEntity(body)), body); + + UpdateAlerts(body, mobState.CurrentState, thresholds, null, Comp(body)); + } + private void MobThresholdStartup(EntityUid target, MobThresholdsComponent thresholds, ComponentStartup args) { if (!TryComp(target, out var mobState) || !TryComp(target, out var damageable)) @@ -457,16 +494,15 @@ private void OnUpdateMobState(EntityUid target, MobThresholdsComponent component } } - private void UpdateAllEffects(Entity ent, MobState currentState) + private void UpdateAllEffects(Entity ent, MobState currentState) { - var (_, thresholds, mobState, damageable) = ent; - if (Resolve(ent, ref thresholds, ref mobState, ref damageable)) + var (_, thresholds, mobState, damageable, bodyComponent) = ent; + if (Resolve(ent, ref thresholds, ref mobState)) { - var ev = new MobThresholdChecked(ent, mobState, thresholds, damageable); - RaiseLocalEvent(ent, ref ev, true); + RaiseNetworkEvent(new MobThresholdChecked(GetNetEntity(ent.Owner)), ent.Owner); } - UpdateAlerts(ent, currentState, thresholds, damageable); + UpdateAlerts(ent, currentState, thresholds, damageable, bodyComponent); } private void OnThresholdsMobState(Entity ent, ref MobStateChangedEvent args) @@ -480,10 +516,14 @@ private void OnThresholdsMobState(Entity ent, ref MobSta /// /// Event that triggers when an entity with a mob threshold is checked /// -/// Target entity -/// Threshold Component owned by the Target -/// MobState Component owned by the Target -/// Damageable Component owned by the Target -[ByRefEvent] -public readonly record struct MobThresholdChecked(EntityUid Target, MobStateComponent MobState, - MobThresholdsComponent Threshold, DamageableComponent Damageable); +[Serializable, NetSerializable] +public sealed class MobThresholdChecked : EntityEventArgs +{ + public NetEntity Uid { get; } + public MobThresholdChecked(NetEntity uid) + { + Uid = uid; + } +} + + diff --git a/Content.Shared/Tourniquet/TourniquetSerializable.cs b/Content.Shared/Tourniquet/TourniquetSerializable.cs new file mode 100644 index 00000000000..cb8c2a136ff --- /dev/null +++ b/Content.Shared/Tourniquet/TourniquetSerializable.cs @@ -0,0 +1,14 @@ +using Content.Shared.DoAfter; +using Robust.Shared.Serialization; + +namespace Content.Shared.Tourniquet; + +[Serializable, NetSerializable] +public sealed partial class TourniquetDoAfterEvent : SimpleDoAfterEvent +{ +} + +[Serializable, NetSerializable] +public sealed partial class RemoveTourniquetDoAfterEvent : SimpleDoAfterEvent +{ +} diff --git a/Resources/Audio/Voice/BrutalDeathRattles/FemaleAgony1.ogg b/Resources/Audio/Voice/BrutalDeathRattles/FemaleAgony1.ogg new file mode 100644 index 00000000000..d5253393245 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/FemaleAgony1.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/FemaleAgony2.ogg b/Resources/Audio/Voice/BrutalDeathRattles/FemaleAgony2.ogg new file mode 100644 index 00000000000..df0b24f013c Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/FemaleAgony2.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/FemaleAgony3.ogg b/Resources/Audio/Voice/BrutalDeathRattles/FemaleAgony3.ogg new file mode 100644 index 00000000000..cabf1b4f577 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/FemaleAgony3.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort1.ogg b/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort1.ogg new file mode 100644 index 00000000000..d3dd0c7f9bf Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort1.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort2.ogg b/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort2.ogg new file mode 100644 index 00000000000..3ec4ef972f6 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort2.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort3.ogg b/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort3.ogg new file mode 100644 index 00000000000..b30bdd59b4d Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort3.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort4.ogg b/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort4.ogg new file mode 100644 index 00000000000..ce59ea38bdd Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort4.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort5.ogg b/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort5.ogg new file mode 100644 index 00000000000..a8d9a94e19c Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/FemalePainShort5.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/MaleAgony1.ogg b/Resources/Audio/Voice/BrutalDeathRattles/MaleAgony1.ogg new file mode 100644 index 00000000000..8a5989017a9 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/MaleAgony1.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/MaleAgony2.ogg b/Resources/Audio/Voice/BrutalDeathRattles/MaleAgony2.ogg new file mode 100644 index 00000000000..c453e69e6c0 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/MaleAgony2.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/MaleAgony3.ogg b/Resources/Audio/Voice/BrutalDeathRattles/MaleAgony3.ogg new file mode 100644 index 00000000000..24f60f91ea8 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/MaleAgony3.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort1.ogg b/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort1.ogg new file mode 100644 index 00000000000..dc301668e84 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort1.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort2.ogg b/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort2.ogg new file mode 100644 index 00000000000..d155c705348 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort2.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort3.ogg b/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort3.ogg new file mode 100644 index 00000000000..def7f556393 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort3.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort4.ogg b/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort4.ogg new file mode 100644 index 00000000000..f2c05ce19fb Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort4.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort5.ogg b/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort5.ogg new file mode 100644 index 00000000000..fa0e925c8e7 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort5.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort6.ogg b/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort6.ogg new file mode 100644 index 00000000000..594c4e2046e Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort6.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort7.ogg b/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort7.ogg new file mode 100644 index 00000000000..34b07145969 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/MalePainShort7.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/PainRattles1.ogg b/Resources/Audio/Voice/BrutalDeathRattles/PainRattles1.ogg new file mode 100644 index 00000000000..31106ca0b02 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/PainRattles1.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/PainRattles2.ogg b/Resources/Audio/Voice/BrutalDeathRattles/PainRattles2.ogg new file mode 100644 index 00000000000..96fb6e853c6 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/PainRattles2.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/PainRattles3.ogg b/Resources/Audio/Voice/BrutalDeathRattles/PainRattles3.ogg new file mode 100644 index 00000000000..9769d4752dc Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/PainRattles3.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/PainShockFemale1.ogg b/Resources/Audio/Voice/BrutalDeathRattles/PainShockFemale1.ogg new file mode 100644 index 00000000000..3a34e6aa256 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/PainShockFemale1.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/PainShockFemale2.ogg b/Resources/Audio/Voice/BrutalDeathRattles/PainShockFemale2.ogg new file mode 100644 index 00000000000..022cd389ab1 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/PainShockFemale2.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/PainShockFemale3.ogg b/Resources/Audio/Voice/BrutalDeathRattles/PainShockFemale3.ogg new file mode 100644 index 00000000000..3cec8f7d792 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/PainShockFemale3.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/PainShockMale1.ogg b/Resources/Audio/Voice/BrutalDeathRattles/PainShockMale1.ogg new file mode 100644 index 00000000000..25b5d0becd3 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/PainShockMale1.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/PainShockMale2.ogg b/Resources/Audio/Voice/BrutalDeathRattles/PainShockMale2.ogg new file mode 100644 index 00000000000..d5eefff5eaa Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/PainShockMale2.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/PainShockMale3.ogg b/Resources/Audio/Voice/BrutalDeathRattles/PainShockMale3.ogg new file mode 100644 index 00000000000..56be63014ab Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/PainShockMale3.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/PainShockMale4.ogg b/Resources/Audio/Voice/BrutalDeathRattles/PainShockMale4.ogg new file mode 100644 index 00000000000..c531153dbff Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/PainShockMale4.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/StillAliveFemale1.ogg b/Resources/Audio/Voice/BrutalDeathRattles/StillAliveFemale1.ogg new file mode 100644 index 00000000000..a0b6b7e7a61 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/StillAliveFemale1.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/StillAliveFemale2.ogg b/Resources/Audio/Voice/BrutalDeathRattles/StillAliveFemale2.ogg new file mode 100644 index 00000000000..250fc42ea7d Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/StillAliveFemale2.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/StillAliveFemale3.ogg b/Resources/Audio/Voice/BrutalDeathRattles/StillAliveFemale3.ogg new file mode 100644 index 00000000000..90bacbed686 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/StillAliveFemale3.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/StillAliveMale1.ogg b/Resources/Audio/Voice/BrutalDeathRattles/StillAliveMale1.ogg new file mode 100644 index 00000000000..f1b39760149 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/StillAliveMale1.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/StillAliveMale2.ogg b/Resources/Audio/Voice/BrutalDeathRattles/StillAliveMale2.ogg new file mode 100644 index 00000000000..f14560c2a2a Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/StillAliveMale2.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/StillAliveMale3.ogg b/Resources/Audio/Voice/BrutalDeathRattles/StillAliveMale3.ogg new file mode 100644 index 00000000000..fe64674dc1a Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/StillAliveMale3.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/StillAliveMale4.ogg b/Resources/Audio/Voice/BrutalDeathRattles/StillAliveMale4.ogg new file mode 100644 index 00000000000..0cc92761286 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/StillAliveMale4.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/StillAlivePainedFemale1.ogg b/Resources/Audio/Voice/BrutalDeathRattles/StillAlivePainedFemale1.ogg new file mode 100644 index 00000000000..62f301c3426 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/StillAlivePainedFemale1.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/StillAlivePainedMale1.ogg b/Resources/Audio/Voice/BrutalDeathRattles/StillAlivePainedMale1.ogg new file mode 100644 index 00000000000..c059268c615 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/StillAlivePainedMale1.ogg differ diff --git a/Resources/Audio/Voice/BrutalDeathRattles/StillAlivePainedMale2.ogg b/Resources/Audio/Voice/BrutalDeathRattles/StillAlivePainedMale2.ogg new file mode 100644 index 00000000000..9e71c8d1807 Binary files /dev/null and b/Resources/Audio/Voice/BrutalDeathRattles/StillAlivePainedMale2.ogg differ diff --git a/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone1.ogg b/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone1.ogg new file mode 100644 index 00000000000..0651cdd67d7 Binary files /dev/null and b/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone1.ogg differ diff --git a/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone2.ogg b/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone2.ogg new file mode 100644 index 00000000000..2eb3fb8cd9e Binary files /dev/null and b/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone2.ogg differ diff --git a/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone3.ogg b/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone3.ogg new file mode 100644 index 00000000000..2bbe6577b3b Binary files /dev/null and b/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone3.ogg differ diff --git a/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone4.ogg b/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone4.ogg new file mode 100644 index 00000000000..01f7f1cbdcd Binary files /dev/null and b/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone4.ogg differ diff --git a/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone5.ogg b/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone5.ogg new file mode 100644 index 00000000000..2bdcd3a03c6 Binary files /dev/null and b/Resources/Audio/_Shitmed/ReBELL/Bone/BoneGone5.ogg differ diff --git a/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated1.ogg b/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated1.ogg new file mode 100644 index 00000000000..4f11511db09 Binary files /dev/null and b/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated1.ogg differ diff --git a/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated2.ogg b/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated2.ogg new file mode 100644 index 00000000000..acb2a197e93 Binary files /dev/null and b/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated2.ogg differ diff --git a/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated3.ogg b/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated3.ogg new file mode 100644 index 00000000000..eb68666772d Binary files /dev/null and b/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated3.ogg differ diff --git a/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated4.ogg b/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated4.ogg new file mode 100644 index 00000000000..bb27991833a Binary files /dev/null and b/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated4.ogg differ diff --git a/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableDestroyed1.ogg b/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableDestroyed1.ogg new file mode 100644 index 00000000000..b7a504bc2d5 Binary files /dev/null and b/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableDestroyed1.ogg differ diff --git a/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableDestroyed2.ogg b/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableDestroyed2.ogg new file mode 100644 index 00000000000..e3b43e518f5 Binary files /dev/null and b/Resources/Audio/_Shitmed/ReBELL/Woundables/WoundableDestroyed2.ogg differ diff --git a/Resources/Locale/ru-RU/armor/armor-examine.ftl b/Resources/Locale/ru-RU/armor/armor-examine.ftl index 75dbbdcbedc..719e01d2658 100644 --- a/Resources/Locale/ru-RU/armor/armor-examine.ftl +++ b/Resources/Locale/ru-RU/armor/armor-examine.ftl @@ -2,6 +2,7 @@ armor-examinable-verb-text = Броня armor-examinable-verb-message = Изучить показатели брони. armor-examine = Обеспечивает следующую защиту: +armor-coverage-value = - [color=yellow]Этот элемент брони уменьшает входящий урон по { $type } части тела.[/color] armor-coefficient-value = - [color=yellow]{ $type }[/color] урон снижается на [color=lightblue]{ $value }%[/color]. armor-reduction-value = - [color=yellow]{ $type }[/color] урон снижается на [color=lightblue]{ $value }[/color]. armor-damage-type-blunt = Ударный @@ -20,3 +21,13 @@ armor-damage-type-poison = Ядовитый armor-damage-type-shock = Электрический armor-damage-type-structural = Структурный armor-damage-type-holy = Святой + +armor-coverage-type-arm = руки +armor-coverage-type-hand = ладонь +armor-coverage-type-foot = стопа +armor-coverage-type-leg = нога +armor-coverage-type-chest = грудь +armor-coverage-type-groin = пах +armor-coverage-type-head = голова +armor-coverage-type-tail = хвост +armor-coverage-type-other = прочее diff --git a/Resources/Locale/ru-RU/guidebook/chemistry/effects.ftl b/Resources/Locale/ru-RU/guidebook/chemistry/effects.ftl index 58a83bf5088..cf27fabc553 100644 --- a/Resources/Locale/ru-RU/guidebook/chemistry/effects.ftl +++ b/Resources/Locale/ru-RU/guidebook/chemistry/effects.ftl @@ -374,3 +374,8 @@ reagent-effect-guidebook-plant-seeds-remove = [1] Убирает *[other] убирают } семена из растения +reagent-effect-guidebook-suppress-pain = + { $chance -> + [1] подавляет + *[other] подавляют + } боль употребившего diff --git a/Resources/Locale/ru-RU/medical/components/healing-component.ftl b/Resources/Locale/ru-RU/medical/components/healing-component.ftl index 7b042a8aa9b..353c23adf83 100644 --- a/Resources/Locale/ru-RU/medical/components/healing-component.ftl +++ b/Resources/Locale/ru-RU/medical/components/healing-component.ftl @@ -1,5 +1,14 @@ medical-item-finished-using = Вы закончили лечить при помощи { $item } medical-item-cant-use = Нет повреждений, которые можно вылечить при помощи { $item } +medical-item-cant-use-rebell = Вы не можете помочь { $target }. Слишком много крови. +rebell-medical-item-stop-bleeding-fully = Вы остановили кровотечение. +rebell-medical-item-stop-bleeding-partially = Вы частично остановили кровотечение. +does-not-exist-rebell = Эта часть тела отсутствует. +puts-on-a-tourniquet = { CAPITALIZE($user) } накладывает тyрникет на часть тела { $part }. +takes-off-a-tourniquet = { CAPITALIZE($user) } снимает тyрникет с части тела { $part }. +take-off-tourniquet = Cнять тyрникет: { $part } +already-tourniqueted = Eще один тyрникет будет смертельным. +cant-tourniquet = Hевозможно наложить тyрникет. medical-item-stop-bleeding = { CAPITALIZE(OBJECT($target)) } кровотечение прекратилось medical-item-stop-bleeding-self = Ваше кровотечение прекратилось medical-item-popup-target = { CAPITALIZE($user) } пытается лечить вас при помощи { $item }! diff --git a/Resources/Locale/ru-RU/rebell/pain.ftl b/Resources/Locale/ru-RU/rebell/pain.ftl new file mode 100644 index 00000000000..03483f7184a --- /dev/null +++ b/Resources/Locale/ru-RU/rebell/pain.ftl @@ -0,0 +1,7 @@ +screams-and-flinches-pain = { $entity } кричит и дергается от боли! +screams-in-agony = { $entity } кричит от боли и нервозно дергается в агонии! +screams-and-falls-pain = { $entity } кричит от боли и падает на пол, дергаясь! +screams-in-pain = { $entity } кричит от боли и нервозно дергается! +passes-out-pain = { $entity } выдыхается и падает в обморок! + +woundable-dodged = { $entity } уклоняется! diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/clothing/outerclothing/coats.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/clothing/outerclothing/coats.ftl index 5036755ad75..5698789babb 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/clothing/outerclothing/coats.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/clothing/outerclothing/coats.ftl @@ -51,7 +51,7 @@ ent-ClothingOuterCoatRD = лабораторный халат научрука ent-ClothingOuterCoatRDOpened = { ent-ClothingOuterCoatRD } .desc = { ent-ClothingOuterCoatRD.desc } ent-ClothingOuterCoatPirate = одежда пирата - .desc = Яррр. + .desc = Друзья мои! На носу корабля враг! Йахарр! ent-ClothingOuterCoatWarden = бронированная куртка смотрителя .desc = Прочная, утилитарная куртка, предназначенная для защиты смотрителя от любых угроз, связанных с бригом. ent-ClothingOuterDameDane = пальто якудзы diff --git a/Resources/Maps/Corvax/Ruins/corvax_rnd_debris.yml b/Resources/Maps/Corvax/Ruins/corvax_rnd_debris.yml index c67d09823fd..d16e64ae70d 100644 --- a/Resources/Maps/Corvax/Ruins/corvax_rnd_debris.yml +++ b/Resources/Maps/Corvax/Ruins/corvax_rnd_debris.yml @@ -4285,14 +4285,6 @@ entities: - type: Transform pos: 6.5,17.5 parent: 1 -- proto: TorsoBorg - entities: - - uid: 368 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 12.391638,6.3357706 - parent: 1 - proto: ToyFigurineScientist entities: - uid: 298 diff --git a/Resources/Maps/Corvax/corvax_astra.yml b/Resources/Maps/Corvax/corvax_astra.yml index 44cbd7c1328..db0abc93b51 100644 --- a/Resources/Maps/Corvax/corvax_astra.yml +++ b/Resources/Maps/Corvax/corvax_astra.yml @@ -241503,20 +241503,6 @@ entities: - type: Transform pos: 109.50452,-22.239302 parent: 2 -- proto: TorsoSkeleton - entities: - - uid: 33478 - components: - - type: Transform - pos: 65.5,-50.5 - parent: 2 -- proto: TorsoSlime - entities: - - uid: 16254 - components: - - type: Transform - pos: 14.529345,-30.873055 - parent: 2 - proto: TowelColorNT entities: - uid: 1792 diff --git a/Resources/Maps/Corvax/corvax_gelta.yml b/Resources/Maps/Corvax/corvax_gelta.yml index 7cc1db0dcb9..34547d97278 100644 --- a/Resources/Maps/Corvax/corvax_gelta.yml +++ b/Resources/Maps/Corvax/corvax_gelta.yml @@ -136960,7 +136960,6 @@ entities: - 38178 - 38182 - 38184 - - 38191 paper_label: !type:ContainerSlot showEnts: False occludes: True @@ -268529,22 +268528,6 @@ entities: - type: Transform pos: 43.700527,-24.265348 parent: 13307 -- proto: TorsoHuman - entities: - - uid: 27998 - components: - - type: Transform - pos: 74.405785,-38.394585 - parent: 13307 -- proto: TorsoVulpkanin - entities: - - uid: 38191 - components: - - type: Transform - parent: 37590 - - type: Physics - canCollide: False - - type: InsideEntityStorage - proto: ToyAi entities: - uid: 13088 diff --git a/Resources/Maps/Corvax/corvax_outpost.yml b/Resources/Maps/Corvax/corvax_outpost.yml index 55acea2088a..99059e3578d 100644 --- a/Resources/Maps/Corvax/corvax_outpost.yml +++ b/Resources/Maps/Corvax/corvax_outpost.yml @@ -100401,13 +100401,6 @@ entities: - type: Transform pos: -28.316187,13.343903 parent: 2 -- proto: TorsoBorg - entities: - - uid: 12390 - components: - - type: Transform - pos: -73.75546,5.4194083 - parent: 2 - proto: ToyFigurineCaptain entities: - uid: 14948 diff --git a/Resources/Maps/Corvax/corvax_pearl.yml b/Resources/Maps/Corvax/corvax_pearl.yml index 32bb9c9273d..536877734fd 100644 --- a/Resources/Maps/Corvax/corvax_pearl.yml +++ b/Resources/Maps/Corvax/corvax_pearl.yml @@ -140289,21 +140289,6 @@ entities: - type: Transform pos: 47.472157,102.75783 parent: 1 -- proto: TorsoReptilian - entities: - - uid: 16355 - components: - - type: Transform - pos: 131.61108,47.669888 - parent: 1 -- proto: TorsoSkeleton - entities: - - uid: 17747 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 78.49516,161.7972 - parent: 1 - proto: ToyAi entities: - uid: 9696 diff --git a/Resources/Maps/Corvax/corvax_pilgrim.yml b/Resources/Maps/Corvax/corvax_pilgrim.yml index ba6865c8588..a610b1daabb 100644 --- a/Resources/Maps/Corvax/corvax_pilgrim.yml +++ b/Resources/Maps/Corvax/corvax_pilgrim.yml @@ -43268,7 +43268,7 @@ entities: Думаю, когда прилетит следующий экипаж, я попытаюсь затесаться среди них. Банальная история "ГП, я потерял свой КПК" должна сработать. Обязательно напишу книгу. Может, даже, научную работу? Но только за пределами сектора... - Я столкнулся со слишком резкой реакцией на, казалось бы, банальные вопросы. + Я столкнулся со слишком резкой реакцией на, казалось бы, банальные вопросы. Правда, на эти банальные вопросы я до сих пор не смог найти ответ... Словно какая-то невидимая сила не позволяет мне об этом нормально думать. Честно говоря, даже сейчас не могу сосредоточиться. Буду писать так быстро, как только смогу, и как только вспомню. @@ -98122,6 +98122,16 @@ entities: pos: -53.47,14.531252 parent: 2 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot + - Tail + - Other + dismembermentChanceDeduction: 1 modifiers: flatReductions: {} coefficients: diff --git a/Resources/Maps/Corvax/corvax_split.yml b/Resources/Maps/Corvax/corvax_split.yml index fc044ec67c7..f5c73176fff 100644 --- a/Resources/Maps/Corvax/corvax_split.yml +++ b/Resources/Maps/Corvax/corvax_split.yml @@ -258223,13 +258223,6 @@ entities: - type: Transform pos: 59.462196,3.473733 parent: 10755 -- proto: TorsoBorg - entities: - - uid: 23472 - components: - - type: Transform - pos: 36.457973,23.374575 - parent: 10755 - proto: ToyFigurineBartender entities: - uid: 35206 diff --git a/Resources/Maps/Corvax/corvax_tushkan.yml b/Resources/Maps/Corvax/corvax_tushkan.yml index 69540a06c25..589442f3ddf 100644 --- a/Resources/Maps/Corvax/corvax_tushkan.yml +++ b/Resources/Maps/Corvax/corvax_tushkan.yml @@ -73309,13 +73309,6 @@ entities: - type: Transform pos: -9.5,12.5 parent: 2 -- proto: TorsoBorg - entities: - - uid: 1216 - components: - - type: Transform - pos: -36.5,1.5 - parent: 2 - proto: TowelColorWhite entities: - uid: 9975 diff --git a/Resources/Maps/Dungeon/haunted.yml b/Resources/Maps/Dungeon/haunted.yml index b09b5a397b9..7bd51f2eb5e 100644 --- a/Resources/Maps/Dungeon/haunted.yml +++ b/Resources/Maps/Dungeon/haunted.yml @@ -2464,13 +2464,6 @@ entities: - type: Transform pos: 10.669119,46.594402 parent: 1653 -- proto: TorsoSkeleton - entities: - - uid: 325 - components: - - type: Transform - pos: 32.5085,20.620539 - parent: 1653 - proto: TrashBakedBananaPeel entities: - uid: 210 diff --git a/Resources/Maps/Dungeon/mineshaft.yml b/Resources/Maps/Dungeon/mineshaft.yml index 0eb996fe180..4afc3875e31 100644 --- a/Resources/Maps/Dungeon/mineshaft.yml +++ b/Resources/Maps/Dungeon/mineshaft.yml @@ -4669,18 +4669,6 @@ entities: - type: Transform pos: 33.405064,12.760937 parent: 2 -- proto: TorsoBorg - entities: - - uid: 807 - components: - - type: Transform - pos: 42.660984,19.533558 - parent: 2 - - uid: 835 - components: - - type: Transform - pos: 47.640297,19.235235 - parent: 2 - proto: VendingMachineChapel entities: - uid: 146 diff --git a/Resources/Maps/Salvage/ruin-cargo-salvage.yml b/Resources/Maps/Salvage/ruin-cargo-salvage.yml index 50c771700ce..8f3511e226f 100644 --- a/Resources/Maps/Salvage/ruin-cargo-salvage.yml +++ b/Resources/Maps/Salvage/ruin-cargo-salvage.yml @@ -2766,13 +2766,6 @@ entities: - type: Transform pos: -5.5,1.5 parent: 16 -- proto: TorsoSkeleton - entities: - - uid: 173 - components: - - type: Transform - pos: 6.6930027,-5.8542976 - parent: 16 - proto: ToyAi entities: - uid: 282 diff --git a/Resources/Maps/omega.yml b/Resources/Maps/omega.yml index c709fe0a6b5..2efc438ddc0 100644 --- a/Resources/Maps/omega.yml +++ b/Resources/Maps/omega.yml @@ -78816,13 +78816,6 @@ entities: - type: Transform pos: 26.489439,14.7007885 parent: 4812 -- proto: TorsoHuman - entities: - - uid: 12423 - components: - - type: Transform - pos: -53.589386,-16.742252 - parent: 4812 - proto: ToyIan entities: - uid: 2503 diff --git a/Resources/Prototypes/Body/Organs/Animal/animal.yml b/Resources/Prototypes/Body/Organs/Animal/animal.yml index 74d11600020..a88bb65cec6 100644 --- a/Resources/Prototypes/Body/Organs/Animal/animal.yml +++ b/Resources/Prototypes/Body/Organs/Animal/animal.yml @@ -192,6 +192,10 @@ state: brain - type: Organ slotId: brain # backmen: surgery + - type: NerveSystem # backmen: wounding + - type: ConsciousnessRequired + identifier: "nerveSystem" + causesDeath: true - type: Input context: "ghost" - type: Brain diff --git a/Resources/Prototypes/Body/Organs/diona.yml b/Resources/Prototypes/Body/Organs/diona.yml index 54137ae70f3..5a144f92ab9 100644 --- a/Resources/Prototypes/Body/Organs/diona.yml +++ b/Resources/Prototypes/Body/Organs/diona.yml @@ -39,6 +39,7 @@ - type: Organ # Shitmed slotId: Brain - type: Brain # Shitmed + - type: NerveSystem # backmen: wounding - type: SolutionContainerManager solutions: organ: diff --git a/Resources/Prototypes/Body/Organs/human.yml b/Resources/Prototypes/Body/Organs/human.yml index abce3f89cba..895258d1090 100644 --- a/Resources/Prototypes/Body/Organs/human.yml +++ b/Resources/Prototypes/Body/Organs/human.yml @@ -6,6 +6,10 @@ - type: Sprite sprite: Mobs/Species/Human/organs.rsi - type: Organ + integrityThresholds: + Normal: 15 + Damaged: 6 + Destroyed: 0 - type: Food - type: Extractable grindableSolutionName: organ @@ -44,8 +48,18 @@ state: brain - type: Organ slotId: brain # backmen: surgery + intCap: 28 + integrity: 28 + integrityThresholds: + Normal: 28 + Damaged: 16 + Destroyed: 0 - type: Input context: "ghost" + - type: NerveSystem + - type: ConsciousnessRequired + identifier: "nerveSystem" + causesDeath: true - type: Brain - type: InputMover - type: Examiner diff --git a/Resources/Prototypes/Body/Parts/Animal/kobold.yml b/Resources/Prototypes/Body/Parts/Animal/kobold.yml index 2ca5bd7ea78..3029f443d63 100644 --- a/Resources/Prototypes/Body/Parts/Animal/kobold.yml +++ b/Resources/Prototypes/Body/Parts/Animal/kobold.yml @@ -15,13 +15,29 @@ Quantity: 10 - type: entity - id: TorsoKobold - name: "Kobold torso" - parent: [PartKobold, BaseTorso] + id: ChestKobold + name: "Kobold chest" + parent: [BaseChest, PartKobold] components: - type: Sprite sprite: Mobs/Animals/kobold.rsi - state: "torso_m" + state: "chest_m" + - type: Extractable + juiceSolution: + reagents: + - ReagentId: Fat + Quantity: 10 + - ReagentId: Blood + Quantity: 20 + +- type: entity + id: GroinKobold + name: "Kobold groin" + parent: [BaseGroin, PartKobold] + components: + - type: Sprite + sprite: Mobs/Animals/kobold.rsi + state: "groin_m" - type: Extractable juiceSolution: reagents: @@ -33,7 +49,7 @@ - type: entity id: HeadKobold name: "Kobold head" - parent: [PartKobold, BaseHead] + parent: [BaseHead, PartKobold] components: - type: Sprite sprite: Mobs/Animals/kobold.rsi @@ -49,7 +65,7 @@ - type: entity id: LeftArmKobold name: "left Kobold arm" - parent: [PartKobold, BaseLeftArm] + parent: [BaseLeftArm, PartKobold] components: - type: Sprite sprite: Mobs/Animals/kobold.rsi @@ -58,7 +74,7 @@ - type: entity id: RightArmKobold name: "right Kobold arm" - parent: [PartKobold, BaseRightArm] + parent: [BaseRightArm, PartKobold] components: - type: Sprite sprite: Mobs/Animals/kobold.rsi @@ -67,7 +83,7 @@ - type: entity id: LeftHandKobold name: "left Kobold hand" - parent: [PartKobold, BaseLeftHand] + parent: [BaseLeftHand, PartKobold] components: - type: Sprite sprite: Mobs/Animals/kobold.rsi @@ -76,7 +92,7 @@ - type: entity id: RightHandKobold name: "right Kobold hand" - parent: [PartKobold, BaseRightHand] + parent: [BaseRightHand, PartKobold] components: - type: Sprite sprite: Mobs/Animals/kobold.rsi @@ -85,7 +101,7 @@ - type: entity id: LeftLegKobold name: "left Kobold leg" - parent: [PartKobold, BaseLeftLeg] + parent: [BaseLeftLeg, PartKobold] components: - type: Sprite sprite: Mobs/Animals/kobold.rsi @@ -94,7 +110,7 @@ - type: entity id: RightLegKobold name: "right Kobold leg" - parent: [PartKobold, BaseRightLeg] + parent: [BaseRightLeg, PartKobold] components: - type: Sprite sprite: Mobs/Animals/kobold.rsi @@ -103,7 +119,7 @@ - type: entity id: LeftFootKobold name: "left Kobold foot" - parent: [PartKobold, BaseLeftFoot] + parent: [BaseLeftFoot, PartKobold] components: - type: Sprite sprite: Mobs/Animals/kobold.rsi @@ -112,7 +128,7 @@ - type: entity id: RightFootKobold name: "right Kobold foot" - parent: [PartKobold, BaseRightFoot] + parent: [BaseRightFoot, PartKobold] components: - type: Sprite sprite: Mobs/Animals/kobold.rsi diff --git a/Resources/Prototypes/Body/Parts/Animal/monkey.yml b/Resources/Prototypes/Body/Parts/Animal/monkey.yml index 01b8aa4de8a..b82c145181a 100644 --- a/Resources/Prototypes/Body/Parts/Animal/monkey.yml +++ b/Resources/Prototypes/Body/Parts/Animal/monkey.yml @@ -15,13 +15,29 @@ Quantity: 10 - type: entity - id: TorsoMonkey - name: "monkey torso" - parent: [PartMonkey, BaseTorso] + id: ChestMonkey + name: "monkey chest" + parent: [BaseChest, PartMonkey] components: - type: Sprite sprite: Mobs/Animals/monkey.rsi - state: "torso_m" + state: "chest_m" + - type: Extractable + juiceSolution: + reagents: + - ReagentId: Fat + Quantity: 10 + - ReagentId: Blood + Quantity: 20 + +- type: entity + id: GroinMonkey + name: "monkey groin" + parent: [BaseGroin, PartMonkey] + components: + - type: Sprite + sprite: Mobs/Animals/monkey.rsi + state: "groin_m" - type: Extractable juiceSolution: reagents: @@ -33,7 +49,7 @@ - type: entity id: HeadMonkey name: "monkey head" - parent: [PartMonkey, BaseHead] + parent: [BaseHead, PartMonkey] components: - type: Sprite sprite: Mobs/Animals/monkey.rsi @@ -49,7 +65,7 @@ - type: entity id: LeftArmMonkey name: "left monkey arm" - parent: [PartMonkey, BaseLeftArm] + parent: [BaseLeftArm, PartMonkey] components: - type: Sprite sprite: Mobs/Animals/monkey.rsi @@ -58,7 +74,7 @@ - type: entity id: RightArmMonkey name: "right monkey arm" - parent: [PartMonkey, BaseRightArm] + parent: [BaseRightArm, PartMonkey] components: - type: Sprite sprite: Mobs/Animals/monkey.rsi @@ -67,7 +83,7 @@ - type: entity id: LeftHandMonkey name: "left monkey hand" - parent: [PartMonkey, BaseLeftHand] + parent: [BaseLeftHand, PartMonkey] components: - type: Sprite sprite: Mobs/Animals/monkey.rsi @@ -76,7 +92,7 @@ - type: entity id: RightHandMonkey name: "right monkey hand" - parent: [PartMonkey, BaseRightHand] + parent: [BaseRightHand, PartMonkey] components: - type: Sprite sprite: Mobs/Animals/monkey.rsi @@ -85,7 +101,7 @@ - type: entity id: LeftLegMonkey name: "left monkey leg" - parent: [PartMonkey, BaseLeftLeg] + parent: [BaseLeftLeg, PartMonkey] components: - type: Sprite sprite: Mobs/Animals/monkey.rsi @@ -94,7 +110,7 @@ - type: entity id: RightLegMonkey name: "right monkey leg" - parent: [PartMonkey, BaseRightLeg] + parent: [BaseRightLeg, PartMonkey] components: - type: Sprite sprite: Mobs/Animals/monkey.rsi @@ -103,7 +119,7 @@ - type: entity id: LeftFootMonkey name: "left monkey foot" - parent: [PartMonkey, BaseLeftFoot] + parent: [BaseLeftFoot, PartMonkey] components: - type: Sprite sprite: Mobs/Animals/monkey.rsi @@ -112,7 +128,7 @@ - type: entity id: RightFootMonkey name: "right monkey foot" - parent: [PartMonkey, BaseRightFoot] + parent: [BaseRightFoot, PartMonkey] components: - type: Sprite sprite: Mobs/Animals/monkey.rsi diff --git a/Resources/Prototypes/Body/Parts/Animal/rat.yml b/Resources/Prototypes/Body/Parts/Animal/rat.yml index bd51e006f70..48facde640d 100644 --- a/Resources/Prototypes/Body/Parts/Animal/rat.yml +++ b/Resources/Prototypes/Body/Parts/Animal/rat.yml @@ -1,13 +1,13 @@ # Just copypasta of some animal basic body parts for interaction, # It's basically as animals except a different torso with different organs - type: entity - id: TorsoRat - name: "animal torso" + id: ChestRat + name: "animal chest" parent: PartAnimal categories: [ HideSpawnMenu ] components: - type: BodyPart - partType: Torso + partType: Chest - type: Damageable damageContainer: Biological - type: Tag diff --git a/Resources/Prototypes/Body/Parts/animal.yml b/Resources/Prototypes/Body/Parts/animal.yml index 4c79f342bdb..c2df6495a4e 100644 --- a/Resources/Prototypes/Body/Parts/animal.yml +++ b/Resources/Prototypes/Body/Parts/animal.yml @@ -77,16 +77,37 @@ slotId: feet # Shitmed - type: entity - id: TorsoAnimal - name: animal torso + id: ChestAnimal + name: animal chest parent: PartAnimal categories: [ HideSpawnMenu ] components: - type: Sprite layers: - - state: torso_m + - state: chest_m - type: BodyPart - partType: Torso + partType: Chest + - type: Damageable + damageContainer: Biological + - type: Extractable + juiceSolution: + reagents: + - ReagentId: Fat + Quantity: 10 + - ReagentId: Blood + Quantity: 20 + +- type: entity + id: GroinAnimal + name: animal groin + parent: PartAnimal + categories: [ HideSpawnMenu ] + components: + - type: Sprite + layers: + - state: groin_m + - type: BodyPart + partType: Groin - type: Damageable damageContainer: Biological - type: Extractable diff --git a/Resources/Prototypes/Body/Parts/arachnid.yml b/Resources/Prototypes/Body/Parts/arachnid.yml index d275bd91c63..db4e56d1dea 100644 --- a/Resources/Prototypes/Body/Parts/arachnid.yml +++ b/Resources/Prototypes/Body/Parts/arachnid.yml @@ -6,6 +6,14 @@ name: "arachnid body part" abstract: true components: + - type: WoundableVisuals + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#162581" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: Extractable juiceSolution: reagents: @@ -15,13 +23,29 @@ Quantity: 10 - type: entity - id: TorsoArachnid - name: "arachnid torso" - parent: [PartArachnid, BaseTorso] + id: ChestArachnid + name: "arachnid chest" + parent: [BaseChest, PartArachnid] components: - type: Sprite sprite: Mobs/Species/Arachnid/parts.rsi - state: "torso_m" + state: "chest_m" + - type: Extractable + juiceSolution: + reagents: + - ReagentId: Fat + Quantity: 10 + - ReagentId: CopperBlood + Quantity: 20 + +- type: entity + id: GroinArachnid + name: "arachnid groin" + parent: [BaseGroin, PartArachnid] + components: + - type: Sprite + sprite: Mobs/Species/Arachnid/parts.rsi + state: "groin_m" - type: Extractable juiceSolution: reagents: @@ -33,7 +57,7 @@ - type: entity id: HeadArachnid name: "arachnid head" - parent: [PartArachnid, BaseHead] + parent: [BaseHead, PartArachnid] components: - type: Sprite sprite: Mobs/Species/Arachnid/parts.rsi @@ -49,7 +73,7 @@ - type: entity id: LeftArmArachnid name: "left arachnid arm" - parent: [PartArachnid, BaseLeftArm] + parent: [BaseLeftArm, PartArachnid] components: - type: Sprite sprite: Mobs/Species/Arachnid/parts.rsi @@ -58,7 +82,7 @@ - type: entity id: RightArmArachnid name: "right arachnid arm" - parent: [PartArachnid, BaseRightArm] + parent: [BaseRightArm, PartArachnid] components: - type: Sprite sprite: Mobs/Species/Arachnid/parts.rsi @@ -67,7 +91,7 @@ - type: entity id: LeftHandArachnid name: "left arachnid hand" - parent: [PartArachnid, BaseLeftHand] + parent: [BaseLeftHand, PartArachnid] components: - type: Sprite sprite: Mobs/Species/Arachnid/parts.rsi @@ -76,7 +100,7 @@ - type: entity id: RightHandArachnid name: "right arachnid hand" - parent: [PartArachnid, BaseRightHand] + parent: [BaseRightHand, PartArachnid] components: - type: Sprite sprite: Mobs/Species/Arachnid/parts.rsi @@ -85,7 +109,7 @@ - type: entity id: LeftLegArachnid name: "left arachnid leg" - parent: [PartArachnid, BaseLeftLeg] + parent: [BaseLeftLeg, PartArachnid] components: - type: Sprite sprite: Mobs/Species/Arachnid/parts.rsi @@ -95,7 +119,7 @@ - type: entity id: RightLegArachnid name: "right arachnid leg" - parent: [PartArachnid, BaseRightLeg] + parent: [BaseRightLeg, PartArachnid] components: - type: Sprite sprite: Mobs/Species/Arachnid/parts.rsi @@ -105,7 +129,7 @@ - type: entity id: LeftFootArachnid name: "left arachnid foot" - parent: [PartArachnid, BaseLeftFoot] + parent: [BaseLeftFoot, PartArachnid] components: - type: Sprite sprite: Mobs/Species/Arachnid/parts.rsi @@ -114,7 +138,7 @@ - type: entity id: RightFootArachnid name: "right arachnid foot" - parent: [PartArachnid, BaseRightFoot] + parent: [BaseRightFoot, PartArachnid] components: - type: Sprite sprite: Mobs/Species/Arachnid/parts.rsi diff --git a/Resources/Prototypes/Body/Parts/base.yml b/Resources/Prototypes/Body/Parts/base.yml index 7505813574e..f8d92a22ffb 100644 --- a/Resources/Prototypes/Body/Parts/base.yml +++ b/Resources/Prototypes/Body/Parts/base.yml @@ -8,6 +8,26 @@ damageContainer: OrganicPart - type: BodyPart # start-backmen: surgery + - type: Woundable + integrity: 65 + integrityCap: 65 + thresholds: + Minor: 60 + Moderate: 45 + Severe: 30 + Critical: 12 + Loss: 0 + - type: WoundableVisuals + thresholds: [ 10, 20, 30, 50, 70, 100 ] + occupiedLayer: "enum.HumanoidVisualLayers.Chest" # Default to Chest if something anomalous happens. + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#FF0000" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi + - type: Nerve - type: SurgeryTool startSound: path: /Audio/Medical/Surgery/organ1.ogg @@ -24,6 +44,7 @@ tags: - Trash # start-backmen: surgery + - type: Appearance - type: Gibbable - type: Destructible thresholds: @@ -57,20 +78,76 @@ # end-backmen: surgery - type: entity - id: BaseTorso - name: "torso" + id: BaseChest + name: "сhest" parent: BasePart abstract: true components: - type: BodyPart - partType: Torso - # start-backmen: surgery - toolName: "a torso" - containerName: "torso_slot" + partType: Chest + toolName: "a сhest" + containerName: "сhest_slot" + - type: Woundable + integrity: 100 + integrityCap: 100 + thresholds: + Minor: 84 + Moderate: 70 + Severe: 55 + Critical: 30 + Loss: 0 + - type: WoundableVisuals + thresholds: [ 10, 20, 30, 50, 70, 100 ] + occupiedLayer: "enum.HumanoidVisualLayers.Chest" + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#FF0000" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi + - type: ConsciousnessRequired + identifier: "chest" + causesDeath: true - type: ContainerContainer containers: - torso_slot: !type:ContainerSlot {} - # end-backmen: surgery + сhest_slot: !type:ContainerSlot {} + +- type: entity + id: BaseGroin + name: "groin" + parent: BasePart + abstract: true + components: + - type: BodyPart + partType: Groin + toolName: "a groin" + containerName: "groin_slot" + - type: Woundable + integrity: 70 + integrityCap: 70 + thresholds: + Minor: 60 + Moderate: 47 + Severe: 33 + Critical: 17 + Loss: 0 + - type: WoundableVisuals + thresholds: [ 10, 20, 30, 50, 70, 100 ] + occupiedLayer: "enum.HumanoidVisualLayers.Groin" + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#FF0000" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi + - type: ConsciousnessRequired + identifier: "groin" + causesDeath: true + - type: ContainerContainer + containers: + groin_slot: !type:ContainerSlot {} - type: entity id: BaseHead @@ -84,6 +161,28 @@ vital: true - type: Input context: "ghost" + - type: Woundable + integrity: 42 + integrityCap: 42 + thresholds: + Minor: 36 + Moderate: 30 + Severe: 24 + Critical: 12 + Loss: 0 + - type: WoundableVisuals + thresholds: [ 10, 20, 30, 50, 70, 100 ] + occupiedLayer: "enum.HumanoidVisualLayers.Head" + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#FF0000" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi + - type: ConsciousnessRequired + identifier: "head" + causesDeath: true - type: Tag tags: - Head @@ -94,6 +193,16 @@ parent: BasePart abstract: true components: + - type: WoundableVisuals + thresholds: [ 10, 20, 30, 50, 70, 100 ] + occupiedLayer: "enum.HumanoidVisualLayers.LArm" + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#FF0000" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: BodyPart partType: Arm symmetry: Left @@ -105,6 +214,16 @@ parent: BasePart abstract: true components: + - type: WoundableVisuals + thresholds: [ 10, 20, 30, 50, 70, 100 ] + occupiedLayer: "enum.HumanoidVisualLayers.RArm" + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#FF0000" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: BodyPart partType: Arm symmetry: Right @@ -116,10 +235,29 @@ parent: BasePart abstract: true components: + - type: WoundableVisuals + thresholds: [ 10, 20, 30, 50, 70, 100 ] + occupiedLayer: "enum.HumanoidVisualLayers.LHand" + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#FF0000" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: BodyPart partType: Hand symmetry: Left toolName: "a left hand" # backmen: surgery + - type: Woundable + integrity: 50 + integrityCap: 50 + thresholds: + Minor: 42 + Moderate: 36 + Severe: 26 + Critical: 15 + Loss: 0 - type: entity id: BaseRightHand @@ -127,10 +265,29 @@ parent: BasePart abstract: true components: + - type: WoundableVisuals + thresholds: [ 10, 20, 30, 50, 70, 100 ] + occupiedLayer: "enum.HumanoidVisualLayers.RHand" + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#FF0000" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: BodyPart partType: Hand symmetry: Right toolName: "a right hand" # backmen: surgery + - type: Woundable + integrity: 50 + integrityCap: 50 + thresholds: + Minor: 42 + Moderate: 36 + Severe: 26 + Critical: 15 + Loss: 0 - type: entity id: BaseLeftLeg @@ -138,6 +295,16 @@ parent: BasePart abstract: true components: + - type: WoundableVisuals + thresholds: [ 10, 20, 30, 50, 70, 100 ] + occupiedLayer: "enum.HumanoidVisualLayers.LLeg" + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#FF0000" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: BodyPart partType: Leg symmetry: Left @@ -150,6 +317,16 @@ parent: BasePart abstract: true components: + - type: WoundableVisuals + thresholds: [ 10, 20, 30, 50, 70, 100 ] + occupiedLayer: "enum.HumanoidVisualLayers.RLeg" + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#FF0000" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: BodyPart partType: Leg symmetry: Right @@ -162,10 +339,29 @@ parent: BasePart abstract: true components: + - type: WoundableVisuals + thresholds: [ 10, 20, 30, 50, 70, 100 ] + occupiedLayer: "enum.HumanoidVisualLayers.LFoot" + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#FF0000" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: BodyPart partType: Foot symmetry: Left toolName: "a left foot" # backmen: surgery + - type: Woundable + integrity: 50 + integrityCap: 50 + thresholds: + Minor: 42 + Moderate: 36 + Severe: 26 + Critical: 15 + Loss: 0 - type: entity id: BaseRightFoot @@ -173,7 +369,26 @@ parent: BasePart abstract: true components: + - type: WoundableVisuals + thresholds: [ 10, 20, 30, 50, 70, 100 ] + occupiedLayer: "enum.HumanoidVisualLayers.RFoot" + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#FF0000" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: BodyPart partType: Foot symmetry: Right toolName: "a right foot" # backmen: surgery + - type: Woundable + integrity: 50 + integrityCap: 50 + thresholds: + Minor: 42 + Moderate: 36 + Severe: 26 + Critical: 15 + Loss: 0 diff --git a/Resources/Prototypes/Body/Parts/diona.yml b/Resources/Prototypes/Body/Parts/diona.yml index 5257512aaab..6ea7b0a5810 100644 --- a/Resources/Prototypes/Body/Parts/diona.yml +++ b/Resources/Prototypes/Body/Parts/diona.yml @@ -4,21 +4,37 @@ name: "diona body part" abstract: true components: + - type: WoundableVisuals + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#cd7314" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: Sprite sprite: Mobs/Species/Diona/parts.rsi - type: entity - id: TorsoDiona - name: "diona torso" - parent: [PartDiona, BaseTorso] + id: ChestDiona + name: "diona chest" + parent: [BaseChest, PartDiona] components: - type: Sprite - state: "torso_m" + state: "chest_m" + +- type: entity + id: GroinDiona + name: "diona groin" + parent: [BaseGroin, PartDiona] + components: + - type: Sprite + state: "groin_m" - type: entity id: HeadDiona name: "diona head" - parent: [PartDiona, BaseHead] + parent: [BaseHead, PartDiona] components: - type: Sprite state: "head_m" @@ -26,7 +42,7 @@ - type: entity id: LeftArmDiona name: "left diona arm" - parent: [PartDiona, BaseLeftArm] + parent: [BaseLeftArm, PartDiona] components: - type: Sprite state: "l_arm" @@ -34,7 +50,7 @@ - type: entity id: RightArmDiona name: "right diona arm" - parent: [PartDiona, BaseRightArm] + parent: [BaseRightArm, PartDiona] components: - type: Sprite state: "r_arm" @@ -42,7 +58,7 @@ - type: entity id: LeftHandDiona name: "left diona hand" - parent: [PartDiona, BaseLeftHand] + parent: [BaseLeftHand, PartDiona] components: - type: Sprite state: "l_hand" @@ -50,7 +66,7 @@ - type: entity id: RightHandDiona name: "right diona hand" - parent: [PartDiona, BaseRightHand] + parent: [BaseRightHand, PartDiona] components: - type: Sprite state: "r_hand" @@ -58,7 +74,7 @@ - type: entity id: LeftLegDiona name: "left diona leg" - parent: [PartDiona, BaseLeftLeg] + parent: [BaseLeftLeg, PartDiona] components: - type: Sprite state: "l_leg" @@ -66,7 +82,7 @@ - type: entity id: RightLegDiona name: "right diona leg" - parent: [PartDiona, BaseRightLeg] + parent: [BaseRightLeg, PartDiona] components: - type: Sprite state: "r_leg" @@ -77,7 +93,7 @@ - type: entity id: LeftFootDiona name: "left diona foot" - parent: [PartDiona, BaseLeftFoot] + parent: [BaseLeftFoot, PartDiona] components: - type: Sprite state: "l_foot" @@ -88,7 +104,7 @@ - type: entity id: RightFootDiona name: "right diona foot" - parent: [PartDiona, BaseRightFoot] + parent: [BaseRightFoot, PartDiona] components: - type: Sprite state: "r_foot" diff --git a/Resources/Prototypes/Body/Parts/gingerbread.yml b/Resources/Prototypes/Body/Parts/gingerbread.yml index f95e66145be..c109cc341e9 100644 --- a/Resources/Prototypes/Body/Parts/gingerbread.yml +++ b/Resources/Prototypes/Body/Parts/gingerbread.yml @@ -4,6 +4,14 @@ name: "gingerbread body part" abstract: true components: + - type: WoundableVisuals + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#896e55" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: Extractable juiceSolution: reagents: @@ -13,13 +21,29 @@ Quantity: 10 - type: entity - id: TorsoGingerbread - name: "gingerbread torso" - parent: [PartGingerbread, BaseTorso] + id: ChestGingerbread + name: "gingerbread chest" + parent: [BaseChest, PartGingerbread] components: - type: Sprite sprite: Mobs/Species/Gingerbread/parts.rsi - state: "torso_m" + state: "chest_m" + - type: Extractable + juiceSolution: + reagents: + - ReagentId: Nutriment + Quantity: 10 + - ReagentId: Sugar + Quantity: 20 + +- type: entity + id: GroinGingerbread + name: "gingerbread groin" + parent: [BaseGroin, PartGingerbread] + components: + - type: Sprite + sprite: Mobs/Species/Gingerbread/parts.rsi + state: "groin_m" - type: Extractable juiceSolution: reagents: @@ -31,7 +55,7 @@ - type: entity id: HeadGingerbread name: "gingerbread head" - parent: [PartGingerbread, BaseHead] + parent: [BaseHead, PartGingerbread] components: - type: Sprite sprite: Mobs/Species/Gingerbread/parts.rsi @@ -47,7 +71,7 @@ - type: entity id: LeftArmGingerbread name: "left gingerbread arm" - parent: [PartGingerbread, BaseLeftArm] + parent: [BaseLeftArm, PartGingerbread] components: - type: Sprite sprite: Mobs/Species/Gingerbread/parts.rsi @@ -56,7 +80,7 @@ - type: entity id: RightArmGingerbread name: "right gingerbread arm" - parent: [PartGingerbread, BaseRightArm] + parent: [BaseRightArm, PartGingerbread] components: - type: Sprite sprite: Mobs/Species/Gingerbread/parts.rsi @@ -65,7 +89,7 @@ - type: entity id: LeftHandGingerbread name: "left gingerbread hand" - parent: [PartGingerbread, BaseLeftHand] + parent: [BaseLeftHand, PartGingerbread] components: - type: Sprite sprite: Mobs/Species/Gingerbread/parts.rsi @@ -74,7 +98,7 @@ - type: entity id: RightHandGingerbread name: "right gingerbread hand" - parent: [PartGingerbread, BaseRightHand] + parent: [BaseRightHand, PartGingerbread] components: - type: Sprite sprite: Mobs/Species/Gingerbread/parts.rsi @@ -83,7 +107,7 @@ - type: entity id: LeftLegGingerbread name: "left gingerbread leg" - parent: [PartGingerbread, BaseLeftLeg] + parent: [BaseLeftLeg, PartGingerbread] components: - type: Sprite sprite: Mobs/Species/Gingerbread/parts.rsi @@ -92,7 +116,7 @@ - type: entity id: RightLegGingerbread name: "right gingerbread leg" - parent: [PartGingerbread, BaseRightLeg] + parent: [BaseRightLeg, PartGingerbread] components: - type: Sprite sprite: Mobs/Species/Gingerbread/parts.rsi @@ -101,7 +125,7 @@ - type: entity id: LeftFootGingerbread name: "left gingerbread foot" - parent: [PartGingerbread, BaseLeftFoot] + parent: [BaseLeftFoot, PartGingerbread] components: - type: Sprite sprite: Mobs/Species/Gingerbread/parts.rsi @@ -110,7 +134,7 @@ - type: entity id: RightFootGingerbread name: "right gingerbread foot" - parent: [PartGingerbread, BaseRightFoot] + parent: [BaseRightFoot, PartGingerbread] components: - type: Sprite sprite: Mobs/Species/Gingerbread/parts.rsi diff --git a/Resources/Prototypes/Body/Parts/human.yml b/Resources/Prototypes/Body/Parts/human.yml index a1510fcdbb1..9ff267b0ebb 100644 --- a/Resources/Prototypes/Body/Parts/human.yml +++ b/Resources/Prototypes/Body/Parts/human.yml @@ -15,13 +15,29 @@ Quantity: 10 - type: entity - id: TorsoHuman - name: "human torso" - parent: [PartHuman, BaseTorso] + id: ChestHuman + name: "human chest" + parent: [BaseChest, PartHuman] components: - type: Sprite sprite: Mobs/Species/Human/parts.rsi - state: "torso_m" + state: "chest_m" + - type: Extractable + juiceSolution: + reagents: + - ReagentId: Fat + Quantity: 10 + - ReagentId: Blood + Quantity: 20 + +- type: entity + id: GroinHuman + name: "human groin" + parent: [BaseGroin, PartHuman] + components: + - type: Sprite + sprite: Mobs/Species/Human/parts.rsi + state: "groin_m" - type: Extractable juiceSolution: reagents: @@ -33,7 +49,7 @@ - type: entity id: HeadHuman name: "human head" - parent: [PartHuman, BaseHead] + parent: [BaseHead, PartHuman] components: - type: Sprite sprite: Mobs/Species/Human/parts.rsi @@ -49,7 +65,7 @@ - type: entity id: LeftArmHuman name: "left human arm" - parent: [PartHuman, BaseLeftArm] + parent: [BaseLeftArm, PartHuman] components: - type: Sprite sprite: Mobs/Species/Human/parts.rsi @@ -58,7 +74,7 @@ - type: entity id: RightArmHuman name: "right human arm" - parent: [PartHuman, BaseRightArm] + parent: [BaseRightArm, PartHuman] components: - type: Sprite sprite: Mobs/Species/Human/parts.rsi @@ -67,7 +83,7 @@ - type: entity id: LeftHandHuman name: "left human hand" - parent: [PartHuman, BaseLeftHand] + parent: [BaseLeftHand, PartHuman] components: - type: Sprite sprite: Mobs/Species/Human/parts.rsi @@ -76,7 +92,7 @@ - type: entity id: RightHandHuman name: "right human hand" - parent: [PartHuman, BaseRightHand] + parent: [BaseRightHand, PartHuman] components: - type: Sprite sprite: Mobs/Species/Human/parts.rsi @@ -85,7 +101,7 @@ - type: entity id: LeftLegHuman name: "left human leg" - parent: [PartHuman, BaseLeftLeg] + parent: [BaseLeftLeg, PartHuman] components: - type: Sprite sprite: Mobs/Species/Human/parts.rsi @@ -94,7 +110,7 @@ - type: entity id: RightLegHuman name: "right human leg" - parent: [PartHuman, BaseRightLeg] + parent: [BaseRightLeg, PartHuman] components: - type: Sprite sprite: Mobs/Species/Human/parts.rsi @@ -103,7 +119,7 @@ - type: entity id: LeftFootHuman name: "left human foot" - parent: [PartHuman, BaseLeftFoot] + parent: [BaseLeftFoot, PartHuman] components: - type: Sprite sprite: Mobs/Species/Human/parts.rsi @@ -112,7 +128,7 @@ - type: entity id: RightFootHuman name: "right human foot" - parent: [PartHuman, BaseRightFoot] + parent: [BaseRightFoot, PartHuman] components: - type: Sprite sprite: Mobs/Species/Human/parts.rsi diff --git a/Resources/Prototypes/Body/Parts/moth.yml b/Resources/Prototypes/Body/Parts/moth.yml index bb96430383a..4945d2d16fc 100644 --- a/Resources/Prototypes/Body/Parts/moth.yml +++ b/Resources/Prototypes/Body/Parts/moth.yml @@ -6,6 +6,14 @@ name: "moth body part" abstract: true components: + - type: WoundableVisuals + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#808A51" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: Extractable juiceSolution: reagents: @@ -15,13 +23,13 @@ Quantity: 10 - type: entity - id: TorsoMoth - name: "moth torso" - parent: [PartMoth, BaseTorso] + id: ChestMoth + name: "moth chest" + parent: [BaseChest, PartMoth] components: - type: Sprite sprite: Mobs/Species/Moth/parts.rsi - state: "torso_m" + state: "chest_m" - type: Extractable juiceSolution: reagents: @@ -30,11 +38,26 @@ - ReagentId: Blood Quantity: 20 +- type: entity + id: GroinMoth + name: "moth groin" + parent: [BaseGroin, PartMoth] + components: + - type: Sprite + sprite: Mobs/Species/Moth/parts.rsi + state: "groin_m" + - type: Extractable + juiceSolution: + reagents: + - ReagentId: Fat + Quantity: 10 + - ReagentId: Blood + Quantity: 20 - type: entity id: HeadMoth name: "moth head" - parent: [PartMoth, BaseHead] + parent: [BaseHead, PartMoth] components: - type: Sprite sprite: Mobs/Species/Moth/parts.rsi @@ -50,7 +73,7 @@ - type: entity id: LeftArmMoth name: "left moth arm" - parent: [PartMoth, BaseLeftArm] + parent: [BaseLeftArm, PartMoth] components: - type: Sprite sprite: Mobs/Species/Moth/parts.rsi @@ -59,7 +82,7 @@ - type: entity id: RightArmMoth name: "right moth arm" - parent: [PartMoth, BaseRightArm] + parent: [BaseRightArm, PartMoth] components: - type: Sprite sprite: Mobs/Species/Moth/parts.rsi @@ -68,7 +91,7 @@ - type: entity id: LeftHandMoth name: "left moth hand" - parent: [PartMoth, BaseLeftHand] + parent: [BaseLeftHand, PartMoth] components: - type: Sprite sprite: Mobs/Species/Moth/parts.rsi @@ -77,7 +100,7 @@ - type: entity id: RightHandMoth name: "right moth hand" - parent: [PartMoth, BaseRightHand] + parent: [BaseRightHand, PartMoth] components: - type: Sprite sprite: Mobs/Species/Moth/parts.rsi @@ -86,7 +109,7 @@ - type: entity id: LeftLegMoth name: "left moth leg" - parent: [PartMoth, BaseLeftLeg] + parent: [BaseLeftLeg, PartMoth] components: - type: Sprite sprite: Mobs/Species/Moth/parts.rsi @@ -95,7 +118,7 @@ - type: entity id: RightLegMoth name: "right moth leg" - parent: [PartMoth, BaseRightLeg] + parent: [BaseRightLeg, PartMoth] components: - type: Sprite sprite: Mobs/Species/Moth/parts.rsi @@ -104,7 +127,7 @@ - type: entity id: LeftFootMoth name: "left moth foot" - parent: [PartMoth, BaseLeftFoot] + parent: [BaseLeftFoot, PartMoth] components: - type: Sprite sprite: Mobs/Species/Moth/parts.rsi @@ -113,7 +136,7 @@ - type: entity id: RightFootMoth name: "right moth foot" - parent: [PartMoth, BaseRightFoot] + parent: [BaseRightFoot, PartMoth] components: - type: Sprite sprite: Mobs/Species/Moth/parts.rsi diff --git a/Resources/Prototypes/Body/Parts/reptilian.yml b/Resources/Prototypes/Body/Parts/reptilian.yml index a299636352a..62d05e0fc7f 100644 --- a/Resources/Prototypes/Body/Parts/reptilian.yml +++ b/Resources/Prototypes/Body/Parts/reptilian.yml @@ -15,13 +15,29 @@ Quantity: 10 - type: entity - id: TorsoReptilian - name: "reptilian torso" - parent: [PartReptilian, BaseTorso] + id: ChestReptilian + name: "reptilian chest" + parent: [BaseChest, PartReptilian] components: - type: Sprite sprite: Mobs/Species/Reptilian/parts.rsi - state: "torso_m" + state: "chest_m" + - type: Extractable + juiceSolution: + reagents: + - ReagentId: Fat + Quantity: 10 + - ReagentId: Blood + Quantity: 20 + +- type: entity + id: GroinReptilian + name: "reptilian groin" + parent: [BaseGroin, PartReptilian] + components: + - type: Sprite + sprite: Mobs/Species/Reptilian/parts.rsi + state: "groin_m" - type: Extractable juiceSolution: reagents: @@ -33,7 +49,7 @@ - type: entity id: HeadReptilian name: "reptilian head" - parent: [PartReptilian, BaseHead] + parent: [BaseHead, PartReptilian] components: - type: Sprite sprite: Mobs/Species/Reptilian/parts.rsi @@ -49,7 +65,7 @@ - type: entity id: LeftArmReptilian name: "left reptilian arm" - parent: [PartReptilian, BaseLeftArm] + parent: [BaseLeftArm, PartReptilian] components: - type: Sprite sprite: Mobs/Species/Reptilian/parts.rsi @@ -58,7 +74,7 @@ - type: entity id: RightArmReptilian name: "right reptilian arm" - parent: [PartReptilian, BaseRightArm] + parent: [BaseRightArm, PartReptilian] components: - type: Sprite sprite: Mobs/Species/Reptilian/parts.rsi @@ -67,7 +83,7 @@ - type: entity id: LeftHandReptilian name: "left reptilian hand" - parent: [PartReptilian, BaseLeftHand] + parent: [BaseLeftHand, PartReptilian] components: - type: Sprite sprite: Mobs/Species/Reptilian/parts.rsi @@ -76,7 +92,7 @@ - type: entity id: RightHandReptilian name: "right reptilian hand" - parent: [PartReptilian, BaseRightHand] + parent: [BaseRightHand, PartReptilian] components: - type: Sprite sprite: Mobs/Species/Reptilian/parts.rsi @@ -85,7 +101,7 @@ - type: entity id: LeftLegReptilian name: "left reptilian leg" - parent: [PartReptilian, BaseLeftLeg] + parent: [BaseLeftLeg, PartReptilian] components: - type: Sprite sprite: Mobs/Species/Reptilian/parts.rsi @@ -94,7 +110,7 @@ - type: entity id: RightLegReptilian name: "right reptilian leg" - parent: [PartReptilian, BaseRightLeg] + parent: [BaseRightLeg, PartReptilian] components: - type: Sprite sprite: Mobs/Species/Reptilian/parts.rsi @@ -103,7 +119,7 @@ - type: entity id: LeftFootReptilian name: "left reptilian foot" - parent: [PartReptilian, BaseLeftFoot] + parent: [BaseLeftFoot, PartReptilian] components: - type: Sprite sprite: Mobs/Species/Reptilian/parts.rsi @@ -112,7 +128,7 @@ - type: entity id: RightFootReptilian name: "right reptilian foot" - parent: [PartReptilian, BaseRightFoot] + parent: [BaseRightFoot, PartReptilian] components: - type: Sprite sprite: Mobs/Species/Reptilian/parts.rsi diff --git a/Resources/Prototypes/Body/Parts/silicon.yml b/Resources/Prototypes/Body/Parts/silicon.yml index 577ec2bffce..6c10e89b8ae 100644 --- a/Resources/Prototypes/Body/Parts/silicon.yml +++ b/Resources/Prototypes/Body/Parts/silicon.yml @@ -3,13 +3,21 @@ parent: BaseItem abstract: true components: + - type: WoundableVisuals + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#DD8822" + Burn: + # TODO: stuff here + sprite: Mobs/Effects/burn_damage.rsi # Would have been cool if those were some fancy burns or stuff + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi # they bleed oil, no? Change this if possible - type: Sprite sprite: Objects/Specific/Robotics/cyborg_parts.rsi - type: Icon sprite: Objects/Specific/Robotics/cyborg_parts.rsi - type: Damageable damageContainer: Inorganic - - type: BodyPart - type: ContainerContainer containers: bodypart: !type:Container @@ -34,7 +42,7 @@ - type: entity id: LeftArmBorg - parent: PartSilicon + parent: [BaseLeftArm, PartSilicon] name: cyborg left arm components: - type: BodyPart @@ -52,7 +60,7 @@ - type: entity id: RightArmBorg - parent: PartSilicon + parent: [BaseRightArm, PartSilicon] name: cyborg right arm components: - type: BodyPart @@ -70,7 +78,7 @@ - type: entity id: LeftLegBorg - parent: PartSilicon + parent: [BaseLeftLeg, PartSilicon] name: cyborg left leg components: - type: BodyPart @@ -93,7 +101,7 @@ - type: entity id: RightLegBorg - parent: PartSilicon + parent: [BaseRightLeg, PartSilicon] name: cyborg right leg components: - type: BodyPart @@ -116,7 +124,7 @@ - type: entity id: LightHeadBorg - parent: PartSilicon + parent: [BaseHead, PartSilicon] name: cyborg head components: - type: BodyPart @@ -132,11 +140,11 @@ - type: entity id: TorsoBorg - parent: PartSilicon - name: cyborg torso + parent: [BaseChest, PartSilicon] + name: cyborg chest components: - type: BodyPart - partType: Torso + partType: Chest - type: Sprite state: borg_chest - type: Icon diff --git a/Resources/Prototypes/Body/Parts/skeleton.yml b/Resources/Prototypes/Body/Parts/skeleton.yml index 058ee29db1d..45dc0f0b376 100644 --- a/Resources/Prototypes/Body/Parts/skeleton.yml +++ b/Resources/Prototypes/Body/Parts/skeleton.yml @@ -1,73 +1,47 @@ - type: entity id: PartSkeleton - parent: BaseItem + parent: BasePart name: "skeleton body part" abstract: true components: - - type: Damageable - damageContainer: OrganicPart # backmen: surgery - - type: BodyPart - - type: ContainerContainer - containers: - bodypart: !type:Container - ents: [] - - type: StaticPrice - price: 20 - - type: Tag - tags: - - Trash - # start-backmen: surgery - - type: Gibbable - - type: Destructible - thresholds: - - trigger: - !type:DamageTypeTrigger - damageType: Blunt - damage: 120 - behaviors: - - !type:GibPartBehavior { } - - trigger: - !type:DamageTypeTrigger - damageType: Slash - damage: 120 - behaviors: - - !type:GibPartBehavior { } - - trigger: - !type:DamageTypeTrigger - damageType: Heat - damage: 200 - behaviors: - - !type:SpawnEntitiesBehavior - spawnInContainer: true - spawn: - Ash: - min: 1 - max: 1 - - !type:BurnBodyBehavior { } - - !type:PlaySoundBehavior - sound: - collection: MeatLaserImpact - # end-backmen: surgery + - type: WoundableVisuals + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#555555AA" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: entity - id: TorsoSkeleton - name: "skeleton torso" - parent: PartSkeleton + id: ChestSkeleton + name: "skeleton chest" + parent: [BaseChest, PartSkeleton] components: - type: Sprite sprite: Mobs/Species/Skeleton/parts.rsi - state: "torso_m" + state: "chest_m" - type: Icon sprite: Mobs/Species/Skeleton/parts.rsi - state: "torso_m" - - type: BodyPart - partType: Torso + state: "chest_m" + +- type: entity + id: GroinSkeleton + name: "skeleton groin" + parent: [BaseGroin, PartSkeleton] + components: + - type: Sprite + sprite: Mobs/Species/Skeleton/parts.rsi + state: "groin_m" + - type: Icon + sprite: Mobs/Species/Skeleton/parts.rsi + state: "groin_m" - type: entity id: HeadSkeleton name: "skull" description: Alas poor Yorick... - parent: PartSkeleton + parent: [BaseHead, PartSkeleton] components: - type: Sprite sprite: Mobs/Species/Skeleton/parts.rsi @@ -105,7 +79,7 @@ - type: entity id: LeftArmSkeleton name: "left skeleton arm" - parent: PartSkeleton + parent: [BaseHead, PartSkeleton] components: - type: Sprite sprite: Mobs/Species/Skeleton/parts.rsi @@ -120,7 +94,7 @@ - type: entity id: RightArmSkeleton name: "right skeleton arm" - parent: PartSkeleton + parent: [BaseRightArm, PartSkeleton] components: - type: Sprite sprite: Mobs/Species/Skeleton/parts.rsi @@ -135,7 +109,7 @@ - type: entity id: LeftHandSkeleton name: "left skeleton hand" - parent: PartSkeleton + parent: [BaseLeftHand, PartSkeleton] components: - type: Sprite sprite: Mobs/Species/Skeleton/parts.rsi @@ -150,7 +124,7 @@ - type: entity id: RightHandSkeleton name: "right skeleton hand" - parent: PartSkeleton + parent: [BaseRightHand, PartSkeleton] components: - type: Sprite sprite: Mobs/Species/Skeleton/parts.rsi @@ -165,7 +139,7 @@ - type: entity id: LeftLegSkeleton name: "left skeleton leg" - parent: PartSkeleton + parent: [BaseLeftLeg, PartSkeleton] components: - type: Sprite sprite: Mobs/Species/Skeleton/parts.rsi @@ -181,7 +155,7 @@ - type: entity id: RightLegSkeleton name: "right skeleton leg" - parent: PartSkeleton + parent: [BaseRightLeg, PartSkeleton] components: - type: Sprite sprite: Mobs/Species/Skeleton/parts.rsi @@ -197,7 +171,7 @@ - type: entity id: LeftFootSkeleton name: "left skeleton foot" - parent: PartSkeleton + parent: [BaseLeftFoot, PartSkeleton] components: - type: Sprite sprite: Mobs/Species/Skeleton/parts.rsi @@ -212,7 +186,7 @@ - type: entity id: RightFootSkeleton name: "right skeleton foot" - parent: PartSkeleton + parent: [BaseRightFoot, PartSkeleton] components: - type: Sprite sprite: Mobs/Species/Skeleton/parts.rsi diff --git a/Resources/Prototypes/Body/Parts/slime.yml b/Resources/Prototypes/Body/Parts/slime.yml index 4b0e94b008f..5d430ddbd8a 100644 --- a/Resources/Prototypes/Body/Parts/slime.yml +++ b/Resources/Prototypes/Body/Parts/slime.yml @@ -4,29 +4,47 @@ parent: [BaseItem, BasePart] name: "slime body part" abstract: true + components: + - type: WoundableVisuals + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#2cf274" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: entity - id: TorsoSlime - name: "slime torso" - parent: [PartSlime, BaseTorso] + id: ChestSlime + name: "slime chest" + parent: [BaseChest, PartSlime] components: - type: Sprite sprite: Mobs/Species/Slime/parts.rsi - state: "torso_m" + state: "chest_m" + +- type: entity + id: GroinSlime + name: "slime groin" + parent: [BaseGroin, PartSlime] + components: + - type: Sprite + sprite: Mobs/Species/Slime/parts.rsi + state: "groin_m" - type: entity id: HeadSlime name: "slime head" - parent: [PartSlime, BaseHead] + parent: [BaseHead, PartSlime] components: - type: Sprite sprite: Mobs/Species/Slime/parts.rsi state: "head_m" - + - type: entity id: LeftArmSlime name: "left slime arm" - parent: [PartSlime, BaseLeftArm] + parent: [BaseLeftArm, PartSlime] components: - type: Sprite sprite: Mobs/Species/Slime/parts.rsi @@ -35,7 +53,7 @@ - type: entity id: RightArmSlime name: "right slime arm" - parent: [PartSlime, BaseRightArm] + parent: [BaseRightArm, PartSlime] components: - type: Sprite sprite: Mobs/Species/Slime/parts.rsi @@ -44,7 +62,7 @@ - type: entity id: LeftHandSlime name: "left slime hand" - parent: [PartSlime, BaseLeftHand] + parent: [BaseLeftHand, PartSlime] components: - type: Sprite sprite: Mobs/Species/Slime/parts.rsi @@ -53,7 +71,7 @@ - type: entity id: RightHandSlime name: "right slime hand" - parent: [PartSlime, BaseRightHand] + parent: [BaseRightHand, PartSlime] components: - type: Sprite sprite: Mobs/Species/Slime/parts.rsi @@ -62,7 +80,7 @@ - type: entity id: LeftLegSlime name: "left slime leg" - parent: [PartSlime, BaseLeftLeg] + parent: [BaseLeftLeg, PartSlime] components: - type: Sprite sprite: Mobs/Species/Slime/parts.rsi @@ -71,7 +89,7 @@ - type: entity id: RightLegSlime name: "right slime leg" - parent: [PartSlime, BaseRightLeg] + parent: [BaseRightLeg, PartSlime] components: - type: Sprite sprite: Mobs/Species/Slime/parts.rsi @@ -80,7 +98,7 @@ - type: entity id: LeftFootSlime name: "left slime foot" - parent: [PartSlime, BaseLeftFoot] + parent: [BaseLeftFoot, PartSlime] components: - type: Sprite sprite: Mobs/Species/Slime/parts.rsi @@ -89,7 +107,7 @@ - type: entity id: RightFootSlime name: "right slime foot" - parent: [PartSlime, BaseRightFoot] + parent: [BaseRightFoot, PartSlime] components: - type: Sprite sprite: Mobs/Species/Slime/parts.rsi diff --git a/Resources/Prototypes/Body/Parts/vox.yml b/Resources/Prototypes/Body/Parts/vox.yml index 505eba800f4..82f1e7bc5ed 100644 --- a/Resources/Prototypes/Body/Parts/vox.yml +++ b/Resources/Prototypes/Body/Parts/vox.yml @@ -2,22 +2,18 @@ # TODO BODY: Part damage - type: entity id: PartVox - parent: BaseItem + parent: BasePart name: "vox body part" abstract: true components: - - type: Damageable - damageContainer: OrganicPart # Shitmed - - type: BodyPart - - type: ContainerContainer - containers: - bodypart: !type:Container - ents: [] - - type: StaticPrice - price: 100 - - type: Tag - tags: - - Trash + - type: WoundableVisuals + damageOverlayGroups: + Brute: + sprite: Mobs/Effects/brute_damage.rsi + color: "#7a8bf2" + Burn: + sprite: Mobs/Effects/burn_damage.rsi + bleedingOverlay: Mobs/Effects/bleeding_damage.rsi - type: Extractable juiceSolution: reagents: @@ -27,18 +23,35 @@ Quantity: 10 - type: entity - id: TorsoVox - name: "vox torso" - parent: PartVox + id: ChestVox + name: "vox chest" + parent: [BaseChest, PartVox] components: - type: Sprite sprite: Mobs/Species/Vox/parts.rsi - state: "torso" + state: "chest" - type: Icon sprite: Mobs/Species/Vox/parts.rsi - state: "torso" - - type: BodyPart - partType: Torso + state: "chest" + - type: Extractable + juiceSolution: + reagents: + - ReagentId: Fat + Quantity: 3 + - ReagentId: Blood + Quantity: 10 + +- type: entity + id: GroinVox + name: "vox groin" + parent: [BaseGroin, PartVox] + components: + - type: Sprite + sprite: Mobs/Species/Vox/parts.rsi + state: "groin" + - type: Icon + sprite: Mobs/Species/Vox/parts.rsi + state: "groin" - type: Extractable juiceSolution: reagents: @@ -50,7 +63,7 @@ - type: entity id: HeadVox name: "vox head" - parent: PartVox + parent: [BaseHead, PartVox] components: - type: Sprite sprite: Mobs/Species/Vox/parts.rsi @@ -77,7 +90,7 @@ - type: entity id: LeftArmVox name: "left vox arm" - parent: PartVox + parent: [BaseLeftArm, PartVox] components: - type: Sprite sprite: Mobs/Species/Vox/parts.rsi @@ -92,7 +105,7 @@ - type: entity id: RightArmVox name: "right vox arm" - parent: PartVox + parent: [BaseRightArm, PartVox] components: - type: Sprite sprite: Mobs/Species/Vox/parts.rsi @@ -107,7 +120,7 @@ - type: entity id: LeftHandVox name: "left vox hand" - parent: PartVox + parent: [BaseLeftHand, PartVox] components: - type: Sprite sprite: Mobs/Species/Vox/parts.rsi @@ -122,7 +135,7 @@ - type: entity id: RightHandVox name: "right vox hand" - parent: PartVox + parent: [BaseRightHand, PartVox] components: - type: Sprite sprite: Mobs/Species/Vox/parts.rsi @@ -137,7 +150,7 @@ - type: entity id: LeftLegVox name: "left vox leg" - parent: PartVox + parent: [BaseLeftLeg, PartVox] components: - type: Sprite sprite: Mobs/Species/Vox/parts.rsi @@ -153,7 +166,7 @@ - type: entity id: RightLegVox name: "right vox leg" - parent: PartVox + parent: [BaseRightLeg, PartVox] components: - type: Sprite sprite: Mobs/Species/Vox/parts.rsi @@ -169,7 +182,7 @@ - type: entity id: LeftFootVox name: "left vox foot" - parent: PartVox + parent: [BaseLeftFoot, PartVox] components: - type: Sprite sprite: Mobs/Species/Vox/parts.rsi @@ -184,7 +197,7 @@ - type: entity id: RightFootVox name: "right vox foot" - parent: PartVox + parent: [BaseRightFoot, PartVox] components: - type: Sprite sprite: Mobs/Species/Vox/parts.rsi diff --git a/Resources/Prototypes/Body/Prototypes/Animal/animal.yml b/Resources/Prototypes/Body/Prototypes/Animal/animal.yml index a8c81f9eb60..d841c0ca4aa 100644 --- a/Resources/Prototypes/Body/Prototypes/Animal/animal.yml +++ b/Resources/Prototypes/Body/Prototypes/Animal/animal.yml @@ -1,17 +1,22 @@ - type: body id: Animal name: "animal" - root: torso + root: chest slots: - torso: - part: TorsoAnimal + chest: + part: ChestAnimal connections: - - legs + - groin organs: lungs: OrganAnimalLungs + heart: OrganAnimalHeart + groin: + part: GroinAnimal + connections: + - legs + organs: stomach: OrganAnimalStomach liver: OrganAnimalLiver - heart: OrganAnimalHeart kidneys: OrganAnimalKidneys legs: part: LegsAnimal @@ -23,17 +28,22 @@ - type: body id: Mouse name: "mouse" - root: torso + root: chest slots: - torso: - part: TorsoAnimal + chest: + part: ChestAnimal connections: - - legs + - groin organs: lungs: OrganAnimalLungs + heart: OrganAnimalHeart + groin: + part: GroinAnimal + connections: + - legs + organs: stomach: OrganMouseStomach liver: OrganAnimalLiver - heart: OrganAnimalHeart kidneys: OrganAnimalKidneys legs: part: LegsAnimal diff --git a/Resources/Prototypes/Body/Prototypes/Animal/bloodsucker.yml b/Resources/Prototypes/Body/Prototypes/Animal/bloodsucker.yml index dd8750714ef..63f0d7ba8de 100644 --- a/Resources/Prototypes/Body/Prototypes/Animal/bloodsucker.yml +++ b/Resources/Prototypes/Body/Prototypes/Animal/bloodsucker.yml @@ -1,17 +1,22 @@ - type: body id: Bloodsucker name: "bloodsucker" - root: torso + root: chest slots: - torso: - part: TorsoAnimal + chest: + part: ChestAnimal connections: - - legs + - groin organs: lungs: OrganAnimalLungs + heart: OrganBloodsuckerHeart + groin: + part: GroinAnimal + connections: + - legs + organs: stomach: OrganBloodsuckerStomach liver: OrganBloodsuckerLiver - heart: OrganBloodsuckerHeart kidneys: OrganAnimalKidneys legs: part: LegsAnimal diff --git a/Resources/Prototypes/Body/Prototypes/Animal/hemocyanin.yml b/Resources/Prototypes/Body/Prototypes/Animal/hemocyanin.yml index b29edadc806..e019b40fa23 100644 --- a/Resources/Prototypes/Body/Prototypes/Animal/hemocyanin.yml +++ b/Resources/Prototypes/Body/Prototypes/Animal/hemocyanin.yml @@ -1,17 +1,22 @@ - type: body id: AnimalHemocyanin name: "hemocyanin" - root: torso + root: chest slots: - torso: - part: TorsoAnimal + chest: + part: ChestAnimal connections: - - legs + - groin organs: lungs: OrganAnimalLungs + heart: OrganArachnidHeart + groin: + part: GroinAnimal + connections: + - legs + organs: stomach: OrganAnimalStomach liver: OrganAnimalLiver - heart: OrganArachnidHeart kidneys: OrganAnimalKidneys legs: part: LegsAnimal diff --git a/Resources/Prototypes/Body/Prototypes/Animal/mothroach.yml b/Resources/Prototypes/Body/Prototypes/Animal/mothroach.yml index ef5df769def..1687b5dbac0 100644 --- a/Resources/Prototypes/Body/Prototypes/Animal/mothroach.yml +++ b/Resources/Prototypes/Body/Prototypes/Animal/mothroach.yml @@ -1,13 +1,18 @@ - type: body id: Mothroach name: "mothroach" - root: torso + root: chest slots: - torso: - part: TorsoAnimal + chest: + part: ChestAnimal + connections: + - groin organs: lungs: OrganAnimalLungs + heart: OrganAnimalHeart + groin: + part: GroinAnimal + organs: stomach: OrganMothStomach liver: OrganAnimalLiver - heart: OrganAnimalHeart kidneys: OrganAnimalKidneys diff --git a/Resources/Prototypes/Body/Prototypes/Animal/nymph.yml b/Resources/Prototypes/Body/Prototypes/Animal/nymph.yml index 21aafe291c9..fb8a6700242 100644 --- a/Resources/Prototypes/Body/Prototypes/Animal/nymph.yml +++ b/Resources/Prototypes/Body/Prototypes/Animal/nymph.yml @@ -1,18 +1,23 @@ - type: body id: AnimalNymphBrain name: "nymph" - root: torso + root: chest slots: - torso: - part: TorsoAnimal + chest: + part: ChestAnimal connections: - - legs + - groin organs: brain: OrganDionaBrain lungs: OrganAnimalLungs + heart: OrganAnimalHeart + groin: + part: GroinAnimal + connections: + - legs + organs: stomach: OrganAnimalStomach liver: OrganAnimalLiver - heart: OrganAnimalHeart kidneys: OrganAnimalKidneys legs: part: LegsAnimal @@ -24,17 +29,22 @@ - type: body id: AnimalNymphLungs name: "nymph" - root: torso + root: chest slots: - torso: - part: TorsoAnimal + chest: + part: ChestAnimal connections: - - legs + - groin organs: lungs: OrganDionaLungs + heart: OrganAnimalHeart + groin: + part: GroinAnimal + connections: + - legs + organs: stomach: OrganAnimalStomach liver: OrganAnimalLiver - heart: OrganAnimalHeart kidneys: OrganAnimalKidneys legs: part: LegsAnimal @@ -46,17 +56,22 @@ - type: body id: AnimalNymphStomach name: "nymph" - root: torso + root: chest slots: - torso: - part: TorsoAnimal + chest: + part: ChestAnimal connections: - - legs + - groin organs: lungs: OrganAnimalLungs + heart: OrganAnimalHeart + groin: + part: GroinAnimal + connections: + - legs + organs: stomach: OrganDionaStomach liver: OrganAnimalLiver - heart: OrganAnimalHeart kidneys: OrganAnimalKidneys legs: part: LegsAnimal diff --git a/Resources/Prototypes/Body/Prototypes/Animal/rat.yml b/Resources/Prototypes/Body/Prototypes/Animal/rat.yml index fe772889944..da309e5d205 100644 --- a/Resources/Prototypes/Body/Prototypes/Animal/rat.yml +++ b/Resources/Prototypes/Body/Prototypes/Animal/rat.yml @@ -1,17 +1,22 @@ - type: body id: Rat name: "animal" - root: torso + root: chest slots: - torso: - part: TorsoRat + chest: + part: ChestAnimal connections: - - legs + - groin organs: lungs: OrganRatLungs + heart: OrganAnimalHeart + groin: + part: GroinAnimal + connections: + - legs + organs: stomach: OrganRatStomach liver: OrganAnimalLiver - heart: OrganAnimalHeart kidneys: OrganAnimalKidneys legs: part: LegsAnimal diff --git a/Resources/Prototypes/Body/Prototypes/Animal/ruminant.yml b/Resources/Prototypes/Body/Prototypes/Animal/ruminant.yml index cd3ab1fdd78..745064d3971 100644 --- a/Resources/Prototypes/Body/Prototypes/Animal/ruminant.yml +++ b/Resources/Prototypes/Body/Prototypes/Animal/ruminant.yml @@ -1,18 +1,23 @@ - type: body id: AnimalRuminant name: "ruminant" - root: torso + root: chest slots: - torso: - part: TorsoAnimal + chest: + part: ChestAnimal connections: - - legs + - groin organs: lungs: OrganAnimalLungs + heart: OrganAnimalHeart + groin: + part: GroinAnimal + connections: + - legs + organs: stomach: OrganAnimalRuminantStomach stomach2: OrganAnimalRuminantStomach liver: OrganAnimalLiver - heart: OrganAnimalHeart kidneys: OrganAnimalKidneys legs: part: LegsAnimal diff --git a/Resources/Prototypes/Body/Prototypes/Animal/slimes.yml b/Resources/Prototypes/Body/Prototypes/Animal/slimes.yml index 8d9827e99a0..afd7caf2bf0 100644 --- a/Resources/Prototypes/Body/Prototypes/Animal/slimes.yml +++ b/Resources/Prototypes/Body/Prototypes/Animal/slimes.yml @@ -1,10 +1,10 @@ - type: body id: Slimes name: "slimes" - root: torso + root: chest slots: - torso: - part: TorsoSlime + chest: + part: ChestSlime connections: - legs organs: diff --git a/Resources/Prototypes/Body/Prototypes/a_ghost.yml b/Resources/Prototypes/Body/Prototypes/a_ghost.yml index a2eaef3dd58..b8dd13130d5 100644 --- a/Resources/Prototypes/Body/Prototypes/a_ghost.yml +++ b/Resources/Prototypes/Body/Prototypes/a_ghost.yml @@ -1,10 +1,10 @@ - type: body id: Aghost name: "aghost" - root: torso + root: chest slots: - torso: - part: TorsoHuman + chest: + part: ChestHuman connections: - right arm - left arm diff --git a/Resources/Prototypes/Body/Prototypes/arachnid.yml b/Resources/Prototypes/Body/Prototypes/arachnid.yml index c2175076b14..c483d1ea71b 100644 --- a/Resources/Prototypes/Body/Prototypes/arachnid.yml +++ b/Resources/Prototypes/Body/Prototypes/arachnid.yml @@ -1,29 +1,33 @@ - type: body id: Arachnid name: "arachnid" - root: torso + root: chest slots: head: part: HeadArachnid connections: - - torso + - chest organs: brain: OrganHumanBrain eyes: OrganArachnidEyes - torso: - part: TorsoArachnid + chest: + part: ChestArachnid + connections: + - groin + - right arm + - left arm organs: heart: OrganArachnidHeart lungs: OrganAnimalLungs - stomach: OrganArachnidStomach - liver: OrganArachnidLiver - kidneys: OrganArachnidKidneys + groin: + part: GroinArachnid connections: - - right arm - - left arm - right leg - left leg - - head + organs: + stomach: OrganArachnidStomach + liver: OrganArachnidLiver + kidneys: OrganArachnidKidneys right arm: part: RightArmArachnid connections: diff --git a/Resources/Prototypes/Body/Prototypes/diona.yml b/Resources/Prototypes/Body/Prototypes/diona.yml index 33a65bdc5c3..8530173382b 100644 --- a/Resources/Prototypes/Body/Prototypes/diona.yml +++ b/Resources/Prototypes/Body/Prototypes/diona.yml @@ -1,25 +1,29 @@ - type: body id: Diona name: diona - root: torso + root: chest slots: head: part: HeadDiona connections: - - torso + - chest organs: brain: OrganDionaBrainNymph - torso: - part: TorsoDiona + chest: + part: ChestDiona connections: + - groin - right arm - left arm + organs: + lungs: OrganDionaLungsNymph + groin: + part: GroinDiona + connections: - right leg - left leg - - head organs: stomach: OrganDionaStomachNymph - lungs: OrganDionaLungsNymph right arm: part: RightArmDiona connections: diff --git a/Resources/Prototypes/Body/Prototypes/dwarf.yml b/Resources/Prototypes/Body/Prototypes/dwarf.yml index fb5a1753ae4..1deaad1a9cb 100644 --- a/Resources/Prototypes/Body/Prototypes/dwarf.yml +++ b/Resources/Prototypes/Body/Prototypes/dwarf.yml @@ -1,26 +1,30 @@ - type: body id: Dwarf name: "dwarf" - root: torso + root: chest slots: head: part: HeadHuman connections: - - torso + - chest organs: brain: OrganHumanBrain eyes: OrganHumanEyes - torso: - part: TorsoHuman + chest: + part: ChestHuman connections: + - groin - right arm - left arm - - right leg - - left leg - - head organs: heart: OrganDwarfHeart lungs: OrganHumanLungs + groin: + part: GroinHuman + connections: + - right leg + - left leg + organs: stomach: OrganDwarfStomach liver: OrganDwarfLiver kidneys: OrganHumanKidneys diff --git a/Resources/Prototypes/Body/Prototypes/gingerbread.yml b/Resources/Prototypes/Body/Prototypes/gingerbread.yml index d7a5d7bc1c4..99b7b92d1d8 100644 --- a/Resources/Prototypes/Body/Prototypes/gingerbread.yml +++ b/Resources/Prototypes/Body/Prototypes/gingerbread.yml @@ -1,26 +1,30 @@ - type: body id: Gingerbread name: gingerbread - root: torso + root: chest slots: head: part: HeadGingerbread connections: - - torso + - chest organs: brain: OrganHumanBrain eyes: OrganHumanEyes - torso: - part: TorsoGingerbread + chest: + part: ChestGingerbread connections: + - groin - right arm - left arm - - right leg - - left leg - - head organs: heart: OrganHumanHeart lungs: OrganHumanLungs + groin: + part: GroinGingerbread + connections: + - right leg + - left leg + organs: stomach: OrganHumanStomach liver: OrganHumanLiver kidneys: OrganHumanKidneys diff --git a/Resources/Prototypes/Body/Prototypes/human.yml b/Resources/Prototypes/Body/Prototypes/human.yml index b46e5049bbd..7af6510f9c1 100644 --- a/Resources/Prototypes/Body/Prototypes/human.yml +++ b/Resources/Prototypes/Body/Prototypes/human.yml @@ -1,26 +1,30 @@ - type: body id: Human name: "human" - root: torso + root: chest slots: head: part: HeadHuman connections: - - torso + - chest organs: brain: OrganHumanBrain eyes: OrganHumanEyes - torso: - part: TorsoHuman + chest: + part: ChestHuman connections: + - groin - right arm - left arm - - right leg - - left leg - - head organs: heart: OrganHumanHeart lungs: OrganHumanLungs + groin: + part: GroinHuman + connections: + - right leg + - left leg + organs: stomach: OrganHumanStomach liver: OrganHumanLiver kidneys: OrganHumanKidneys @@ -47,4 +51,4 @@ right foot: part: RightFootHuman left foot: - part: LeftFootHuman + part: LeftFootHuman \ No newline at end of file diff --git a/Resources/Prototypes/Body/Prototypes/kobold.yml b/Resources/Prototypes/Body/Prototypes/kobold.yml index 6cf15dae081..710b8d02763 100644 --- a/Resources/Prototypes/Body/Prototypes/kobold.yml +++ b/Resources/Prototypes/Body/Prototypes/kobold.yml @@ -2,26 +2,30 @@ - type: body id: Kobold name: "Kobold" - root: torso + root: chest slots: head: part: HeadKobold connections: - - torso + - chest organs: brain: OrganAnimalBrain eyes: OrganAnimalEyes - torso: - part: TorsoKobold + chest: + part: ChestKobold connections: + - groin - right arm - left arm - - right leg - - left leg - - head organs: heart: OrganAnimalHeart lungs: OrganAnimalLungs + groin: + part: GroinKobold + connections: + - right leg + - left leg + organs: stomach: OrganAnimalStomach liver: OrganAnimalLiver kidneys: OrganAnimalKidneys diff --git a/Resources/Prototypes/Body/Prototypes/monkey.yml b/Resources/Prototypes/Body/Prototypes/monkey.yml index 9ba35d6c792..424bcf40540 100644 --- a/Resources/Prototypes/Body/Prototypes/monkey.yml +++ b/Resources/Prototypes/Body/Prototypes/monkey.yml @@ -2,26 +2,30 @@ - type: body id: Monkey name: "Monkey" - root: torso + root: chest slots: head: part: HeadMonkey connections: - - torso + - chest organs: brain: OrganAnimalBrain eyes: OrganAnimalEyes - torso: - part: TorsoMonkey + chest: + part: ChestMonkey connections: + - groin - right arm - left arm - - right leg - - left leg - - head organs: heart: OrganAnimalHeart lungs: OrganAnimalLungs + groin: + part: GroinMonkey + connections: + - right leg + - left leg + organs: stomach: OrganAnimalStomach liver: OrganAnimalLiver kidneys: OrganAnimalKidneys diff --git a/Resources/Prototypes/Body/Prototypes/moth.yml b/Resources/Prototypes/Body/Prototypes/moth.yml index 4d80ebf803a..d2cafe81edd 100644 --- a/Resources/Prototypes/Body/Prototypes/moth.yml +++ b/Resources/Prototypes/Body/Prototypes/moth.yml @@ -1,29 +1,33 @@ - type: body id: Moth - name: "moth" - root: torso + name: "Moth" + root: chest slots: head: part: HeadMoth connections: - - torso + - chest organs: brain: OrganHumanBrain eyes: OrganHumanEyes - torso: - part: TorsoMoth + chest: + part: ChestMoth + connections: + - groin + - right arm + - left arm organs: heart: OrganAnimalHeart lungs: OrganHumanLungs - stomach: OrganMothStomach - liver: OrganAnimalLiver - kidneys: OrganHumanKidneys + groin: + part: GroinMoth connections: - - right arm - - left arm - right leg - left leg - - head + organs: + stomach: OrganMothStomach + liver: OrganAnimalLiver + kidneys: OrganHumanKidneys right arm: part: RightArmMoth connections: diff --git a/Resources/Prototypes/Body/Prototypes/primate.yml b/Resources/Prototypes/Body/Prototypes/primate.yml index 1375368ee9c..720b6587e6f 100644 --- a/Resources/Prototypes/Body/Prototypes/primate.yml +++ b/Resources/Prototypes/Body/Prototypes/primate.yml @@ -1,27 +1,32 @@ - type: body id: Primate name: "primate" - root: torso + root: chest slots: head: # Put pun pun into a humans body part: HeadAnimal connections: - - torso + - chest organs: brain: OrganHumanBrain eyes: OrganHumanEyes - torso: - part: TorsoAnimal + chest: + part: ChestAnimal connections: - left hands 1 - left hands 2 - - legs + - groin - head organs: lungs: OrganAnimalLungs + heart: OrganAnimalHeart + groin: + part: GroinAnimal + connections: + - legs + organs: stomach: OrganAnimalStomach liver: OrganAnimalLiver - heart: OrganAnimalHeart kidneys: OrganAnimalKidneys left hands 1: part: HandsAnimal diff --git a/Resources/Prototypes/Body/Prototypes/reptilian.yml b/Resources/Prototypes/Body/Prototypes/reptilian.yml index 92f34634332..3455a2af1a2 100644 --- a/Resources/Prototypes/Body/Prototypes/reptilian.yml +++ b/Resources/Prototypes/Body/Prototypes/reptilian.yml @@ -1,29 +1,33 @@ - type: body name: "reptilian" id: Reptilian - root: torso + root: chest slots: head: part: HeadReptilian connections: - - torso + - chest organs: brain: OrganHumanBrain eyes: OrganHumanEyes - torso: - part: TorsoReptilian - organs: - heart: OrganAnthroAnimalHeart # Ataraxia - lungs: OrganHumanLungs - stomach: OrganReptilianStomach - liver: OrganAnthroAnimalLiver # Ataraxia - kidneys: OrganHumanKidneys + chest: + part: ChestReptilian connections: + - groin - right arm - left arm + organs: + heart: OrganAnimalHeart + lungs: OrganHumanLungs + groin: + part: GroinReptilian + connections: - right leg - left leg - - head + organs: + stomach: OrganReptilianStomach + liver: OrganAnimalLiver + kidneys: OrganHumanKidneys right arm: part: RightArmReptilian connections: diff --git a/Resources/Prototypes/Body/Prototypes/skeleton.yml b/Resources/Prototypes/Body/Prototypes/skeleton.yml index 998d01cc499..0a13e2c64e4 100644 --- a/Resources/Prototypes/Body/Prototypes/skeleton.yml +++ b/Resources/Prototypes/Body/Prototypes/skeleton.yml @@ -1,20 +1,23 @@ - type: body id: Skeleton name: "skeleton" - root: torso + root: chest slots: head: part: HeadSkeleton connections: - - torso - torso: - part: TorsoSkeleton + - chest + chest: + part: ChestSkeleton connections: + - groin - right arm - left arm + groin: + part: GroinSkeleton + connections: - right leg - left leg - - head right arm: part: RightArmSkeleton connections: diff --git a/Resources/Prototypes/Body/Prototypes/slime.yml b/Resources/Prototypes/Body/Prototypes/slime.yml index df246bb0d23..80e91b5ca28 100644 --- a/Resources/Prototypes/Body/Prototypes/slime.yml +++ b/Resources/Prototypes/Body/Prototypes/slime.yml @@ -1,23 +1,26 @@ - type: body id: Slime name: "slime" - root: torso + root: chest slots: head: part: HeadSlime connections: - - torso - torso: - part: TorsoSlime + - chest + chest: + part: ChestSlime connections: + - groin - right arm - left arm - - right leg - - left leg - - head organs: core: SentientSlimeCore lungs: OrganSlimeLungs + groin: + part: GroinHuman + connections: + - right leg + - left leg right arm: part: RightArmSlime connections: diff --git a/Resources/Prototypes/Body/Prototypes/vox.yml b/Resources/Prototypes/Body/Prototypes/vox.yml index 42cbb7e0855..574cde240be 100644 --- a/Resources/Prototypes/Body/Prototypes/vox.yml +++ b/Resources/Prototypes/Body/Prototypes/vox.yml @@ -1,26 +1,30 @@ - type: body id: Vox name: "vox" - root: torso + root: chest slots: head: part: HeadVox connections: - - torso + - chest organs: brain: OrganHumanBrain eyes: OrganHumanEyes - torso: - part: TorsoVox + chest: + part: ChestVox connections: + - groin - right arm - left arm - - right leg - - left leg - - head organs: heart: OrganHumanHeart lungs: OrganVoxLungs + groin: + part: GroinVox + connections: + - right leg + - left leg + organs: stomach: OrganHumanStomach liver: OrganHumanLiver kidneys: OrganHumanKidneys diff --git a/Resources/Prototypes/Corvax/Body/Parts/vulpkanin.yml b/Resources/Prototypes/Corvax/Body/Parts/vulpkanin.yml index 7cc44de0d30..fdb5ebbb3fb 100644 --- a/Resources/Prototypes/Corvax/Body/Parts/vulpkanin.yml +++ b/Resources/Prototypes/Corvax/Body/Parts/vulpkanin.yml @@ -2,29 +2,11 @@ # TODO BODY: Part damage - type: entity id: PartVulpkanin - parent: BaseItem + parent: BasePart name: "vulpkanin body part" abstract: true components: - - type: Damageable - damageContainer: OrganicPart # Shitmed Change - - type: BodyPart - - type: ContainerContainer - containers: - bodypart: !type:Container - ents: [] - - type: StaticPrice #DynamicPrice - price: 100 - - type: Tag - tags: - - Trash # Shitmed Change Start - - type: Gibbable - - type: SurgeryTool - startSound: - path: /Audio/_Shitmed/Medical/Surgery/organ1.ogg - endSound: - path: /Audio/_Shitmed/Medical/Surgery/organ2.ogg - type: Destructible thresholds: - trigger: @@ -57,25 +39,25 @@ # Shitmed Change End - type: entity - id: TorsoVulpkanin - name: "vulpkanin torso" + id: ChestVulpkanin + name: "vulpkanin chest" parent: PartVulpkanin components: - type: Sprite netsync: false sprite: Corvax/Mobs/Species/Vulpkanin/parts.rsi - state: "torso_m" + state: "chest_m" - type: Icon sprite: Corvax/Mobs/Species/Vulpkanin/parts.rsi - state: "torso_m" + state: "chest_m" # Shitmed Change Start - type: BodyPart - partType: Torso - toolName: "a torso" - containerName: "torso_slot" + partType: Chest + toolName: "a chest" + containerName: "chest_slot" - type: ContainerContainer containers: - torso_slot: !type:ContainerSlot {} + chest_slot: !type:ContainerSlot {} - type: Destructible thresholds: - trigger: @@ -107,6 +89,55 @@ collection: MeatLaserImpact # Shitmed Change End +- type: entity + id: GroinVulpkanin + name: "vulpkanin groin" + parent: PartVulpkanin + components: + - type: Sprite + netsync: false + sprite: Corvax/Mobs/Species/Vulpkanin/parts.rsi + state: "groin_m" + - type: Icon + sprite: Corvax/Mobs/Species/Vulpkanin/parts.rsi + state: "groin_m" + - type: BodyPart + partType: Groin + toolName: "a groin" + containerName: "groin_slot" + - type: ContainerContainer + containers: + groin_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 { } + - trigger: + !type:DamageTypeTrigger + damageType: Heat + damage: 400 + behaviors: + - !type:SpawnEntitiesBehavior + spawnInContainer: true + spawn: + Ash: + min: 1 + max: 1 + - !type:BurnBodyBehavior { } + - !type:PlaySoundBehavior + sound: + collection: MeatLaserImpact + - type: entity id: HeadVulpkanin name: "vulpkanin head" diff --git a/Resources/Prototypes/Corvax/Body/Prototypes/vulpkanin.yml b/Resources/Prototypes/Corvax/Body/Prototypes/vulpkanin.yml index bdbfc1747af..2a4e6db90ba 100644 --- a/Resources/Prototypes/Corvax/Body/Prototypes/vulpkanin.yml +++ b/Resources/Prototypes/Corvax/Body/Prototypes/vulpkanin.yml @@ -1,26 +1,31 @@ - type: body name: "vulpkanin" id: Vulpkanin - root: torso + root: chest slots: head: part: HeadVulpkanin connections: - - torso + - chest organs: brain: OrganHumanBrain eyes: OrganHumanEyes - torso: - part: TorsoVulpkanin + chest: + part: ChestVulpkanin connections: - right arm - left arm - - right leg - - left leg + - groin - head organs: heart: OrganAnimalHeart lungs: OrganHumanLungs + groin: + part: GroinVulpkanin + connections: + - right leg + - left leg + organs: stomach: OrganVulpkaninStomach liver: OrganAnimalLiver kidneys: OrganHumanKidneys diff --git a/Resources/Prototypes/Corvax/Species/vulpkanin.yml b/Resources/Prototypes/Corvax/Species/vulpkanin.yml index 03096f5b00d..d5ff6d6d78e 100644 --- a/Resources/Prototypes/Corvax/Species/vulpkanin.yml +++ b/Resources/Prototypes/Corvax/Species/vulpkanin.yml @@ -21,7 +21,8 @@ Hair: MobHumanoidAnyMarking FacialHair: MobHumanoidAnyMarking Snout: MobHumanoidAnyMarking - Chest: MobVulpkaninTorso + Chest: MobVulpkaninChest + Groin: MobVulpkaninGroin HeadTop: MobHumanoidAnyMarking HeadSide: MobHumanoidAnyMarking Tail: MobHumanoidAnyMarking @@ -79,22 +80,40 @@ state: head_f - type: humanoidBaseSprite - id: MobVulpkaninTorso + id: MobVulpkaninChest baseSprite: sprite: Corvax/Mobs/Species/Vulpkanin/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobVulpkaninTorsoMale + id: MobVulpkaninChestMale baseSprite: sprite: Corvax/Mobs/Species/Vulpkanin/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobVulpkaninTorsoFemale + id: MobVulpkaninChestFemale baseSprite: sprite: Corvax/Mobs/Species/Vulpkanin/parts.rsi - state: torso_f + state: chest_f + +- type: humanoidBaseSprite + id: MobVulpkaninGroin + baseSprite: + sprite: Corvax/Mobs/Species/Vulpkanin/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobVulpkaninGroinMale + baseSprite: + sprite: Corvax/Mobs/Species/Vulpkanin/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobVulpkaninGroinFemale + baseSprite: + sprite: Corvax/Mobs/Species/Vulpkanin/parts.rsi + state: groin_f - type: humanoidBaseSprite id: MobVulpkaninLLeg diff --git a/Resources/Prototypes/Corvax/sponsor.yml b/Resources/Prototypes/Corvax/sponsor.yml index edcab6b161f..0e964029b90 100644 --- a/Resources/Prototypes/Corvax/sponsor.yml +++ b/Resources/Prototypes/Corvax/sponsor.yml @@ -23,6 +23,8 @@ - type: Clothing sprite: Corvax/Sponsor/Clothing/Mask/atmosian.rsi - type: Armor + coverage: + - Head modifiers: coefficients: Heat: 0.80 @@ -156,6 +158,13 @@ - type: Clothing sprite: Corvax/Sponsor/NEKISH/Clothing/OuterClothing/Coats/hos_overcoat.rsi - type: Armor + coverage: + - Chest + - Groin + - Arm + - Tail + - Other + dismembermentChanceDeduction: 0.14 modifiers: coefficients: Blunt: 0.7 diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/base_clothingeyes.yml b/Resources/Prototypes/Entities/Clothing/Eyes/base_clothingeyes.yml index b31f821629d..260b42afd28 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/base_clothingeyes.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/base_clothingeyes.yml @@ -10,6 +10,15 @@ - type: Item size: Small storedRotation: -90 + - type: Armor # provide minimal covering to your head + coverage: + - Head + modifiers: + coefficients: + Heat: 0.95 + Blunt: 0.95 + Slash: 0.95 + Piercing: 0.95 - type: entity parent: [ClothingEyesBase, BaseFoldable] diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml index c44d7c94e6f..426216ca041 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml @@ -170,6 +170,15 @@ - type: FlashImmunity - type: EyeProtection protectionTime: 5 + - type: Armor # provide more coverage than default ones. you know, it's a sec one + coverage: + - Head + modifiers: + coefficients: + Heat: 0.9 + Blunt: 0.9 + Slash: 0.9 + Piercing: 0.9 - type: Construction graph: GlassesSecHUD node: glassesSec @@ -216,6 +225,15 @@ - type: Clothing sprite: Clothing/Eyes/Glasses/mercglasses.rsi - type: FlashImmunity + - type: Armor # the same as SEC + coverage: + - Head + modifiers: + coefficients: + Heat: 0.9 + Blunt: 0.9 + Slash: 0.9 + Piercing: 0.9 - type: EyeProtection protectionTime: 5 - type: IdentityBlocker @@ -233,9 +251,14 @@ - type: Clothing sprite: Clothing/Eyes/Glasses/thermal.rsi - type: Armor + coverage: # defends you well only against heat lol + - Head modifiers: coefficients: - Heat: 0.95 + Heat: 0.8 + Blunt: 0.95 + Slash: 0.95 + Piercing: 0.95 - type: GroupExamine - type: IdentityBlocker coverage: EYES @@ -265,3 +288,12 @@ - type: Clothing sprite: Clothing/Eyes/Glasses/ninjavisor.rsi - type: FlashImmunity + - type: Armor + coverage: + - Head + modifiers: + coefficients: + Heat: 0.9 + Blunt: 0.9 + Slash: 0.9 + Piercing: 0.9 diff --git a/Resources/Prototypes/Entities/Clothing/Hands/base_clothinghands.yml b/Resources/Prototypes/Entities/Clothing/Hands/base_clothinghands.yml index bed8b678853..1803b5013a0 100644 --- a/Resources/Prototypes/Entities/Clothing/Hands/base_clothinghands.yml +++ b/Resources/Prototypes/Entities/Clothing/Hands/base_clothinghands.yml @@ -27,6 +27,15 @@ damageProtection: flatReductions: Heat: 5 # the average lightbulb only does around four damage! + - type: Armor # the same as SEC + coverage: + - Hand + modifiers: + coefficients: + Heat: 0.9 + Blunt: 0.9 + Slash: 0.9 + Piercing: 0.9 - type: DiseaseProtection #Backmen & Ataraxia anti viral protection: 0.1 diff --git a/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml b/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml index 545c90977e2..7de3712873e 100644 --- a/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml +++ b/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml @@ -123,6 +123,8 @@ fiberMaterial: fibers-durathread fiberColor: fibers-black - type: Armor + coverage: + - Hand modifiers: coefficients: Slash: 0.95 diff --git a/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml b/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml index 3285c72f49c..da33171285f 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml @@ -160,6 +160,8 @@ heatingCoefficient: 0.1 coolingCoefficient: 0.1 - type: Armor + coverage: + - Head modifiers: coefficients: Blunt: 0.90 diff --git a/Resources/Prototypes/Entities/Clothing/Head/eva-helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/eva-helmets.yml index 60a0e0be287..611c82fe8a2 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/eva-helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/eva-helmets.yml @@ -87,6 +87,8 @@ heatingCoefficient: 0.1 coolingCoefficient: 0.1 - type: Armor + coverage: + - Head modifiers: coefficients: Heat: 0.90 diff --git a/Resources/Prototypes/Entities/Clothing/Head/hardhats.yml b/Resources/Prototypes/Entities/Clothing/Head/hardhats.yml index 15cda5a69f7..dca9f76bb33 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hardhats.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hardhats.yml @@ -65,6 +65,16 @@ - type: Tag tags: - WhitelistChameleon + - type: Armor + coverage: + - Head + dismembermentChanceDeduction: 0.07 # kinda saves you + modifiers: + coefficients: + Blunt: 0.9 + Slash: 0.9 + Piercing: 0.9 + Heat: 0.9 - type: entity parent: ClothingHeadHatHardhatBase @@ -143,9 +153,12 @@ - type: Clothing sprite: Clothing/Head/Hardhats/armored.rsi - type: Armor #Copied from the sec helmet, as it's hard to give these sane values without locational damage existing. + coverage: + - Head + dismembermentChanceDeduction: 0.2 modifiers: coefficients: - Blunt: 0.8 - Slash: 0.8 - Piercing: 0.9 - Heat: 0.8 + Blunt: 0.65 + Slash: 0.75 + Piercing: 0.75 + Heat: 0.7 diff --git a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml index b86a0b46699..eab0ad207de 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml @@ -1,9 +1,5 @@ #When adding new hardsuits, please try to keep the organization consistent with hardsuit.yml (if possible.) -#For now, since locational damage is not a thing, all "combat" hardsuits (with the exception of the deathsquad hardsuit) have the equvilent of a helmet in terms of armor. -#This is so people don't need to wear both regular, on-station helmets and hardsuits to get full protection. -#Generally, unless you're adding something like caustic damage, you should probably avoid messing with armor here outside of the above scenario. - #CREW HARDSUITS #Standard Hardsuit - type: entity @@ -186,12 +182,14 @@ highPressureMultiplier: 0.08 lowPressureMultiplier: 1000 - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.7 + Slash: 0.7 + Piercing: 0.7 + Heat: 0.7 #Security Hardsuit - type: entity @@ -210,12 +208,14 @@ highPressureMultiplier: 0.525 lowPressureMultiplier: 1000 - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.7 + Slash: 0.7 + Piercing: 0.7 + Heat: 0.7 #Brigmedic Hardsuit - type: entity @@ -231,14 +231,16 @@ - type: PointLight color: "#00FFFF" - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.95 - Slash: 0.95 - Piercing: 0.95 - Heat: 0.95 - Radiation: 0.90 - Caustic: 0.90 + Blunt: 0.75 + Slash: 0.75 + Piercing: 0.75 + Heat: 0.75 + Radiation: 0.7 + Caustic: 0.7 - type: PressureProtection highPressureMultiplier: 0.6 lowPressureMultiplier: 1000 @@ -260,12 +262,14 @@ highPressureMultiplier: 0.525 lowPressureMultiplier: 1000 - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.7 + Slash: 0.7 + Piercing: 0.7 + Heat: 0.7 #Captain's Hardsuit - type: entity @@ -365,12 +369,15 @@ highPressureMultiplier: 0.45 lowPressureMultiplier: 1000 - type: Armor + coverage: + - Head + dismembermentChanceDeduction: 0.4 modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.5 + Slash: 0.5 + Piercing: 0.5 + Heat: 0.4 #Luxury Mining Hardsuit - type: entity @@ -409,12 +416,15 @@ highPressureMultiplier: 0.08 lowPressureMultiplier: 1000 - type: Armor + coverage: + - Head + dismembermentChanceDeduction: 0.4 modifiers: - coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + coefficients: # this should protect you REALLY weeell + Blunt: 0.4 + Slash: 0.4 + Piercing: 0.4 + Heat: 0.4 - type: TinfoilHat destroyOnFry: false @@ -435,12 +445,17 @@ highPressureMultiplier: 0.08 lowPressureMultiplier: 1000 - type: Armor + coverage: + - Head + dismembermentChanceDeduction: 0.4 modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.5 + Slash: 0.5 + Piercing: 0.5 + Heat: 0.4 + Radiation: 0.6 + Caustic: 0.6 - type: TinfoilHat destroyOnFry: false @@ -466,12 +481,15 @@ - type: FireProtection reduction: 0.2 - type: Armor + coverage: + - Head + dismembermentChanceDeduction: 0.4 modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.5 + Slash: 0.5 + Piercing: 0.5 + Heat: 0.4 - type: TinfoilHat destroyOnFry: false @@ -492,12 +510,15 @@ highPressureMultiplier: 0.08 lowPressureMultiplier: 1000 - type: Armor + coverage: + - Head + dismembermentChanceDeduction: 0.4 modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.4 + Slash: 0.4 + Piercing: 0.4 + Heat: 0.4 - type: TinfoilHat destroyOnFry: false @@ -518,12 +539,15 @@ highPressureMultiplier: 0.3 lowPressureMultiplier: 1000 - type: Armor + coverage: + - Head + dismembermentChanceDeduction: 1 modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.25 + Slash: 0.25 + Piercing: 0.25 + Heat: 0.25 - type: TinfoilHat destroyOnFry: false @@ -544,12 +568,15 @@ highPressureMultiplier: 0.27 lowPressureMultiplier: 1000 - type: Armor + coverage: + - Head + dismembermentChanceDeduction: 1 modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.5 + Slash: 0.5 + Piercing: 0.5 + Heat: 0.5 - type: HeadCage #Organic Space Suit @@ -614,12 +641,15 @@ - type: PointLight # Corvax-Resprite color: cyan - type: Armor + coverage: + - Head + dismembermentChanceDeduction: 0.4 modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.5 + Slash: 0.5 + Piercing: 0.5 + Heat: 0.4 #ERT Chaplain Hardsuit - type: entity @@ -649,12 +679,15 @@ - type: PointLight color: "#f4ffad" - type: Armor + coverage: + - Head + dismembermentChanceDeduction: 0.4 modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.5 + Slash: 0.5 + Piercing: 0.5 + Heat: 0.4 #ERT Medical Hardsuit - type: entity @@ -684,12 +717,15 @@ - type: PointLight color: "#ffadc6" - type: Armor + coverage: + - Head + dismembermentChanceDeduction: 0.4 modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.5 + Slash: 0.5 + Piercing: 0.5 + Heat: 0.4 #ERT Janitor Hardsuit - type: entity @@ -737,12 +773,15 @@ heatingCoefficient: 0.005 coolingCoefficient: 0.005 - type: Armor + coverage: + - Head + dismembermentChanceDeduction: 0.4 modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.5 + Slash: 0.5 + Piercing: 0.5 + Heat: 0.4 - type: DiseaseProtection #Backmen & Ataraxia anti viral protection: 0.4 @@ -766,14 +805,17 @@ - type: FireProtection reduction: 0.2 - type: Armor + coverage: + - Head + dismembermentChanceDeduction: 1 modifiers: coefficients: - Blunt: 0.80 - Slash: 0.80 - Piercing: 0.80 - Heat: 0.80 - Radiation: 0.80 - Caustic: 0.95 + Blunt: 0.3 + Slash: 0.3 + Piercing: 0.3 + Heat: 0.3 + Radiation: 0.4 + Caustic: 0.45 - type: DiseaseProtection #Backmen & Ataraxia anti viral protection: 1 diff --git a/Resources/Prototypes/Entities/Clothing/Head/hats.yml b/Resources/Prototypes/Entities/Clothing/Head/hats.yml index 1e818226d58..62f9088edeb 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hats.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hats.yml @@ -787,6 +787,8 @@ - type: Clothing sprite: Clothing/Head/Hats/melon.rsi - type: Armor + coverage: + - Head modifiers: coefficients: Blunt: 0.95 @@ -802,9 +804,13 @@ - type: Clothing sprite: Clothing/Head/Hats/holyhatmelon.rsi - type: Armor + coverage: + - Head + dismembermentChanceDeduction: -1 modifiers: coefficients: - Caustic: 0.95 + Caustic: 0.9 + Radiation: 0.9 - type: entity parent: [ClothingHeadBase, BaseSyndicateContraband] diff --git a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml index 8f19dd2835a..2f571763a2d 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml @@ -7,12 +7,15 @@ abstract: true components: - type: Armor #Values seem to let the user survive one extra hit if attacked consistently. + coverage: + - Head + dismembermentChanceDeduction: 0.2 # gives you an ability to not get your fucking head chopped off by a random sabre hit modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.8 + Slash: 0.7 + Piercing: 0.7 + Heat: 0.7 - type: Tag tags: - WhitelistChameleon @@ -61,14 +64,16 @@ - type: Clothing sprite: Clothing/Head/Helmets/swat.rsi - type: Armor #This is intentionally not spaceproof, when the time comes to port the values from SS13 this should be buffed from what it was. + coverage: + - Head modifiers: coefficients: - Blunt: 0.80 - Slash: 0.80 - Piercing: 0.80 - Heat: 0.80 - Radiation: 0.80 - Caustic: 0.95 + Blunt: 0.6 + Slash: 0.6 + Piercing: 0.6 + Heat: 0.6 + Radiation: 0.9 + Caustic: 0.9 # why - type: ExplosionResistance damageCoefficient: 0.75 @@ -98,11 +103,13 @@ sprite: Clothing/Head/Helmets/light_riot.rsi - type: IngestionBlocker - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.8 - Slash: 0.8 - Piercing: 0.95 + Blunt: 0.65 + Slash: 0.65 + Piercing: 0.65 #Bombsuit Helmet - type: entity @@ -119,11 +126,14 @@ - type: ExplosionResistance damageCoefficient: 0.9 - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.95 - Slash: 0.95 - Piercing: 0.95 + Heat: 0.87 + Blunt: 0.87 + Slash: 0.87 + Piercing: 0.87 - type: HideLayerClothing slots: - Hair @@ -157,12 +167,14 @@ sprite: Clothing/Head/Helmets/cult.rsi - type: IngestionBlocker - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.9 - Slash: 0.8 - Piercing: 0.9 - Heat: 0.9 + Blunt: 0.75 + Slash: 0.75 + Piercing: 0.75 + Heat: 0.75 #Space Ninja Helmet - type: entity @@ -303,6 +315,9 @@ - type: Clothing sprite: Clothing/Head/Helmets/linghelmet.rsi - type: Armor #admeme item so it should be fine being overpowered while helmets are still intentionally kneecapped. + coverage: + - Head + dismembermentChanceDeduction: 0.4 modifiers: coefficients: Blunt: 0.5 @@ -383,12 +398,15 @@ - type: Clothing sprite: Clothing/Head/Helmets/syndie-raid.rsi - type: Armor - modifiers: #There's gotta be SOME reason to use this over other helmets. + coverage: + - Head + dismembermentChanceDeduction: 0.2 + modifiers: coefficients: - Blunt: 0.85 - Slash: 0.85 - Piercing: 0.85 - Heat: 0.85 + Blunt: 0.6 + Slash: 0.6 + Piercing: 0.6 + Heat: 0.6 #Bone Helmet - type: entity diff --git a/Resources/Prototypes/Entities/Clothing/Head/hoods.yml b/Resources/Prototypes/Entities/Clothing/Head/hoods.yml index a7c6b75fe3a..b978790f3aa 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hoods.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hoods.yml @@ -153,10 +153,12 @@ - type: Clothing sprite: Clothing/Head/Hoods/rad.rsi - type: Armor + coverage: + - Head modifiers: coefficients: - Heat: 0.95 - Radiation: 0.65 + Heat: 0.7 + Radiation: 0.2 - type: IdentityBlocker - type: BreathMask - type: HideLayerClothing diff --git a/Resources/Prototypes/Entities/Clothing/Head/welding.yml b/Resources/Prototypes/Entities/Clothing/Head/welding.yml index c0ae440a56e..1835995d583 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/welding.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/welding.yml @@ -10,6 +10,15 @@ - type: FlashImmunity - type: IdentityBlocker - type: EyeProtection + - type: Armor + coverage: + - Head + modifiers: + coefficients: + Heat: 0.8 + Blunt: 0.95 + Slash: 0.85 + Piercing: 0.85 - type: PhysicalComposition materialComposition: Steel: 200 diff --git a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml index c5d032e790e..b1b744eda58 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml @@ -35,12 +35,14 @@ - type: Clothing sprite: Clothing/Mask/gassecurity.rsi - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.95 - Slash: 0.95 - Piercing: 0.95 - Heat: 0.95 + Blunt: 0.85 + Slash: 0.85 + Piercing: 0.85 + Heat: 0.85 - type: entity parent: [ClothingMaskGas, BaseSyndicateContraband] @@ -55,12 +57,14 @@ - type: FlashImmunity - type: EyeProtection - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.95 - Slash: 0.95 - Piercing: 0.95 - Heat: 0.95 + Blunt: 0.85 + Slash: 0.85 + Piercing: 0.85 + Heat: 0.85 - type: DiseaseProtection #Backmen & Ataraxia anti viral protection: 0.2 @@ -75,9 +79,11 @@ - type: Clothing sprite: Clothing/Mask/gasatmos.rsi - type: Armor + coverage: + - Head modifiers: coefficients: - Heat: 0.80 + Heat: 0.6 - type: entity parent: [ClothingMaskGasAtmos, BaseCommandContraband] @@ -116,12 +122,14 @@ - type: Clothing sprite: Clothing/Mask/gasexplorer.rsi - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.90 - Slash: 0.90 - Piercing: 0.95 - Heat: 0.95 + Blunt: 0.8 + Slash: 0.8 + Piercing: 0.85 + Heat: 0.85 - type: entity parent: ClothingMaskPullableBase @@ -157,12 +165,14 @@ - type: Clothing sprite: Clothing/Mask/medicalsecurity.rsi - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.95 - Slash: 0.95 - Piercing: 0.95 - Heat: 0.95 + Blunt: 0.85 + Slash: 0.85 + Piercing: 0.85 + Heat: 0.85 - type: DiseaseProtection #Backmen & Ataraxia anti viral protection: 0.2 @@ -249,12 +259,14 @@ - type: Clothing sprite: Clothing/Mask/clown_security.rsi - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.95 - Slash: 0.95 - Piercing: 0.95 - Heat: 0.95 + Blunt: 0.85 + Slash: 0.85 + Piercing: 0.85 + Heat: 0.85 - type: entity parent: ClothingMaskBase @@ -386,12 +398,14 @@ - Snout hideOnToggle: true - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.90 - Slash: 0.90 - Piercing: 0.95 - Heat: 0.95 + Blunt: 0.8 + Slash: 0.8 + Piercing: 0.85 + Heat: 0.85 - type: entity parent: [ ClothingMaskGas, BaseSecurityCargoContraband ] @@ -404,12 +418,14 @@ - type: Clothing sprite: Clothing/Mask/merc.rsi - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.90 - Slash: 0.90 - Piercing: 0.95 - Heat: 0.95 + Blunt: 0.8 + Slash: 0.8 + Piercing: 0.85 + Heat: 0.85 - type: entity parent: [ ClothingMaskGas, BaseCentcommContraband ] @@ -432,12 +448,14 @@ - type: FlashImmunity - type: EyeProtection - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.95 - Slash: 0.95 - Piercing: 0.95 - Heat: 0.95 + Blunt: 0.75 + Slash: 0.75 + Piercing: 0.75 + Heat: 0.8 - type: DiseaseProtection #Backmen & Ataraxia anti viral protection: 0.2 @@ -452,12 +470,14 @@ - type: Clothing sprite: Clothing/Mask/squadron.rsi - type: Armor + coverage: + - Head modifiers: coefficients: - Blunt: 0.80 - Slash: 0.80 - Piercing: 0.90 - Heat: 0.90 + Blunt: 0.7 + Slash: 0.7 + Piercing: 0.7 + Heat: 0.6 - type: DiseaseProtection #Backmen & Ataraxia anti viral protection: 0.2 diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml index 8decaf99b20..3c40a5ec815 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml @@ -13,7 +13,11 @@ sprite: Clothing/OuterClothing/Armor/security.rsi - type: Clothing sprite: Clothing/OuterClothing/Armor/security.rsi - - type: Armor #Based on /tg/ but slightly compensated to fit the fact that armor stacks in SS14. + - type: Armor # Based on /tg/ but slightly compensated to fit the fact that armor stacks in SS14. :x: + coverage: + - Chest + - Groin + dismembermentChanceDeduction: 0.2 modifiers: coefficients: Blunt: 0.70 @@ -57,12 +61,21 @@ - type: Clothing sprite: Clothing/OuterClothing/Armor/riot.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail + - Arm + - Hand + - Leg + - Foot + dismembermentChanceDeduction: 0.4 modifiers: coefficients: Blunt: 0.4 Slash: 0.4 Piercing: 0.7 - Heat: 0.9 + Heat: 0.7 Caustic: 0.9 - type: ExplosionResistance damageCoefficient: 0.9 @@ -79,6 +92,11 @@ - type: Clothing sprite: Clothing/OuterClothing/Armor/bulletproof.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail + dismembermentChanceDeduction: 0.07 modifiers: coefficients: Blunt: 0.9 @@ -87,7 +105,7 @@ ArmorPiercing: 0.70 Heat: 0.9 - type: ExplosionResistance - damageCoefficient: 0.80 + damageCoefficient: 0.60 - type: entity parent: ClothingOuterArmorBase @@ -100,12 +118,17 @@ - type: Clothing sprite: Clothing/OuterClothing/Armor/armor_reflec.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail + # Does not give dismemberment deduction because of reflection. yeah do with it somehow modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - Heat: 0.4 # this technically means it protects against fires pretty well? -heat is just for lasers and stuff, not atmos temperature + Blunt: 0.8 + Slash: 0.8 + Piercing: 0.8 + Heat: 0.33 # this technically means it protects against fires pretty well? -heat is just for lasers and stuff, not atmos temperature - type: Reflect reflectProb: 1 reflects: @@ -127,6 +150,15 @@ - type: Clothing sprite: Clothing/OuterClothing/Armor/syndie-raid.rsi - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot + - Tail + dismembermentChanceDeduction: 0.4 modifiers: coefficients: Blunt: 0.35 @@ -196,6 +228,15 @@ - type: Clothing sprite: Clothing/OuterClothing/Armor/cult_armour.rsi - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot + - Tail + dismembermentChanceDeduction: 0.332 modifiers: coefficients: Blunt: 0.5 @@ -216,9 +257,18 @@ - type: Clothing sprite: Clothing/OuterClothing/Armor/heavy.rsi - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot + - Tail + dismembermentChanceDeduction: 1 modifiers: coefficients: - Blunt: 0.2 + Blunt: 0.2 # very swag armor Slash: 0.2 Piercing: 0.2 ArmorPiercing: 0.6 @@ -287,6 +337,11 @@ - type: Clothing sprite: Clothing/OuterClothing/Armor/captain_carapace.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail + dismembermentChanceDeduction: 0.2 modifiers: coefficients: Blunt: 0.5 @@ -314,6 +369,17 @@ - type: Clothing sprite: Clothing/OuterClothing/Armor/lingarmor.rsi - type: Armor + coverage: + - Head + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot + - Tail + - Other + dismembermentChanceDeduction: 0.4 modifiers: coefficients: Blunt: 0.5 @@ -348,6 +414,15 @@ - type: Clothing sprite: Clothing/OuterClothing/Armor/flesh_armor.rsi - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot + - Tail + dismembermentChanceDeduction: 0.4 modifiers: coefficients: Blunt: 0.5 @@ -376,6 +451,16 @@ - type: Clothing sprite: Clothing/OuterClothing/Armor/bone_armor.rsi - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot + - Tail + - Other + dismembermentChanceDeduction: -1 #:trolley: modifiers: coefficients: Blunt: 0.6 @@ -404,6 +489,16 @@ - type: Clothing sprite: Clothing/OuterClothing/Armor/podwars_armor.rsi - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot + - Tail + - Other + dismembermentChanceDeduction: 0.27 modifiers: coefficients: Blunt: 0.5 diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml index 6707de71906..0e278f22aa3 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml @@ -118,12 +118,20 @@ - type: Item size: Huge - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot + dismembermentChanceDeduction: 0.2 # having a suit on saves your limbs modifiers: coefficients: - Blunt: 0.90 - Slash: 0.90 - Piercing: 0.95 - Heat: 0.90 + Blunt: 0.7 + Slash: 0.7 + Piercing: 0.75 + Heat: 0.7 Radiation: 0.25 - type: ToggleableClothing slot: head diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/bio.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/bio.yml index 26211c81bb5..88a9a8b67fe 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/bio.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/bio.yml @@ -13,9 +13,17 @@ tags: - FullBodyOuter - type: Armor + coverage: + - Head + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Caustic: 0.5 + Caustic: 0.2 - type: DiseaseProtection #Backmen & Ataraxia anti viral protection: 0.4 @@ -70,6 +78,14 @@ - type: Clothing sprite: Clothing/OuterClothing/Bio/security.rsi - type: Armor #Based on /tg/ but slightly compensated to fit the fact that armor stacks in SS14. + coverage: + - Head + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: Blunt: 0.75 @@ -77,6 +93,7 @@ Piercing: 0.70 ArmorPiercing: 0.90 Heat: 0.80 + Caustic: 0.2 - type: entity parent: ClothingOuterBioGeneral diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml index 6fb5e16c1a6..f2e0a0ae0db 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml @@ -64,6 +64,10 @@ id: ClothingOuterArmorHoS components: - type: Armor + coverage: + - Chest + - Groin + - Tail modifiers: coefficients: Blunt: 0.7 @@ -72,7 +76,7 @@ ArmorPiercing: 0.8 Stun: 0.6 Heat: 0.7 - Caustic: 0.75 # not the full 90% from ss13 because of the head + Caustic: 0.1 # ~~not~~ the full 90% from ss13 - type: ExplosionResistance damageCoefficient: 0.9 @@ -82,6 +86,10 @@ id: ClothingOuterArmorWarden components: - type: Armor + coverage: + - Chest + - Groin + - Tail modifiers: coefficients: Blunt: 0.7 @@ -131,9 +139,13 @@ heatingCoefficient: 0.1 coolingCoefficient: 0.1 - type: Armor + coverage: + - Chest + - Groin + - Tail modifiers: coefficients: - Slash: 0.95 + Slash: 0.9 - type: Food requiresSpecialDigestion: true - type: SolutionContainerManager @@ -155,9 +167,13 @@ - type: Clothing sprite: Clothing/OuterClothing/Coats/labcoat.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail modifiers: coefficients: - Caustic: 0.75 + Caustic: 0.65 - type: entity parent: [ClothingOuterStorageFoldableBaseOpened, ClothingOuterCoatLab] @@ -175,9 +191,13 @@ - type: Clothing sprite: Clothing/OuterClothing/Coats/labcoat_chem.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail modifiers: coefficients: - Caustic: 0.75 + Caustic: 0.65 - type: entity parent: [ClothingOuterStorageFoldableBaseOpened, ClothingOuterCoatLabChem] @@ -195,9 +215,13 @@ - type: Clothing sprite: Clothing/OuterClothing/Coats/labcoat_viro.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail modifiers: coefficients: - Caustic: 0.75 + Caustic: 0.65 - type: entity parent: [ClothingOuterStorageFoldableBaseOpened, ClothingOuterCoatLabViro] @@ -215,9 +239,13 @@ - type: Clothing sprite: Clothing/OuterClothing/Coats/labcoat_gene.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail modifiers: coefficients: - Caustic: 0.75 + Caustic: 0.65 - type: entity parent: [ClothingOuterStorageFoldableBaseOpened, ClothingOuterCoatLabGene] @@ -235,11 +263,15 @@ - type: Clothing sprite: Clothing/OuterClothing/Coats/labcoat_cmo.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail modifiers: coefficients: - Slash: 0.95 - Heat: 0.95 - Caustic: 0.65 + Slash: 0.84 + Heat: 0.84 + Caustic: 0.4 - type: entity parent: [ClothingOuterStorageFoldableBaseOpened, ClothingOuterCoatLabCmo] @@ -257,9 +289,13 @@ - type: Clothing sprite: Clothing/OuterClothing/Coats/labcoat_sci.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail modifiers: coefficients: - Caustic: 0.75 + Caustic: 0.65 - type: entity parent: [ClothingOuterStorageFoldableBaseOpened, ClothingOuterCoatRnd] @@ -277,9 +313,13 @@ - type: Clothing sprite: Clothing/OuterClothing/Coats/labcoat_robo.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail modifiers: coefficients: - Caustic: 0.75 + Caustic: 0.65 - type: entity parent: [ClothingOuterStorageFoldableBaseOpened, ClothingOuterCoatRobo] @@ -297,10 +337,19 @@ - type: Clothing sprite: Clothing/OuterClothing/Coats/labcoat_rd.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail + - Arm + - Hand + - Leg + - Foot + - Other modifiers: coefficients: - Caustic: 0.75 - Radiation: 0.9 + Caustic: 0.9 # Protects very good against radiation. but does very little caustic defence + Radiation: 0.6 - type: entity parent: [ClothingOuterStorageFoldableBaseOpened, ClothingOuterCoatRD] @@ -311,7 +360,7 @@ parent: ClothingOuterStorageBase id: ClothingOuterCoatPirate name: pirate garb - description: Yarr. + description: Me hearties! There's an intruder aboard the ship's bow! Yaharr! components: - type: Sprite sprite: Clothing/OuterClothing/Coats/pirate.rsi @@ -362,11 +411,15 @@ - type: Clothing sprite: Clothing/OuterClothing/Coats/dogi.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail modifiers: coefficients: - Blunt: 0.8 - Slash: 0.65 - Piercing: 0.85 + Blunt: 0.6 + Slash: 0.47 + Piercing: 0.6 - type: entity parent: ClothingOuterStorageBase @@ -412,6 +465,10 @@ - type: Clothing sprite: Clothing/OuterClothing/Coats/brigmedic.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail modifiers: coefficients: Blunt: 0.8 @@ -432,9 +489,13 @@ - type: Clothing sprite: Clothing/OuterClothing/Coats/labcoat_senior_researcher.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail modifiers: coefficients: - Caustic: 0.75 + Caustic: 0.65 - type: entity parent: ClothingOuterStorageBase @@ -447,9 +508,13 @@ - type: Clothing sprite: Clothing/OuterClothing/Coats/labcoat_senior_physician.rsi - type: Armor + coverage: + - Chest + - Groin + - Tail modifiers: coefficients: - Caustic: 0.75 + Caustic: 0.65 - type: entity parent: ClothingOuterStorageBase diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml index 88adc19e9c1..6fbdaec05a5 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml @@ -15,14 +15,21 @@ - type: ExplosionResistance damageCoefficient: 0.9 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - ArmorPiercing: 0.9 - Caustic: 0.9 - Stun: 0.9 + Blunt: 0.8 + Slash: 0.8 + Piercing: 0.8 + ArmorPiercing: 0.8 + Caustic: 0.8 + Stun: 0.8 - type: ClothingSpeedModifier walkModifier: 0.80 sprintModifier: 0.80 @@ -52,16 +59,22 @@ - type: ExplosionResistance damageCoefficient: 0.5 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - ArmorPiercing: 0.9 - Heat: 0.8 - Radiation: 0.5 - Caustic: 0.5 - Stun: 0.6 + Blunt: 0.6 + Slash: 0.6 + Piercing: 0.6 + Heat: 0.3 + Radiation: 0.4 + Caustic: 0.4 + Stun: 0.4 # not sigma - type: ClothingSpeedModifier walkModifier: 0.7 sprintModifier: 0.7 @@ -86,16 +99,23 @@ - type: ExplosionResistance damageCoefficient: 0.5 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - ArmorPiercing: 0.9 - Shock: 0.8 + Blunt: 0.6 + Slash: 0.6 + Piercing: 0.6 + Heat: 0.45 + Shock: 0.5 Caustic: 0.5 Radiation: 0.2 - Stun: 0.7 + Stun: 0.5 - type: ClothingSpeedModifier walkModifier: 0.7 sprintModifier: 0.7 @@ -118,15 +138,21 @@ highPressureMultiplier: 0.7 lowPressureMultiplier: 1000 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.9 - ArmorPiercing: 0.9 + Blunt: 0.8 + Slash: 0.8 + Piercing: 0.8 Radiation: 0.3 #salv is supposed to have radiation hazards in the future Caustic: 0.8 - Stun: 0.8 + Stun: 0.7 - type: ClothingSpeedModifier walkModifier: 0.9 sprintModifier: 0.8 @@ -156,15 +182,22 @@ - type: ExplosionResistance damageCoefficient: 0.3 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.7 - Slash: 0.7 - Piercing: 0.5 - ArmorPiercing: 0.6 + Blunt: 0.5 + Slash: 0.5 + Piercing: 0.4 + Heat: 0.5 Radiation: 0.3 Caustic: 0.7 - Stun: 0.7 + Stun: 0.4 - type: ClothingSpeedModifier walkModifier: 0.75 sprintModifier: 0.75 @@ -191,10 +224,10 @@ - type: Armor modifiers: coefficients: - Blunt: 0.7 - Slash: 0.7 - Piercing: 0.5 - Heat: 0.7 #Goliath hide gets grilled instead of you + Blunt: 0.5 + Slash: 0.5 + Piercing: 0.34 + Heat: 0.5 #Goliath hide gets grilled instead of you Radiation: 0.3 Caustic: 0.8 - type: ClothingSpeedModifier @@ -225,12 +258,18 @@ walkModifier: 1.0 sprintModifier: 1.0 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.6 - Slash: 0.6 - Piercing: 0.5 - ArmorPiercing: 0.6 + Blunt: 0.3 + Slash: 0.3 + Piercing: 0.3 Heat: 0.3 Radiation: 0.1 - type: ExplosionResistance @@ -256,16 +295,23 @@ highPressureMultiplier: 0.5 lowPressureMultiplier: 1000 - type: ExplosionResistance - damageCoefficient: 0.4 + damageCoefficient: 0.3 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.6 - Slash: 0.6 - Piercing: 0.6 - ArmorPiercing: 0.6 + Blunt: 0.4 + Slash: 0.4 + Piercing: 0.4 + Heat: 0.5 Caustic: 0.7 - Stun: 0.5 + Stun: 0.3 # I hate this really much - type: ClothingSpeedModifier walkModifier: 0.75 sprintModifier: 0.75 @@ -288,15 +334,21 @@ highPressureMultiplier: 0.3 lowPressureMultiplier: 1000 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: # backmen brigmedic's hardsuit rebalance - Blunt: 0.7 - Slash: 0.8 - Piercing: 0.7 - ArmorPiercing: 0.7 - Heat: 0.8 + Blunt: 0.3 + Slash: 0.3 + Piercing: 0.3 + Heat: 0.5 Caustic: 0.5 - Stun: 0.7 + Stun: 0.2 - type: ClothingSpeedModifier # backmen brigmedic's hardsuit rebalance walkModifier: 0.85 sprintModifier: 0.85 @@ -321,12 +373,19 @@ - type: ExplosionResistance damageCoefficient: 0.4 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.5 - Slash: 0.6 - Piercing: 0.6 - ArmorPiercing: 0.6 + Blunt: 0.3 + Slash: 0.3 + Piercing: 0.3 + Heat: 0.5 Caustic: 0.7 Stun: 0.5 - type: ClothingSpeedModifier @@ -353,16 +412,22 @@ - type: ExplosionResistance damageCoefficient: 0.5 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.5 #Backmen edit - Slash: 0.5 #Backmen edit - Piercing: 0.5 #Backmen edit - ArmorPiercing: 0.6 #Backmen edit - Heat: 0.5 #Backmen edit - Radiation: 0.5 #Backmen edit - Caustic: 0.5 #Backmen edit - Stun: 0.6 #Backmen edit + Blunt: 0.3 + Slash: 0.3 + Piercing: 0.3 + Heat: 0.3 + Radiation: 0.6 + Caustic: 0.6 + Stun: 0.1 - type: ClothingSpeedModifier walkModifier: 0.9 #Backmen edit sprintModifier: 0.9 #Backmen edit @@ -389,12 +454,18 @@ - type: ExplosionResistance damageCoefficient: 0.2 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.8 - Slash: 0.8 - Piercing: 0.8 - ArmorPiercing: 0.8 + Blunt: 0.4 + Slash: 0.4 + Piercing: 0.4 Heat: 0.4 Radiation: 0.0 Caustic: 0.7 @@ -417,13 +488,26 @@ sprite: Clothing/OuterClothing/Hardsuits/medical.rsi - type: Clothing sprite: Clothing/OuterClothing/Hardsuits/medical.rsi + - type: ExplosionResistance + damageCoefficient: 0.5 - type: PressureProtection highPressureMultiplier: 0.3 lowPressureMultiplier: 1000 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Caustic: 0.1 + Blunt: 0.6 + Slash: 0.6 + Piercing: 0.6 + Heat: 0.4 + Caustic: 0 # it literally gives no other protections. so - type: ClothingSpeedModifier walkModifier: 0.9 sprintModifier: 0.95 @@ -446,16 +530,23 @@ highPressureMultiplier: 0.02 lowPressureMultiplier: 1000 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.6 - Slash: 0.8 - Piercing: 0.9 - ArmorPiercing: 0.8 - Heat: 0.3 + Blunt: 0.7 + Slash: 0.7 + Piercing: 0.7 + ArmorPiercing: 0.7 + Heat: 0.4 Radiation: 0.1 - Caustic: 0.2 - Stun: 0.4 + Caustic: 0.1 + Stun: 0.6 # it is NOT supposed to be stronger than sec - type: ExplosionResistance damageCoefficient: 0.1 - type: ClothingSpeedModifier @@ -492,17 +583,23 @@ highPressureMultiplier: 0.45 lowPressureMultiplier: 1000 - type: ExplosionResistance - damageCoefficient: 0.6 + damageCoefficient: 0.2 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.6 - Slash: 0.5 - Piercing: 0.5 - ArmorPiercing: 0.6 + Blunt: 0.3 + Slash: 0.3 + Piercing: 0.3 Radiation: 0.5 - Caustic: 0.6 - Stun: 0.5 + Caustic: 0.5 + Stun: 0.2 - type: ClothingSpeedModifier walkModifier: 0.8 sprintModifier: 0.8 @@ -528,14 +625,20 @@ - type: ExplosionResistance damageCoefficient: 0.5 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 - Piercing: 0.8 - ArmorPiercing: 0.8 + Blunt: 0.4 + Slash: 0.4 + Piercing: 0.5 Radiation: 0.5 - Caustic: 0.8 + Caustic: 0.5 Stun: 0.5 - type: ClothingSpeedModifier walkModifier: 0.85 @@ -562,15 +665,21 @@ highPressureMultiplier: 0.05 lowPressureMultiplier: 1000 - type: ExplosionResistance - damageCoefficient: 0.5 + damageCoefficient: 0.2 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.5 - Slash: 0.5 - Piercing: 0.5 - ArmorPiercing: 0.7 - Heat: 0.5 + Blunt: 0.3 + Slash: 0.3 + Piercing: 0.3 + Heat: 0.3 Radiation: 0.5 Caustic: 0.5 Stun: 0.2 @@ -626,13 +735,19 @@ - type: FireProtection reduction: 0.8 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.6 - Slash: 0.6 - Piercing: 0.6 - ArmorPiercing: 0.3 - Heat: 0.2 + Blunt: 0.3 + Slash: 0.3 + Piercing: 0.3 + Heat: 0.3 Radiation: 0.01 Caustic: 0.5 Stun: 0.2 @@ -660,17 +775,23 @@ highPressureMultiplier: 0.05 lowPressureMultiplier: 1000 - type: ExplosionResistance - damageCoefficient: 0.5 + damageCoefficient: 0.2 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.4 - Slash: 0.4 + Blunt: 0.3 + Slash: 0.3 Piercing: 0.3 - ArmorPiercing: 0.4 Heat: 0.5 - Radiation: 0.25 - Caustic: 0.4 + Radiation: 0.5 + Caustic: 0.5 Stun: 0.2 - type: ClothingSpeedModifier walkModifier: 1.0 @@ -694,18 +815,26 @@ highPressureMultiplier: 0.2 lowPressureMultiplier: 1000 - type: ExplosionResistance - damageCoefficient: 0.3 + damageCoefficient: 0.05 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot + dismembermentChanceDeduction: 1 modifiers: coefficients: - Blunt: 0.2 - Slash: 0.2 + Blunt: 0.1 + Slash: 0.1 Piercing: 0.2 ArmorPiercing: 0.35 Heat: 0.2 - Radiation: 0.2 - Caustic: 0.2 - Stun: 0.1 + Radiation: 0.1 + Caustic: 0.1 + Stun: 0.01 # stronk - type: ClothingSpeedModifier walkModifier: 0.9 sprintModifier: 0.65 @@ -730,15 +859,21 @@ - type: ExplosionResistance damageCoefficient: 0.5 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.6 - Slash: 0.6 - Piercing: 0.4 - ArmorPiercing: 0.7 - Heat: 0.25 - Radiation: 0.25 - Caustic: 0.75 + Blunt: 0.5 + Slash: 0.5 + Piercing: 0.5 + Heat: 0.3 + Radiation: 0.1 + Caustic: 0.55 Stun: 0.4 - type: ClothingSpeedModifier walkModifier: 0.8 @@ -764,13 +899,20 @@ - type: ExplosionResistance damageCoefficient: 0.2 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.95 - Slash: 0.95 - Piercing: 1 - Heat: 0.5 - Stun: 0.7 + Blunt: 0.85 + Slash: 0.85 + Piercing: 0.85 + Heat: 0.4 + Stun: 0.8 - type: ClothingSpeedModifier walkModifier: 0.8 sprintModifier: 0.8 @@ -794,13 +936,20 @@ - type: ExplosionResistance damageCoefficient: 0.7 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.8 - Slash: 0.8 - Piercing: 0.9 + Blunt: 0.7 + Slash: 0.7 + Piercing: 0.8 Heat: 0.4 - Caustic: 0.75 + Caustic: 0.6 Stun: 0.8 - type: ClothingSpeedModifier walkModifier: 0.6 @@ -828,14 +977,20 @@ - type: ExplosionResistance damageCoefficient: 0.6 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.7 - Slash: 0.8 - Piercing: 0.85 - ArmorPiercing: 0.9 - Heat: 0.4 - Caustic: 0.75 + Blunt: 0.4 + Slash: 0.4 + Piercing: 0.5 + Heat: 0.3 + Caustic: 0.5 Stun: 0.4 - type: ClothingSpeedModifier walkModifier: 0.8 @@ -954,20 +1109,26 @@ heatingCoefficient: 0.001 coolingCoefficient: 0.001 - type: ExplosionResistance - damageCoefficient: 0.2 + damageCoefficient: 0.0 - type: FireProtection reduction: 0.8 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.1 #best armor in the game - Slash: 0.1 - Piercing: 0.1 - ArmorPiercing: 0.3 - Heat: 0.1 - Radiation: 0.1 - Caustic: 0.1 - Stun: 0.1 + Blunt: 0.05 #best armor in the game + Slash: 0.05 + Piercing: 0.05 + Heat: 0.05 + Radiation: 0.05 + Caustic: 0.05 + Stun: 0.01 # reasons - type: ClothingSpeedModifier walkModifier: 1.0 sprintModifier: 1.0 @@ -995,19 +1156,25 @@ heatingCoefficient: 0.001 coolingCoefficient: 0.001 - type: ExplosionResistance - damageCoefficient: 0.7 + damageCoefficient: 0.3 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.7 - Slash: 0.7 - Piercing: 0.6 - ArmorPiercing: 0.9 - Heat: 0.1 - Cold: 0.1 - Shock: 0.1 - Radiation: 0.1 - Caustic: 0.1 + Blunt: 0.4 + Slash: 0.4 + Piercing: 0.5 + Heat: 0.05 + Cold: 0.05 + Shock: 0.05 + Radiation: 0.2 + Caustic: 0.2 Stun: 0.1 - type: ClothingSpeedModifier walkModifier: 1.0 @@ -1036,10 +1203,17 @@ - type: ExplosionResistance damageCoefficient: 0.9 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.9 - Slash: 0.9 + Blunt: 0.8 + Slash: 0.8 Piercing: 0.9 Caustic: 0.8 Stun: 1.3 @@ -1087,11 +1261,18 @@ - type: ExplosionResistance damageCoefficient: 0.85 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.85 - Slash: 0.9 - Piercing: 0.85 + Blunt: 0.7 # to protect santa from filthy santa deniers + Slash: 0.7 + Piercing: 0.8 Caustic: 0.8 - type: ClothingSpeedModifier walkModifier: 0.9 @@ -1099,4 +1280,3 @@ - type: HeldSpeedModifier - type: ToggleableClothing clothingPrototype: ClothingHeadHelmetHardsuitSanta - diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml index 6b3834cbfea..2e74b75adb1 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml @@ -115,11 +115,18 @@ heatingCoefficient: 0.1 coolingCoefficient: 0.1 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Heat: 0.90 - Radiation: 0.75 - Caustic: 0.5 + Heat: 0.8 + Radiation: 0.5 + Caustic: 0.3 - type: GroupExamine - type: StealTarget stealGroup: ClothingOuterHardsuitVoidParamed diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml index 316fc134a3d..ff91f1bfd8c 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml @@ -12,6 +12,13 @@ walkModifier: 0.8 sprintModifier: 0.8 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: Blunt: 0.9 @@ -59,11 +66,19 @@ - type: FireProtection reduction: 0.65 # doesnt have a full seal so not as good - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Slash: 0.9 - Heat: 0.8 - Cold: 0.8 + Slash: 0.7 + Heat: 0.5 + Piercing: 0.8 + Cold: 0.5 - type: ClothingSpeedModifier walkModifier: 0.8 sprintModifier: 0.7 @@ -93,11 +108,18 @@ - type: FireProtection reduction: 0.8 # atmos firesuit offers best protection, hardsuits are a little vulnerable - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Slash: 0.9 - Heat: 0.8 - Cold: 0.8 + Slash: 0.8 + Heat: 0.4 + Cold: 0.4 - type: ClothingSpeedModifier walkModifier: 0.8 sprintModifier: 0.8 @@ -117,9 +139,16 @@ - type: Sprite sprite: Clothing/OuterClothing/Suits/rad.rsi - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Heat: 0.90 + Heat: 0.8 Radiation: 0.01 - type: Clothing sprite: Clothing/OuterClothing/Suits/rad.rsi @@ -153,6 +182,13 @@ heatingCoefficient: 0.01 coolingCoefficient: 0.01 - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: Blunt: 0.8 diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml index 96d4060d45b..f1fff487469 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml @@ -10,10 +10,17 @@ - type: Clothing sprite: Clothing/OuterClothing/Vests/webvest.rsi - type: Armor + coverage: + - Chest + - Groin + - Arm + - Hand + - Leg + - Foot modifiers: coefficients: - Blunt: 0.6 #ballistic plates = better protection - Slash: 0.6 + Blunt: 0.5 #ballistic plates = better protection + Slash: 0.5 Piercing: 0.3 ArmorPiercing: 0.6 Heat: 0.9 @@ -32,10 +39,13 @@ - type: Clothing sprite: Clothing/OuterClothing/Vests/mercwebvest.rsi - type: Armor + coverage: + - Chest + - Groin modifiers: coefficients: - Blunt: 0.7 #slightly better overall protection but slightly worse than bulletproof armor against bullets seems sensible - Slash: 0.7 + Blunt: 0.45 #slightly better overall protection but slightly worse than bulletproof armor against bullets seems sensible + Slash: 0.45 Piercing: 0.5 ArmorPiercing: 0.7 Heat: 0.9 diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml index c1419717006..2a0e504aed5 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml @@ -14,6 +14,11 @@ - type: Item size: Normal - type: Armor + coverage: + - Chest + - Groin + - Arm + - Tail modifiers: coefficients: Slash: 0.95 diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml index ba839cea253..81de5db6c31 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml @@ -228,6 +228,11 @@ graph: BananaClownJumpsuit node: jumpsuit - type: Armor + coverage: + - Chest + - Groin + - Arm + - Leg modifiers: coefficients: Radiation: 0.8 diff --git a/Resources/Prototypes/Entities/Clothing/base_clothing.yml b/Resources/Prototypes/Entities/Clothing/base_clothing.yml index da9a7f8b1a9..554ffc0a873 100644 --- a/Resources/Prototypes/Entities/Clothing/base_clothing.yml +++ b/Resources/Prototypes/Entities/Clothing/base_clothing.yml @@ -9,9 +9,15 @@ - type: Tag tags: - WhitelistChameleon + - type: Armor + modifiers: {} + coverage: + - Other + - Chest + - Groin - type: StaticPrice price: 10 - - type: FlavorProfile #yes not every peice of clothing is edible, but this way every edible piece of clothing should have the flavor without me having to track down what specific clothing can and cannot be eaten. + - type: FlavorProfile #yes not every piece of clothing is edible, but this way every edible piece of clothing should have the flavor without me having to track down what specific clothing can and cannot be eaten. flavors: - fiber @@ -59,6 +65,8 @@ # to show explosion resistance examine - type: GroupExamine - type: Armor + coverage: + - Other modifiers: {} # for clothing that can be toggled, like magboots diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/smokables.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/smokables.yml index 9c8c76de229..2c729de7038 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/smokables.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/smokables.yml @@ -70,7 +70,7 @@ - id: Joint - id: JointRainbow weight: 0.5 - - id: Blunt + - id: BluntCigar - id: BluntRainbow weight: 0.5 - !type:GroupSelector diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 0a4005a7bae..e366a047687 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -1525,6 +1525,9 @@ name: ghost-role-information-monkey-name description: ghost-role-information-monkey-description rules: ghost-role-information-nonantagonist-rules + - type: Consciousness + threshold: 12 + cap: 55 - type: GhostTakeoverAvailable - type: Clumsy gunShootFailDamage: diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml index d66f43957d8..35a9ab95497 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml @@ -250,22 +250,21 @@ deathPenalty: 0.01 # However they really ought to be living and intact, otherwise they're worth 100x less. - type: Pullable - type: Puller - - type: BodyEmotes soundsId: GeneralBodyEmotes - - type: DamageVisuals - thresholds: [ 10, 20, 30, 50, 70, 100 ] - targetLayers: - - "enum.HumanoidVisualLayers.Chest" - - "enum.HumanoidVisualLayers.Head" - - "enum.HumanoidVisualLayers.LArm" - - "enum.HumanoidVisualLayers.LLeg" - - "enum.HumanoidVisualLayers.RArm" - - "enum.HumanoidVisualLayers.RLeg" - damageOverlayGroups: - Brute: - sprite: Mobs/Effects/brute_damage.rsi - color: "#DD8822" + #- type: DamageVisuals + # thresholds: [ 10, 20, 30, 50, 70, 100 ] + # targetLayers: + # - "enum.HumanoidVisualLayers.Chest" + # - "enum.HumanoidVisualLayers.Head" + # - "enum.HumanoidVisualLayers.LArm" + # - "enum.HumanoidVisualLayers.LLeg" + # - "enum.HumanoidVisualLayers.RArm" + # - "enum.HumanoidVisualLayers.RLeg" + # damageOverlayGroups: + # Brute: + # sprite: Mobs/Effects/brute_damage.rsi + # color: "#DD8822" # Organs - type: IdExaminable - type: HealthExaminable diff --git a/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml b/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml index 6fcea44b9db..49552c9c36b 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml @@ -62,13 +62,13 @@ types: Piercing: 5 # Visual & Audio - - type: DamageVisuals - damageOverlayGroups: - Brute: - sprite: Mobs/Effects/brute_damage.rsi - color: "#162581" - Burn: - sprite: Mobs/Effects/burn_damage.rsi + #- type: DamageVisuals + # damageOverlayGroups: + # Brute: + # sprite: Mobs/Effects/brute_damage.rsi + # color: "#162581" + # Burn: + # sprite: Mobs/Effects/burn_damage.rsi - type: Speech speechVerb: Arachnid speechSounds: Arachnid diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml index 254888e1de3..f147b1fd3ef 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/base.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml @@ -12,6 +12,7 @@ - type: Sprite layers: - map: [ "enum.HumanoidVisualLayers.Chest" ] + - map: [ "enum.HumanoidVisualLayers.Groin" ] - map: [ "enum.HumanoidVisualLayers.Head" ] - map: [ "enum.HumanoidVisualLayers.Snout" ] - map: [ "enum.HumanoidVisualLayers.Eyes" ] @@ -55,21 +56,23 @@ sprite: "Effects/creampie.rsi" state: "creampie_human" visible: false - - type: DamageVisuals - thresholds: [ 10, 20, 30, 50, 70, 100 ] - targetLayers: - - "enum.HumanoidVisualLayers.Chest" - - "enum.HumanoidVisualLayers.Head" - - "enum.HumanoidVisualLayers.LArm" - - "enum.HumanoidVisualLayers.LLeg" - - "enum.HumanoidVisualLayers.RArm" - - "enum.HumanoidVisualLayers.RLeg" - damageOverlayGroups: - Brute: - sprite: Mobs/Effects/brute_damage.rsi - color: "#FF0000" - Burn: - sprite: Mobs/Effects/burn_damage.rsi + #- type: DamageVisuals + # thresholds: [ 10, 20, 30, 50, 70, 100 ] + # targetLayers: + # - "enum.HumanoidVisualLayers.Chest" + # - "enum.HumanoidVisualLayers.Head" + # - "enum.HumanoidVisualLayers.LArm" + # - "enum.HumanoidVisualLayers.LLeg" + # - "enum.HumanoidVisualLayers.RArm" + # - "enum.HumanoidVisualLayers.RLeg" + # damageOverlayGroups: + # Brute: + # sprite: Mobs/Effects/brute_damage.rsi + # color: "#FF0000" + # Burn: + # sprite: Mobs/Effects/burn_damage.rsi + - type: Consciousness + threshold: 35 - type: GenericVisualizer visuals: enum.CreamPiedVisuals.Creamed: @@ -255,15 +258,6 @@ types: Blunt: 0.50 #per second, scales with pressure and other constants. Heat: 0.1 - - type: PassiveDamage # Slight passive regen. Assuming one damage type, comes out to about 4 damage a minute. - allowedStates: - - Alive - damageCap: 20 - damage: - types: - Heat: -0.07 - groups: - Brute: -0.07 - type: Fingerprint - type: Blindable # Other @@ -332,6 +326,7 @@ # TODO BODY Turn these into individual body parts? layers: - map: [ "enum.HumanoidVisualLayers.Chest" ] + - map: [ "enum.HumanoidVisualLayers.Groin" ] - map: [ "enum.HumanoidVisualLayers.Head" ] - map: [ "enum.HumanoidVisualLayers.Snout" ] - map: [ "enum.HumanoidVisualLayers.Eyes" ] diff --git a/Resources/Prototypes/Entities/Mobs/Species/diona.yml b/Resources/Prototypes/Entities/Mobs/Species/diona.yml index 7fb784ab6ad..7c54c35dff2 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/diona.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/diona.yml @@ -20,13 +20,13 @@ - type: Damageable damageContainer: Biological damageModifierSet: Diona - - type: DamageVisuals - damageOverlayGroups: - Brute: - sprite: Mobs/Effects/brute_damage.rsi - color: "#cd7314" - Burn: - sprite: Mobs/Effects/burn_damage.rsi + #- type: DamageVisuals + # damageOverlayGroups: + # Brute: + # sprite: Mobs/Effects/brute_damage.rsi + # color: "#cd7314" + # Burn: + # sprite: Mobs/Effects/burn_damage.rsi - type: Butcherable butcheringType: Spike spawned: diff --git a/Resources/Prototypes/Entities/Mobs/Species/gingerbread.yml b/Resources/Prototypes/Entities/Mobs/Species/gingerbread.yml index 57ef98e69d3..326d4d5fb20 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/gingerbread.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/gingerbread.yml @@ -16,13 +16,13 @@ - type: Damageable damageContainer: Biological damageModifierSet: Gingerbread - - type: DamageVisuals - damageOverlayGroups: - Brute: - sprite: Mobs/Effects/brute_damage.rsi - color: "#896e55" - Burn: - sprite: Mobs/Effects/burn_damage.rsi + #- type: DamageVisuals + # damageOverlayGroups: + # Brute: + # sprite: Mobs/Effects/brute_damage.rsi + # color: "#896e55" + # Burn: + # sprite: Mobs/Effects/burn_damage.rsi - type: Butcherable butcheringType: Spike spawned: diff --git a/Resources/Prototypes/Entities/Mobs/Species/moth.yml b/Resources/Prototypes/Entities/Mobs/Species/moth.yml index e8c7902f6b7..187ff6d69f9 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/moth.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/moth.yml @@ -34,13 +34,13 @@ amount: 5 - type: Bloodstream bloodReagent: InsectBlood - - type: DamageVisuals - damageOverlayGroups: - Brute: - sprite: Mobs/Effects/brute_damage.rsi - color: "#808A51" - Burn: - sprite: Mobs/Effects/burn_damage.rsi + #- type: DamageVisuals I fucking hate those goddamn moths + # damageOverlayGroups: + # Brute: + # sprite: Mobs/Effects/brute_damage.rsi + # color: "#808A51" + # Burn: + # sprite: Mobs/Effects/burn_damage.rsi - type: MothAccent - type: Vocal sounds: diff --git a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml index e6575239d81..67358ec2fc9 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml @@ -18,6 +18,9 @@ - type: Icon sprite: Mobs/Species/Reptilian/parts.rsi state: full + - type: Consciousness # Idk they are kinda more resistant to pain + threshold: 40 + cap: 110 - type: Body prototype: Reptilian requiredLegs: 2 diff --git a/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml b/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml index 764cd23311d..e5c4e113f93 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml @@ -19,13 +19,13 @@ - type: Damageable damageContainer: Biological damageModifierSet: Skeleton - - type: DamageVisuals - damageOverlayGroups: - Brute: - sprite: Mobs/Effects/brute_damage.rsi - color: "#555555AA" - Burn: - sprite: Mobs/Effects/burn_damage.rsi + #- type: DamageVisuals + # damageOverlayGroups: + # Brute: + # sprite: Mobs/Effects/brute_damage.rsi + # color: "#555555AA" + # Burn: + # sprite: Mobs/Effects/burn_damage.rsi - type: MobState - type: MobThresholds thresholds: diff --git a/Resources/Prototypes/Entities/Mobs/Species/slime.yml b/Resources/Prototypes/Entities/Mobs/Species/slime.yml index f31d8d160b2..0e2b66a9277 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/slime.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/slime.yml @@ -36,7 +36,7 @@ enum.StoreUiKey.Key: type: StoreBoundUserInterface enum.SurgeryUIKey.Key: # backmen: surgery - type: SurgeryBui + type: SurgeryBui # to prevent bag open/honk spam - type: UseDelay delay: 0.5 @@ -56,22 +56,13 @@ - type: Damageable damageContainer: Biological damageModifierSet: Slime - - type: PassiveDamage # Around 8 damage a minute healed - allowedStates: - - Alive - damageCap: 65 - damage: - types: - Heat: -0.14 - groups: - Brute: -0.14 - - type: DamageVisuals - damageOverlayGroups: - Brute: - sprite: Mobs/Effects/brute_damage.rsi - color: "#2cf274" - Burn: - sprite: Mobs/Effects/burn_damage.rsi + #- type: DamageVisuals + # damageOverlayGroups: + # Brute: + # sprite: Mobs/Effects/brute_damage.rsi + # color: "#2cf274" + # Burn: + # sprite: Mobs/Effects/burn_damage.rsi - type: Bloodstream bloodReagent: Slime # TODO Color slime blood based on their slime color or smth - type: Barotrauma diff --git a/Resources/Prototypes/Entities/Mobs/Species/vox.yml b/Resources/Prototypes/Entities/Mobs/Species/vox.yml index 8a967122a61..b23337f1cac 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/vox.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/vox.yml @@ -32,25 +32,26 @@ - type: Damageable damageContainer: Biological damageModifierSet: Vox - - type: PassiveDamage - # Augment normal health regen to be able to tank some Poison damage - # This allows Vox to take their mask off temporarily to eat something without needing a trip to medbay afterwards. - allowedStates: - - Alive - damageCap: 20 - damage: - types: - Heat: -0.07 - Poison: -0.2 - groups: - Brute: -0.07 - - type: DamageVisuals - damageOverlayGroups: - Brute: - sprite: Mobs/Effects/brute_damage.rsi - color: "#7a8bf2" - Burn: - sprite: Mobs/Effects/burn_damage.rsi + #- type: DamageVisuals + # damageOverlayGroups: + # Brute: + # sprite: Mobs/Effects/brute_damage.rsi + # color: "#7a8bf2" + # Burn: + # sprite: Mobs/Effects/burn_damage.rsi + #- type: PassiveDamage + # Augment normal health regen to be able to tank some Poison damage + # This allows Vox to take their mask off temporarily to eat something without needing a trip to medbay afterwards. + # Removed for now. Will be enabled back with organ simulation and stuff yeah + # allowedStates: + # - Alive + # damageCap: 20 + # damage: + # types: + # Heat: -0.07 + # Poison: -0.2 + # groups: + # Brute: -0.07 - type: Bloodstream bloodReagent: AmmoniaBlood - type: MeleeWeapon diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/joints.yml b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/joints.yml index 9a0d96e89ea..1c975066d03 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/joints.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/joints.yml @@ -28,7 +28,7 @@ reagents: - ReagentId: THC Quantity: 20 - + - type: entity id: JointRainbow parent: Joint @@ -58,7 +58,7 @@ Quantity: 0.8 - type: entity - id: Blunt + id: BluntCigar parent: BaseCigar name: blunt description: A roll of dried plant matter wrapped in a dried tobacco leaf. @@ -90,7 +90,7 @@ - type: entity id: BluntRainbow - parent: Blunt + parent: BluntCigar name: blunt suffix: Rainbow description: A roll of dried plant matter wrapped in a dried tobacco leaf. Seems to be colorful inside. diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/healing.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/healing.yml index 70e83ab1cc9..4df03e80cd0 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/healing.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/healing.yml @@ -172,7 +172,7 @@ - Biological damage: groups: - Brute: -30 # 10 for each type in the group + Brute: -10 # 3.3~ for each type in the group bloodlossModifier: -10 # a suture should stop ongoing bleeding healingBeginSound: path: "/Audio/Items/Medical/brutepack_begin.ogg" @@ -211,7 +211,7 @@ damage: types: Bloodloss: -0.5 #lowers bloodloss damage - ModifyBloodLevel: 15 #restores about 5% blood per use on standard humanoids. + ModifyBloodLevel: 20 #restores about 5% blood per use on standard humanoids. healingBeginSound: path: "/Audio/Items/Medical/brutepack_begin.ogg" healingEndSound: @@ -236,25 +236,20 @@ name: tourniquet description: Stops bleeding! Hopefully. components: + - type: Tourniquet + blockedBodyParts: + - Head + - Chest + - Groin + putOnSound: + path: "/Audio/Items/Medical/brutepack_begin.ogg" + putOffSound: + path: "/Audio/Items/Medical/brutepack_end.ogg" - type: Tag tags: - SecBeltEquip - type: Sprite state: tourniquet - - type: Healing - damageContainers: - - Biological - damage: - groups: - Brute: 5 # Tourniquets HURT! - types: - Asphyxiation: 5 # Essentially Stopping all blood reaching a part of your body - bloodlossModifier: -10 # Tourniquets stop bleeding - delay: 0.5 - healingBeginSound: - path: "/Audio/Items/Medical/brutepack_begin.ogg" - healingEndSound: - path: "/Audio/Items/Medical/brutepack_end.ogg" - type: entity name: roll of gauze diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml index f4bb21650c4..fa9408726db 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml @@ -188,7 +188,7 @@ - type: Projectile damage: types: - Heat: 5 + Heat: 1 soundHit: path: "/Audio/Weapons/Guns/Hits/taser_hit.ogg" forceSound: true @@ -234,7 +234,7 @@ impactEffect: BulletImpactEffectDisabler damage: types: - Heat: 5 + Heat: 1 soundHit: collection: WeakHit forceSound: true @@ -1020,7 +1020,7 @@ impactEffect: BulletImpactEffectDisabler damage: types: - Heat: 2 + Heat: 1 soundHit: collection: WeakHit forceSound: true diff --git a/Resources/Prototypes/Reagents/medicine.yml b/Resources/Prototypes/Reagents/medicine.yml index 55c475d7347..2969ee5208f 100644 --- a/Resources/Prototypes/Reagents/medicine.yml +++ b/Resources/Prototypes/Reagents/medicine.yml @@ -137,6 +137,14 @@ metabolisms: Medicine: effects: + - !type:SuppressPain + amount: 1.2 + time: 30 # it REFRESHES. Not accumulates + - !type:AdjustPainFeels + conditions: + - !type:ReagentThreshold + min: 15 + amount: 0.04 - !type:HealthChange damage: groups: @@ -220,6 +228,14 @@ metabolisms: Medicine: effects: + - !type:SuppressPain + amount: 2 + time: 7 # it REFRESHES. Not accumulates + - !type:AdjustPainFeels + conditions: + - !type:ReagentThreshold + min: 10 + amount: 0.01 - !type:HealthChange damage: types: @@ -252,6 +268,14 @@ metabolisms: Medicine: effects: + - !type:SuppressPain + amount: 2.4 + time: 12 # it REFRESHES. Not accumulates + - !type:AdjustPainFeels + conditions: + - !type:ReagentThreshold + min: 20 + amount: 0.04 - !type:HealthChange damage: types: @@ -277,6 +301,14 @@ metabolisms: Medicine: effects: + - !type:SuppressPain + amount: 3.7 + time: 12 # it REFRESHES. Not accumulates + - !type:AdjustPainFeels + conditions: + - !type:ReagentThreshold + min: 25 + amount: 0.1 - !type:HealthChange damage: types: @@ -310,6 +342,12 @@ metabolisms: Medicine: effects: + - !type:SuppressPain + conditions: + - !type:MobStateCondition + mobstate: Critical + amount: 2 + time: 2 # very little because it's supposed to suppress pain while you're in crit - !type:HealthChange conditions: # they gotta be in crit first @@ -670,6 +708,8 @@ metabolisms: Medicine: effects: + - !type:AdjustPainFeels + amount: 0.05 # heheheh - !type:HealthChange damage: types: @@ -768,7 +808,7 @@ groups: Brute: -1 types: - Poison: -0.5 ##Should be about what it was when it healed the toxin group + Poison: -0.5 # Should be about what it was when it healed the toxin group Heat: -0.33 Shock: -0.33 Cold: -0.33 @@ -800,6 +840,9 @@ metabolisms: Medicine: effects: + - !type:SuppressPain + amount: 2 + time: 14 # it REFRESHES. Not accumulates - !type:HealthChange damage: groups: @@ -1103,6 +1146,9 @@ Medicine: metabolismRate: 0.1 # slow metabolism to not be a godly combat med, its for treating burn victims efficiently effects: + - !type:SuppressPain + amount: 4 # To prevent people from dying while being healed + time: 5 - !type:HealthChange damage: types: @@ -1170,7 +1216,7 @@ conditions: - !type:ReagentThreshold min: 12 - + - type: reagent id: Opporozidone #Name based of an altered version of the startreck chem "Opporozine" name: reagent-name-opporozidone diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/smokeables.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/smokeables.yml index fd613ae0a1f..d1ea24f31e3 100644 --- a/Resources/Prototypes/Recipes/Crafting/Graphs/smokeables.yml +++ b/Resources/Prototypes/Recipes/Crafting/Graphs/smokeables.yml @@ -11,7 +11,7 @@ doAfter: 2 - node: joint entity: Joint - + - type: constructionGraph id: smokeableJointRainbow start: start @@ -38,7 +38,7 @@ - material: GroundCannabis doAfter: 2 - node: blunt - entity: Blunt + entity: BluntCigar - type: constructionGraph id: smokeableBluntRainbow diff --git a/Resources/Prototypes/Recipes/Lathes/robotics.yml b/Resources/Prototypes/Recipes/Lathes/robotics.yml index f6579096f6e..9f74bed138a 100644 --- a/Resources/Prototypes/Recipes/Lathes/robotics.yml +++ b/Resources/Prototypes/Recipes/Lathes/robotics.yml @@ -11,8 +11,8 @@ parent: BaseRoboticsRecipe id: BaseBorgLimbRecipe materials: - Steel: 250 - Glass: 100 + Steel: 500 + Glass: 300 - type: latheRecipe abstract: true diff --git a/Resources/Prototypes/SoundCollections/ReBELL.yml b/Resources/Prototypes/SoundCollections/ReBELL.yml new file mode 100644 index 00000000000..9635c37c46b --- /dev/null +++ b/Resources/Prototypes/SoundCollections/ReBELL.yml @@ -0,0 +1,24 @@ +# Trauma Sounds +- type: soundCollection + id: BoneGone + files: + - /Audio/_Shitmed/ReBELL/Bone/BoneGone1.ogg + - /Audio/_Shitmed/ReBELL/Bone/BoneGone2.ogg + - /Audio/_Shitmed/ReBELL/Bone/BoneGone3.ogg + - /Audio/_Shitmed/ReBELL/Bone/BoneGone4.ogg + - /Audio/_Shitmed/ReBELL/Bone/BoneGone5.ogg + +# Dismemberment +- type: soundCollection + id: WoundableDestroyed + files: + - /Audio/_Shitmed/ReBELL/Woundables/WoundableDestroyed1.ogg + - /Audio/_Shitmed/ReBELL/Woundables/WoundableDestroyed2.ogg + +- type: soundCollection + id: WoundableDelimbed + files: + - /Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated1.ogg + - /Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated2.ogg + - /Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated3.ogg + - /Audio/_Shitmed/ReBELL/Woundables/WoundableAmputated4.ogg diff --git a/Resources/Prototypes/SoundCollections/screams.yml b/Resources/Prototypes/SoundCollections/screams.yml index 8fb39e9dc14..bdf01f9f12f 100644 --- a/Resources/Prototypes/SoundCollections/screams.yml +++ b/Resources/Prototypes/SoundCollections/screams.yml @@ -47,4 +47,89 @@ - /Audio/Voice/Human/femalescream_2.ogg - /Audio/Voice/Human/femalescream_3.ogg - /Audio/Voice/Human/femalescream_4.ogg - - /Audio/Voice/Human/femalescream_5.ogg \ No newline at end of file + - /Audio/Voice/Human/femalescream_5.ogg + +# BRUTAL DEATH RATTLES // REBELL +- type: soundCollection + id: PainRattles + files: + - /Audio/Voice/BrutalDeathRattles/PainRattles1.ogg + - /Audio/Voice/BrutalDeathRattles/PainRattles2.ogg + - /Audio/Voice/BrutalDeathRattles/PainRattles3.ogg + +# Pain screams (male) +- type: soundCollection + id: PainScreamsShortMale + files: + - /Audio/Voice/BrutalDeathRattles/MalePainShort1.ogg + - /Audio/Voice/BrutalDeathRattles/MalePainShort2.ogg + - /Audio/Voice/BrutalDeathRattles/MalePainShort3.ogg + - /Audio/Voice/BrutalDeathRattles/MalePainShort4.ogg + - /Audio/Voice/BrutalDeathRattles/MalePainShort5.ogg + - /Audio/Voice/BrutalDeathRattles/MalePainShort6.ogg + - /Audio/Voice/BrutalDeathRattles/MalePainShort7.ogg + +- type: soundCollection + id: AgonyScreamsMale + files: + - /Audio/Voice/BrutalDeathRattles/MaleAgony1.ogg + - /Audio/Voice/BrutalDeathRattles/MaleAgony2.ogg + - /Audio/Voice/BrutalDeathRattles/MaleAgony3.ogg + +- type: soundCollection + id: PainShockScreamsMale + files: + - /Audio/Voice/BrutalDeathRattles/PainShockMale1.ogg + - /Audio/Voice/BrutalDeathRattles/PainShockMale2.ogg + - /Audio/Voice/BrutalDeathRattles/PainShockMale3.ogg + - /Audio/Voice/BrutalDeathRattles/PainShockMale4.ogg + +- type: soundCollection + id: CritWhimpersMale + files: + - /Audio/Voice/BrutalDeathRattles/StillAliveMale1.ogg + - /Audio/Voice/BrutalDeathRattles/StillAliveMale2.ogg + - /Audio/Voice/BrutalDeathRattles/StillAliveMale3.ogg + - /Audio/Voice/BrutalDeathRattles/StillAliveMale4.ogg + +- type: soundCollection + id: PainShockWhimpersMale + files: + - /Audio/Voice/BrutalDeathRattles/StillAlivePainedMale1.ogg + - /Audio/Voice/BrutalDeathRattles/StillAlivePainedMale2.ogg + +# Pain screams (female) +- type: soundCollection + id: PainScreamsShortFemale + files: + - /Audio/Voice/BrutalDeathRattles/FemalePainShort1.ogg + - /Audio/Voice/BrutalDeathRattles/FemalePainShort2.ogg + - /Audio/Voice/BrutalDeathRattles/FemalePainShort3.ogg + - /Audio/Voice/BrutalDeathRattles/FemalePainShort4.ogg + - /Audio/Voice/BrutalDeathRattles/FemalePainShort5.ogg + +- type: soundCollection + id: AgonyScreamsFemale + files: + - /Audio/Voice/BrutalDeathRattles/FemaleAgony1.ogg + - /Audio/Voice/BrutalDeathRattles/FemaleAgony2.ogg + - /Audio/Voice/BrutalDeathRattles/FemaleAgony3.ogg + +- type: soundCollection + id: PainShockScreamsFemale + files: + - /Audio/Voice/BrutalDeathRattles/PainShockFemale1.ogg + - /Audio/Voice/BrutalDeathRattles/PainShockFemale2.ogg + - /Audio/Voice/BrutalDeathRattles/PainShockFemale3.ogg + +- type: soundCollection + id: CritWhimpersFemale + files: + - /Audio/Voice/BrutalDeathRattles/StillAliveFemale1.ogg + - /Audio/Voice/BrutalDeathRattles/StillAliveFemale2.ogg + - /Audio/Voice/BrutalDeathRattles/StillAliveFemale3.ogg + +- type: soundCollection + id: PainShockWhimpersFemale + files: + - /Audio/Voice/BrutalDeathRattles/StillAlivePainedFemale1.ogg diff --git a/Resources/Prototypes/Species/arachnid.yml b/Resources/Prototypes/Species/arachnid.yml index 84ee5c7e2d0..07f77e3aed7 100644 --- a/Resources/Prototypes/Species/arachnid.yml +++ b/Resources/Prototypes/Species/arachnid.yml @@ -20,7 +20,8 @@ sprites: Head: MobArachnidHead Snout: MobHumanoidAnyMarking - Chest: MobArachnidTorso + Chest: MobArachnidChest + Groin: MobArachnidGroin HeadTop: MobHumanoidAnyMarking HeadSide: MobHumanoidAnyMarking Tail: MobHumanoidAnyMarking @@ -90,22 +91,40 @@ state: head_f - type: humanoidBaseSprite - id: MobArachnidTorso + id: MobArachnidChest baseSprite: sprite: Mobs/Species/Arachnid/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobArachnidTorsoMale + id: MobArachnidChestMale baseSprite: sprite: Mobs/Species/Arachnid/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobArachnidTorsoFemale + id: MobArachnidChestFemale baseSprite: sprite: Mobs/Species/Arachnid/parts.rsi - state: torso_f + state: chest_f + +- type: humanoidBaseSprite + id: MobArachnidGroin + baseSprite: + sprite: Mobs/Species/Arachnid/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobArachnidGroinMale + baseSprite: + sprite: Mobs/Species/Arachnid/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobArachnidGroinFemale + baseSprite: + sprite: Mobs/Species/Arachnid/parts.rsi + state: groin_f - type: humanoidBaseSprite id: MobArachnidLLeg diff --git a/Resources/Prototypes/Species/diona.yml b/Resources/Prototypes/Species/diona.yml index 778d549cc3a..067092394ca 100644 --- a/Resources/Prototypes/Species/diona.yml +++ b/Resources/Prototypes/Species/diona.yml @@ -20,7 +20,8 @@ Head: MobDionaHead HeadTop: MobHumanoidAnyMarking HeadSide: MobHumanoidAnyMarking - Chest: MobDionaTorso + Chest: MobDionaChest + Groin: MobDionaGroin Eyes: MobDionaEyes LArm: MobDionaLArm RArm: MobDionaRArm @@ -83,22 +84,40 @@ state: head_f - type: humanoidBaseSprite - id: MobDionaTorso + id: MobDionaChest baseSprite: sprite: Mobs/Species/Diona/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobDionaTorsoMale + id: MobDionaChestMale baseSprite: sprite: Mobs/Species/Diona/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobDionaTorsoFemale + id: MobDionaChestFemale baseSprite: sprite: Mobs/Species/Diona/parts.rsi - state: torso_f + state: chest_f + +- type: humanoidBaseSprite + id: MobDionaGroin + baseSprite: + sprite: Mobs/Species/Diona/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobDionaGroinMale + baseSprite: + sprite: Mobs/Species/Diona/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobDionaGroinFemale + baseSprite: + sprite: Mobs/Species/Diona/parts.rsi + state: groin_f - type: humanoidBaseSprite id: MobDionaLLeg diff --git a/Resources/Prototypes/Species/gingerbread.yml b/Resources/Prototypes/Species/gingerbread.yml index bcce8d6ca98..5086b1e0ff2 100644 --- a/Resources/Prototypes/Species/gingerbread.yml +++ b/Resources/Prototypes/Species/gingerbread.yml @@ -15,7 +15,8 @@ Head: MobGingerbreadHead HeadTop: MobHumanoidAnyMarking HeadSide: MobHumanoidAnyMarking - Chest: MobGingerbreadTorso + Chest: MobGingerbreadChest + Groin: MobGingerbreadGroin Eyes: MobGingerbreadEyes LArm: MobGingerbreadLArm RArm: MobGingerbreadRArm @@ -51,22 +52,40 @@ state: head_f - type: humanoidBaseSprite - id: MobGingerbreadTorso + id: MobGingerbreadChest baseSprite: sprite: Mobs/Species/Gingerbread/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobGingerbreadTorsoMale + id: MobGingerbreadChestMale baseSprite: sprite: Mobs/Species/Gingerbread/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobGingerbreadTorsoFemale + id: MobGingerbreadChestFemale baseSprite: sprite: Mobs/Species/Gingerbread/parts.rsi - state: torso_f + state: chest_f + +- type: humanoidBaseSprite + id: MobGingerbreadGroin + baseSprite: + sprite: Mobs/Species/Gingerbread/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobGingerbreadGroinMale + baseSprite: + sprite: Mobs/Species/Gingerbread/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobGingerbreadGroinFemale + baseSprite: + sprite: Mobs/Species/Gingerbread/parts.rsi + state: groin_f - type: humanoidBaseSprite id: MobGingerbreadLLeg diff --git a/Resources/Prototypes/Species/human.yml b/Resources/Prototypes/Species/human.yml index ef586c55355..0cb68116463 100644 --- a/Resources/Prototypes/Species/human.yml +++ b/Resources/Prototypes/Species/human.yml @@ -22,7 +22,8 @@ Hair: MobHumanoidAnyMarking FacialHair: MobHumanoidAnyMarking Snout: MobHumanoidAnyMarking - Chest: MobHumanTorso + Chest: MobHumanChest + Groin: MobHumanGroin Tail: MobHumanoidAnyMarking # Corvax-Sponsors Eyes: MobHumanoidEyes HeadTop: MobHumanoidAnyMarking @@ -98,22 +99,40 @@ state: head_f - type: humanoidBaseSprite - id: MobHumanTorso + id: MobHumanChest baseSprite: sprite: Mobs/Species/Human/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobHumanTorsoMale + id: MobHumanChestMale baseSprite: sprite: Mobs/Species/Human/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobHumanTorsoFemale + id: MobHumanChestFemale baseSprite: sprite: Mobs/Species/Human/parts.rsi - state: torso_f + state: chest_f + +- type: humanoidBaseSprite + id: MobHumanGroin + baseSprite: + sprite: Mobs/Species/Human/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobHumanGroinMale + baseSprite: + sprite: Mobs/Species/Human/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobHumanGroinFemale + baseSprite: + sprite: Mobs/Species/Human/parts.rsi + state: groin_f - type: humanoidBaseSprite id: MobHumanLLeg diff --git a/Resources/Prototypes/Species/moth.yml b/Resources/Prototypes/Species/moth.yml index b474f613f84..c014807126c 100644 --- a/Resources/Prototypes/Species/moth.yml +++ b/Resources/Prototypes/Species/moth.yml @@ -18,7 +18,8 @@ sprites: Head: MobMothHead Snout: MobHumanoidAnyMarking - Chest: MobMothTorso + Chest: MobMothChest + Groin: MobMothGroin HeadTop: MobHumanoidAnyMarking HeadSide: MobHumanoidAnyMarking Tail: MobHumanoidAnyMarking @@ -94,22 +95,40 @@ state: head_f - type: humanoidBaseSprite - id: MobMothTorso + id: MobMothChest baseSprite: sprite: Mobs/Species/Moth/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobMothTorsoMale + id: MobMothChestMale baseSprite: sprite: Mobs/Species/Moth/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobMothTorsoFemale + id: MobMothChestFemale baseSprite: sprite: Mobs/Species/Moth/parts.rsi - state: torso_f + state: chest_f + +- type: humanoidBaseSprite + id: MobMothGroin + baseSprite: + sprite: Mobs/Species/Moth/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobMothGroinMale + baseSprite: + sprite: Mobs/Species/Moth/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobMothGroinFemale + baseSprite: + sprite: Mobs/Species/Moth/parts.rsi + state: groin_f - type: humanoidBaseSprite id: MobMothLLeg diff --git a/Resources/Prototypes/Species/reptilian.yml b/Resources/Prototypes/Species/reptilian.yml index 01f3a79767c..4f2300569b1 100644 --- a/Resources/Prototypes/Species/reptilian.yml +++ b/Resources/Prototypes/Species/reptilian.yml @@ -17,7 +17,8 @@ sprites: Head: MobReptilianHead Snout: MobHumanoidAnyMarking - Chest: MobReptilianTorso + Chest: MobReptilianChest + Groin: MobReptilianGroin HeadTop: MobHumanoidAnyMarking HeadSide: MobHumanoidAnyMarking Tail: MobHumanoidAnyMarking @@ -84,22 +85,40 @@ state: head_f - type: humanoidBaseSprite - id: MobReptilianTorso + id: MobReptilianChest baseSprite: sprite: Mobs/Species/Reptilian/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobReptilianTorsoMale + id: MobReptilianChestMale baseSprite: sprite: Mobs/Species/Reptilian/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobReptilianTorsoFemale + id: MobReptilianChestFemale baseSprite: sprite: Mobs/Species/Reptilian/parts.rsi - state: torso_f + state: chest_f + +- type: humanoidBaseSprite + id: MobReptilianGroin + baseSprite: + sprite: Mobs/Species/Reptilian/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobReptilianGroinMale + baseSprite: + sprite: Mobs/Species/Reptilian/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobReptilianGroinFemale + baseSprite: + sprite: Mobs/Species/Reptilian/parts.rsi + state: groin_f - type: humanoidBaseSprite id: MobReptilianLLeg diff --git a/Resources/Prototypes/Species/skeleton.yml b/Resources/Prototypes/Species/skeleton.yml index 1f2a95e9918..17c58a086d0 100644 --- a/Resources/Prototypes/Species/skeleton.yml +++ b/Resources/Prototypes/Species/skeleton.yml @@ -15,7 +15,8 @@ id: MobSkeletonSprites sprites: Head: MobSkeletonHead - Chest: MobSkeletonTorso + Chest: MobSkeletonChest + Groin: MobSkeletonGroin LArm: MobSkeletonLArm RArm: MobSkeletonRArm LHand: MobSkeletonLHand @@ -44,22 +45,40 @@ state: head_f - type: humanoidBaseSprite - id: MobSkeletonTorso + id: MobSkeletonChest baseSprite: sprite: Mobs/Species/Skeleton/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobSkeletonTorsoMale + id: MobSkeletonChestMale baseSprite: sprite: Mobs/Species/Skeleton/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobSkeletonTorsoFemale + id: MobSkeletonChestFemale baseSprite: sprite: Mobs/Species/Skeleton/parts.rsi - state: torso_f + state: chest_f + +- type: humanoidBaseSprite + id: MobSkeletonGroin + baseSprite: + sprite: Mobs/Species/Skeleton/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobSkeletonGroinMale + baseSprite: + sprite: Mobs/Species/Skeleton/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobSkeletonGroinFemale + baseSprite: + sprite: Mobs/Species/Skeleton/parts.rsi + state: groin_f - type: humanoidBaseSprite id: MobSkeletonLLeg diff --git a/Resources/Prototypes/Species/slime.yml b/Resources/Prototypes/Species/slime.yml index 895872256bb..a9184c72e83 100644 --- a/Resources/Prototypes/Species/slime.yml +++ b/Resources/Prototypes/Species/slime.yml @@ -15,7 +15,8 @@ Head: MobSlimeHead Hair: MobSlimeMarkingFollowSkin FacialHair: MobSlimeMarkingFollowSkin - Chest: MobSlimeTorso + Chest: MobSlimeChest + Groin: MobSlimeGroin HeadTop: MobHumanoidAnyMarking # Corvax Sponsors Tail: MobHumanoidAnyMarking # Corvax Sponsors Eyes: MobHumanoidEyes @@ -77,22 +78,40 @@ state: head_f - type: humanoidBaseSprite - id: MobSlimeTorso + id: MobSlimeChest baseSprite: sprite: Mobs/Species/Slime/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobSlimeTorsoMale + id: MobSlimeChestMale baseSprite: sprite: Mobs/Species/Slime/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobSlimeTorsoFemale + id: MobSlimeChestFemale baseSprite: sprite: Mobs/Species/Slime/parts.rsi - state: torso_f + state: chest_f + +- type: humanoidBaseSprite + id: MobSlimeGroin + baseSprite: + sprite: Mobs/Species/Slime/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobSlimeGroinMale + baseSprite: + sprite: Mobs/Species/Slime/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobSlimeGroinFemale + baseSprite: + sprite: Mobs/Species/Slime/parts.rsi + state: groin_f - type: humanoidBaseSprite id: MobSlimeLLeg diff --git a/Resources/Prototypes/Species/vox.yml b/Resources/Prototypes/Species/vox.yml index 7419f3f277e..22bab44f86b 100644 --- a/Resources/Prototypes/Species/vox.yml +++ b/Resources/Prototypes/Species/vox.yml @@ -21,7 +21,8 @@ Snout: MobHumanoidAnyMarking Hair: MobHumanoidAnyMarking FacialHair: MobHumanoidAnyMarking - Chest: MobVoxTorso + Chest: MobVoxChest + Groin: MobVoxGroin Eyes: MobVoxEyes LArm: MobVoxLArm RArm: MobVoxRArm @@ -91,22 +92,40 @@ state: head - type: humanoidBaseSprite - id: MobVoxTorso + id: MobVoxChest baseSprite: sprite: Mobs/Species/Vox/parts.rsi - state: torso + state: chest - type: humanoidBaseSprite - id: MobVoxTorsoMale + id: MobVoxChestMale baseSprite: sprite: Mobs/Species/Vox/parts.rsi - state: torso + state: chest - type: humanoidBaseSprite - id: MobVoxTorsoFemale + id: MobVoxChestFemale baseSprite: sprite: Mobs/Species/Vox/parts.rsi - state: torso + state: chest + +- type: humanoidBaseSprite + id: MobVoxGroin + baseSprite: + sprite: Mobs/Species/Vox/parts.rsi + state: groin + +- type: humanoidBaseSprite + id: MobVoxGroinMale + baseSprite: + sprite: Mobs/Species/Vox/parts.rsi + state: groin + +- type: humanoidBaseSprite + id: MobVoxGroinFemale + baseSprite: + sprite: Mobs/Species/Vox/parts.rsi + state: groin - type: humanoidBaseSprite id: MobVoxLLeg diff --git a/Resources/Prototypes/_Backmen/Body/Parts/animal.yml b/Resources/Prototypes/_Backmen/Body/Parts/animal.yml index bbf31e7c12e..7edd192bcd9 100644 --- a/Resources/Prototypes/_Backmen/Body/Parts/animal.yml +++ b/Resources/Prototypes/_Backmen/Body/Parts/animal.yml @@ -27,11 +27,23 @@ - type: entity categories: [ HideSpawnMenu ] parent: BaseCarpPart - id: TorsoCarp - name: carp torso + id: ChestCarp + name: carp chest components: - type: Sprite layers: - - state: torso + - state: chest - type: BodyPart - partType: Torso + partType: Chest + +- type: entity + categories: [ HideSpawnMenu ] + parent: BaseCarpPart + id: GroinCarp + name: carp groin + components: + - type: Sprite + layers: + - state: groin + - type: BodyPart + partType: Groin diff --git a/Resources/Prototypes/_Backmen/Body/Parts/golem.yml b/Resources/Prototypes/_Backmen/Body/Parts/golem.yml index df840c58265..c4ec88531b1 100644 --- a/Resources/Prototypes/_Backmen/Body/Parts/golem.yml +++ b/Resources/Prototypes/_Backmen/Body/Parts/golem.yml @@ -15,8 +15,8 @@ price: 100 - type: entity - id: TorsoGolemCult - name: "golem torso" + id: ChestGolemCult + name: "golem chest" parent: PartGolem components: - type: Sprite @@ -26,7 +26,21 @@ sprite: Backmen/Mobs/Species/Golem/cult.rsi state: "cultgolem_chest" - type: BodyPart - partType: Torso + partType: Chest + +- type: entity + id: GroinGolemCult + name: "golem groin" + parent: PartGolem + components: + - type: Sprite + sprite: Backmen/Mobs/Species/Golem/cult.rsi + state: "cultgolem_groin" + - type: Icon + sprite: Backmen/Mobs/Species/Golem/cult.rsi + state: "cultgolem_groin" + - type: BodyPart + partType: Groin - type: entity id: HeadGolemCult diff --git a/Resources/Prototypes/_Backmen/Body/Parts/harpy.yml b/Resources/Prototypes/_Backmen/Body/Parts/harpy.yml index 65f0bf3fedb..0c36784c107 100644 --- a/Resources/Prototypes/_Backmen/Body/Parts/harpy.yml +++ b/Resources/Prototypes/_Backmen/Body/Parts/harpy.yml @@ -1,46 +1,47 @@ - type: entity id: PartHarpy - parent: BaseItem + parent: BasePart name: "harpy body part" abstract: true + +- type: entity + id: ChestHarpy + name: "harpy chest" + parent: PartHarpy components: - - type: Damageable - damageContainer: OrganicPart # Shitmed Change + - type: Sprite + netsync: false + sprite: Backmen/Mobs/Species/Harpy/parts.rsi + state: "chest_m" + - type: Icon + sprite: Backmen/Mobs/Species/Harpy/parts.rsi + state: "chest_m" - type: BodyPart + partType: Chest + # Shitmed Change Start + toolName: "a chest" + containerName: "chest_slot" - type: ContainerContainer containers: - bodypart: !type:Container - ents: [] - - type: StaticPrice #DynamicPrice - price: 100 - - type: Tag - tags: - - Trash - # Shitmed Change Start - - type: Gibbable - - type: SurgeryTool - startSound: - path: /Audio/_Shitmed/Medical/Surgery/organ1.ogg - endSound: - path: /Audio/_Shitmed/Medical/Surgery/organ2.ogg + chest_slot: !type:ContainerSlot {} - type: Destructible thresholds: - trigger: !type:DamageTypeTrigger damageType: Blunt - damage: 120 + damage: 400 behaviors: - !type:GibPartBehavior { } - trigger: !type:DamageTypeTrigger damageType: Slash - damage: 120 + damage: 400 behaviors: - !type:GibPartBehavior { } - trigger: !type:DamageTypeTrigger damageType: Heat - damage: 200 + damage: 400 behaviors: - !type:SpawnEntitiesBehavior spawnInContainer: true @@ -55,25 +56,25 @@ # Shitmed Change End - type: entity - id: TorsoHarpy - name: "harpy torso" + id: GroinHarpy + name: "harpy groin" parent: PartHarpy components: - type: Sprite netsync: false sprite: Backmen/Mobs/Species/Harpy/parts.rsi - state: "torso_m" + state: "groin_m" - type: Icon sprite: Backmen/Mobs/Species/Harpy/parts.rsi - state: "torso_m" + state: "groin_m" - type: BodyPart - partType: Torso + partType: Groin # Shitmed Change Start - toolName: "a torso" - containerName: "torso_slot" + toolName: "a groin" + containerName: "groin_slot" - type: ContainerContainer containers: - torso_slot: !type:ContainerSlot {} + groin_slot: !type:ContainerSlot {} - type: Destructible thresholds: - trigger: @@ -105,6 +106,7 @@ collection: MeatLaserImpact # Shitmed Change End + - type: entity id: HeadHarpy name: "harpy head" diff --git a/Resources/Prototypes/_Backmen/Body/Parts/shadowkin.yml b/Resources/Prototypes/_Backmen/Body/Parts/shadowkin.yml index a87aca23e4f..02437258339 100644 --- a/Resources/Prototypes/_Backmen/Body/Parts/shadowkin.yml +++ b/Resources/Prototypes/_Backmen/Body/Parts/shadowkin.yml @@ -1,6 +1,6 @@ - type: entity id: PartShadowkin - parent: BaseItem + parent: BasePart name: "Shadowkin body part" abstract: true components: @@ -9,68 +9,40 @@ sprite: Backmen/Mobs/Species/Shadowkin/parts.rsi - type: Icon sprite: Backmen/Mobs/Species/Shadowkin/parts.rsi - - type: Damageable - damageContainer: OrganicPart # backmen: surgery - - type: SurgeryTool + +- type: entity + id: ChestShadowkin + name: "Shadowkin chest" + parent: PartShadowkin + components: + - type: Sprite + state: "chest_m" + - type: Icon + state: "chest_m" - type: BodyPart + partType: Chest + toolName: "a chest" + containerName: "chest_slot" - type: ContainerContainer containers: - bodypart: !type:Container - ents: [] - - type: StaticPrice #DynamicPrice - price: 100 - - type: Tag - tags: - - Trash - # start-backmen: surgery - - type: Gibbable - - type: Destructible - thresholds: - - trigger: - !type:DamageTypeTrigger - damageType: Blunt - damage: 120 - behaviors: - - !type:GibPartBehavior { } - - trigger: - !type:DamageTypeTrigger - damageType: Slash - damage: 120 - behaviors: - - !type:GibPartBehavior { } - - trigger: - !type:DamageTypeTrigger - damageType: Heat - damage: 200 - behaviors: - - !type:SpawnEntitiesBehavior - spawnInContainer: true - spawn: - Ash: - min: 1 - max: 1 - - !type:BurnBodyBehavior { } - - !type:PlaySoundBehavior - sound: - collection: MeatLaserImpact - # end-backmen: surgery + chest_slot: !type:ContainerSlot {} - type: entity - id: TorsoShadowkin - name: "Shadowkin torso" + id: GroinShadowkin + name: "Shadowkin groin" parent: PartShadowkin components: - type: Sprite - state: "torso_m" + state: "groin_m" - type: Icon - state: "torso_m" + state: "groin_m" - type: BodyPart - partType: Torso - toolName: "a torso" - containerName: "torso_slot" + partType: Groin + toolName: "a groin" + containerName: "groin_slot" - type: ContainerContainer containers: - torso_slot: !type:ContainerSlot {} + groin_slot: !type:ContainerSlot {} - type: entity id: HeadShadowkin diff --git a/Resources/Prototypes/_Backmen/Body/Parts/spider.yml b/Resources/Prototypes/_Backmen/Body/Parts/spider.yml index d67e2f39758..cbc8c5261f0 100644 --- a/Resources/Prototypes/_Backmen/Body/Parts/spider.yml +++ b/Resources/Prototypes/_Backmen/Body/Parts/spider.yml @@ -11,19 +11,36 @@ containers: bodypart: !type:Container ents: [] + # start-backmen: surgery + - type: Woundable + integrity: 65 + integrityCap: 65 + thresholds: + Minor: 60 + Moderate: 45 + Severe: 30 + Critical: 12 + Loss: 0 + - type: Nerve + - type: SurgeryTool + startSound: + path: /Audio/Medical/Surgery/organ1.ogg + endSound: + path: /Audio/Medical/Surgery/organ2.ogg + # end-backmen: surgery - type: entity id: ThoraxSpider name: "spider thorax" #for ArachneClassic, actual spiders should get a cephalothorax that combines with head. - parent: [PartSpider, BaseTorso] + parent: [BaseGroin, PartSpider] components: - type: Sprite netsync: false sprite: Backmen/Mobs/Species/Moth/parts.rsi # placeholder sprite - state: "torso_m" + state: "chest_m" - type: Icon sprite: Backmen/Mobs/Species/Moth/parts.rsi - state: "torso_m" + state: "chest_m" - type: BodyPart #"Other" type slotId: thorax containerName: thorax_slot diff --git a/Resources/Prototypes/_Backmen/Body/Prototypes/Animal/carp.yml b/Resources/Prototypes/_Backmen/Body/Prototypes/Animal/carp.yml index 81bf6a4bd5c..8292c467514 100644 --- a/Resources/Prototypes/_Backmen/Body/Prototypes/Animal/carp.yml +++ b/Resources/Prototypes/_Backmen/Body/Prototypes/Animal/carp.yml @@ -1,17 +1,22 @@ - type: body id: Carp name: carp - root: torso + root: chest slots: - torso: - part: TorsoAnimal + chest: + part: ChestAnimal connections: - - tail + - groin organs: lungs: OrganSpaceAnimalLungs # Immunity to airloss + heart: OrganSpaceAnimalHeart # Immunity to cold + groin: + part: GroinAnimal + connections: + - tail + organs: stomach: OrganAnimalStomach liver: OrganAnimalLiver - heart: OrganSpaceAnimalHeart # Immunity to cold kidneys: OrganAnimalKidneys tail: part: TailCarp diff --git a/Resources/Prototypes/_Backmen/Body/Prototypes/arachne.yml b/Resources/Prototypes/_Backmen/Body/Prototypes/arachne.yml index e7c09b16d0d..3cb01546061 100644 --- a/Resources/Prototypes/_Backmen/Body/Prototypes/arachne.yml +++ b/Resources/Prototypes/_Backmen/Body/Prototypes/arachne.yml @@ -1,23 +1,20 @@ - type: body id: ArachneClassic name: "ArachneClassic" - root: torso + root: chest slots: head: part: HeadHuman connections: - - torso + - chest organs: brain: OrganHumanBrain eyes: OrganHumanEyes - torso: - part: TorsoHuman + chest: + part: ChestHuman organs: heart: OrganSpaceAnimalHeart lungs: OrganSpaceAnimalLungs - stomach: OrganVampiricHumanoidStomach - liver: OrganHumanLiver - kidneys: OrganHumanKidneys connections: - right arm - left arm @@ -36,6 +33,10 @@ part: LeftHandHuman thorax: part: ThoraxSpider + organs: + stomach: OrganVampiricHumanoidStomach + liver: OrganHumanLiver + kidneys: OrganHumanKidneys connections: - left leg first - left leg second diff --git a/Resources/Prototypes/_Backmen/Body/Prototypes/drone.yml b/Resources/Prototypes/_Backmen/Body/Prototypes/drone.yml index f68c4b9800e..f2f027dd1f1 100644 --- a/Resources/Prototypes/_Backmen/Body/Prototypes/drone.yml +++ b/Resources/Prototypes/_Backmen/Body/Prototypes/drone.yml @@ -1,10 +1,10 @@ - type: body id: Drone name: "drone" - root: torso + root: chest slots: - torso: - part: TorsoDrone + chest: + part: ChestDrone connections: - left arm 1 - left arm 2 @@ -27,15 +27,15 @@ - type: entity parent: BaseItem - id: TorsoDrone - name: nt-800 torso + id: ChestDrone + name: nt-800 chest components: - type: Sprite sprite: Mobs/Species/Terminator/parts.rsi - state: torso_m + state: chest_m - type: Icon sprite: Mobs/Species/Terminator/parts.rsi - state: torso_m + state: chest_m - type: Damageable damageContainer: Inorganic damageModifierSet: Metallic @@ -47,4 +47,4 @@ - type: StaticPrice price: 200 - type: BodyPart - partType: Torso + partType: Chest diff --git a/Resources/Prototypes/_Backmen/Body/Prototypes/felinid.yml b/Resources/Prototypes/_Backmen/Body/Prototypes/felinid.yml index b3e1040c3d2..e289ec3249e 100644 --- a/Resources/Prototypes/_Backmen/Body/Prototypes/felinid.yml +++ b/Resources/Prototypes/_Backmen/Body/Prototypes/felinid.yml @@ -1,28 +1,32 @@ - type: body id: Felinid name: "felinid" - root: torso + root: chest slots: head: part: HeadHuman connections: - - torso + - chest organs: brain: OrganHumanBrain eyes: OrganHumanEyes - torso: - part: TorsoHuman - connections: # Goobstation - fix some species having their hands the wrong way around + chest: + part: ChestHuman + connections: + - groin - right arm - left arm - - right leg - - left leg - - head # Shitmed Change organs: heart: OrganAnimalHeart lungs: OrganHumanLungs + groin: + part: GroinHuman + connections: + - right leg + - left leg + organs: stomach: OrganFelinidStomach - liver: OrganAnimalLiver + liver: OrganAnimalLiver kidneys: OrganHumanKidneys right arm: part: RightArmHuman @@ -48,3 +52,4 @@ part: RightFootHuman left foot: part: LeftFootHuman + diff --git a/Resources/Prototypes/_Backmen/Body/Prototypes/haisenberg.yml b/Resources/Prototypes/_Backmen/Body/Prototypes/haisenberg.yml index fc0031c0727..dc2b45d8329 100644 --- a/Resources/Prototypes/_Backmen/Body/Prototypes/haisenberg.yml +++ b/Resources/Prototypes/_Backmen/Body/Prototypes/haisenberg.yml @@ -1,19 +1,24 @@ - type: body id: BodyHaisenberg name: "BodyHaisenberg" - root: torso + root: chest slots: - torso: - part: TorsoAnimal + chest: + part: ChestAnimal organs: lungs: OrganAnimalLungs - stomach: OrganAnimalStomach - liver: OrganAnimalLiver heart: OrganAnimalHeart - kidneys: OrganAnimalKidneys connections: - right arm - left arm + - groin + groin: + part: GroinAnimal + organs: + stomach: OrganAnimalStomach + liver: OrganAnimalLiver + kidneys: OrganAnimalKidneys + connections: - legs right arm: part: RightArmHuman diff --git a/Resources/Prototypes/_Backmen/Body/Prototypes/harpy.yml b/Resources/Prototypes/_Backmen/Body/Prototypes/harpy.yml index 06112e8cfb2..6b123719eb3 100644 --- a/Resources/Prototypes/_Backmen/Body/Prototypes/harpy.yml +++ b/Resources/Prototypes/_Backmen/Body/Prototypes/harpy.yml @@ -1,28 +1,32 @@ - type: body id: Harpy name: "harpy" - root: torso + root: chest slots: head: part: HeadHarpy connections: - - torso + - chest organs: brain: OrganHumanBrain eyes: OrganHumanEyes - torso: - part: TorsoHarpy - connections: # Goobstation - fix some species having their hands the wrong way around + chest: + part: ChestHarpy + connections: + - groin - right arm - left arm - - right leg - - left leg - - head # Shitmed Change organs: heart: OrganHumanHeart lungs: OrganHarpyLungs + groin: + part: GroinHarpy + connections: + - right leg + - left leg + organs: stomach: OrganAnimalStomach - liver: OrganAnimalLiver + liver: OrganAnimalLiver kidneys: OrganAnimalKidneys right arm: part: RightArmHarpy @@ -48,4 +52,3 @@ part: RightFootHarpy left foot: part: LeftFootHarpy - diff --git a/Resources/Prototypes/_Backmen/Body/Prototypes/shadowkin.yml b/Resources/Prototypes/_Backmen/Body/Prototypes/shadowkin.yml index 652fee55b3d..8d5f1abcf6a 100644 --- a/Resources/Prototypes/_Backmen/Body/Prototypes/shadowkin.yml +++ b/Resources/Prototypes/_Backmen/Body/Prototypes/shadowkin.yml @@ -1,29 +1,33 @@ - type: body id: Shadowkin name: "Shadowkin" - root: torso + root: chest slots: head: part: HeadShadowkin connections: - - torso + - chest organs: brain: OrganShadowkinBrain eyes: OrganShadowkinEyes - torso: - part: TorsoShadowkin + chest: + part: ChestShadowkin connections: - right arm - left arm + - groin + organs: + heart: OrganShadowkinHeart + lungs: OrganHumanLungs + groin: + part: GroinShadowkin + connections: - right leg - left leg - - head organs: - heart: OrganShadowkinHeart stomach: OrganShadowkinStomach liver: OrganShadowkinLiver kidneys: OrganShadowkinKidneys - lungs: OrganHumanLungs right arm: part: RightArmShadowkin connections: diff --git a/Resources/Prototypes/_Backmen/Entities/Body/golem.yml b/Resources/Prototypes/_Backmen/Entities/Body/golem.yml index 026f9be5ba5..93503aed3e5 100644 --- a/Resources/Prototypes/_Backmen/Entities/Body/golem.yml +++ b/Resources/Prototypes/_Backmen/Entities/Body/golem.yml @@ -8,7 +8,7 @@ connections: - torso torso: - part: TorsoGolemCult + part: ChestGolemCult connections: - left arm - right arm diff --git a/Resources/Prototypes/_Backmen/Entities/Body/vampiricanimal.yml b/Resources/Prototypes/_Backmen/Entities/Body/vampiricanimal.yml index 7feed8d2df5..4204f8bc97f 100644 --- a/Resources/Prototypes/_Backmen/Entities/Body/vampiricanimal.yml +++ b/Resources/Prototypes/_Backmen/Entities/Body/vampiricanimal.yml @@ -4,7 +4,7 @@ root: torso slots: torso: - part: TorsoAnimal + part: ChestAnimal connections: - legs organs: @@ -26,7 +26,7 @@ root: torso slots: torso: - part: TorsoAnimal + part: ChestAnimal connections: - legs organs: diff --git a/Resources/Prototypes/_Backmen/Entities/Mobs/NPCs/TGMC_xeno.yml b/Resources/Prototypes/_Backmen/Entities/Mobs/NPCs/TGMC_xeno.yml index 6c15ec35781..8abb40ca12a 100644 --- a/Resources/Prototypes/_Backmen/Entities/Mobs/NPCs/TGMC_xeno.yml +++ b/Resources/Prototypes/_Backmen/Entities/Mobs/NPCs/TGMC_xeno.yml @@ -885,7 +885,7 @@ root: torso slots: torso: - part: TorsoReptilian + part: ChestReptilian connections: - hand 1 hand 1: @@ -897,7 +897,7 @@ root: torso slots: torso: - part: TorsoReptilian + part: ChestReptilian connections: - hand 1 - hand 2 @@ -912,7 +912,7 @@ root: torso slots: torso: - part: TorsoReptilian + part: ChestReptilian connections: - hand 1 - hand 2 @@ -930,7 +930,7 @@ root: torso slots: torso: - part: TorsoReptilian + part: ChestReptilian connections: - hand 1 - hand 2 @@ -951,7 +951,7 @@ root: torso slots: torso: - part: TorsoReptilian + part: ChestReptilian connections: - hand 1 - hand 2 @@ -972,7 +972,7 @@ - type: entity id: XenoArm name: "кость ксено" - parent: PartSilicon + parent: [BaseLeftHand, PartSilicon] components: - type: BodyPart partType: Hand diff --git a/Resources/Prototypes/_Backmen/Entities/Mobs/NPCs/base.yml b/Resources/Prototypes/_Backmen/Entities/Mobs/NPCs/base.yml index 38d9290b018..222e4094be0 100644 --- a/Resources/Prototypes/_Backmen/Entities/Mobs/NPCs/base.yml +++ b/Resources/Prototypes/_Backmen/Entities/Mobs/NPCs/base.yml @@ -129,7 +129,7 @@ root: torso slots: torso: - part: TorsoHuman + part: ChestHuman connections: - right leg - left leg diff --git a/Resources/Prototypes/_Backmen/Entities/Mobs/Species/arachne.yml b/Resources/Prototypes/_Backmen/Entities/Mobs/Species/arachne.yml index 001bcd9d496..6101f6c3286 100644 --- a/Resources/Prototypes/_Backmen/Entities/Mobs/Species/arachne.yml +++ b/Resources/Prototypes/_Backmen/Entities/Mobs/Species/arachne.yml @@ -25,7 +25,11 @@ - map: [ "enum.HumanoidVisualLayers.Chest" ] color: "#e8b59b" sprite: Mobs/Species/Human/parts.rsi - state: torso_m + state: chest_m + - map: [ "enum.HumanoidVisualLayers.Groin" ] + color: "#e8b59b" + sprite: Mobs/Species/Human/parts.rsi + state: groin_m - map: [ "enum.HumanoidVisualLayers.RLeg" ] sprite: Backmen/Mobs/Species/ArachneClassic/arachneClassic.rsi state: spider_body_front @@ -133,13 +137,13 @@ webRequired: true - type: Arachne - type: Cocooner - - type: DamageVisuals - thresholds: [ 10, 20, 30, 50, 70, 100 ] - targetLayers: - - "enum.HumanoidVisualLayers.Chest" - - "enum.HumanoidVisualLayers.Head" - - "enum.HumanoidVisualLayers.LArm" - - "enum.HumanoidVisualLayers.RArm" + #- type: DamageVisuals + # thresholds: [ 10, 20, 30, 50, 70, 100 ] + # targetLayers: + # - "enum.HumanoidVisualLayers.Chest" + # - "enum.HumanoidVisualLayers.Head" + # - "enum.HumanoidVisualLayers.LArm" + # - "enum.HumanoidVisualLayers.RArm" - type: MovedByPressure pressureResistance: 4 - type: Barotrauma @@ -194,7 +198,11 @@ - map: [ "enum.HumanoidVisualLayers.Chest" ] color: "#e8b59b" sprite: Mobs/Species/Human/parts.rsi - state: torso_m + state: chest_m + - map: [ "enum.HumanoidVisualLayers.Groin" ] + color: "#e8b59b" + sprite: Mobs/Species/Human/parts.rsi + state: groin_m - map: [ "enum.HumanoidVisualLayers.RLeg" ] sprite: Backmen/Mobs/Species/ArachneClassic/arachneClassic.rsi state: spider_body_front diff --git a/Resources/Prototypes/_Backmen/Entities/Mobs/Species/felinid.yml b/Resources/Prototypes/_Backmen/Entities/Mobs/Species/felinid.yml index af5e5587e9e..5a3ff6c2813 100644 --- a/Resources/Prototypes/_Backmen/Entities/Mobs/Species/felinid.yml +++ b/Resources/Prototypes/_Backmen/Entities/Mobs/Species/felinid.yml @@ -14,6 +14,9 @@ understands: - TauCetiBasic - Nekomimetic + - type: Consciousness + cap: 85 + threshold: 25 - type: Sprite scale: 0.8, 0.8 - type: HumanoidAppearance diff --git a/Resources/Prototypes/_Backmen/Entities/Mobs/Species/golem.yml b/Resources/Prototypes/_Backmen/Entities/Mobs/Species/golem.yml index 6df6d27d0d3..c3d2f3888c6 100644 --- a/Resources/Prototypes/_Backmen/Entities/Mobs/Species/golem.yml +++ b/Resources/Prototypes/_Backmen/Entities/Mobs/Species/golem.yml @@ -313,7 +313,11 @@ - map: [ "enum.HumanoidVisualLayers.Chest" ] color: "#e8b59b" sprite: Mobs/Species/Diona/parts.rsi - state: torso_m + state: chest_m + - map: [ "enum.HumanoidVisualLayers.Groin" ] + color: "#e8b59b" + sprite: Mobs/Species/Diona/parts.rsi + state: groin_m - map: [ "enum.HumanoidVisualLayers.Head" ] color: "#e8b59b" sprite: Backmen/Mobs/Species/Golem/wood.rsi diff --git a/Resources/Prototypes/_Backmen/Entities/Surgery/bone.yml b/Resources/Prototypes/_Backmen/Entities/Surgery/bone.yml new file mode 100644 index 00000000000..927b03610c9 --- /dev/null +++ b/Resources/Prototypes/_Backmen/Entities/Surgery/bone.yml @@ -0,0 +1,27 @@ +- type: entity + id: Bone + parent: BaseItem + name: bone + description: A real bone. Contains calcium, a lot of calcium. + components: + - type: Bone # backmen: wounding + - type: Sprite + sprite: Objects/Materials/materials.rsi + state: bones + - type: Appearance + - type: Item + sprite: Objects/Materials/materials.rsi + size: Normal + - type: Tag + tags: + - RawMaterial + - type: Damageable + damageContainer: Inorganic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 100 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] diff --git a/Resources/Prototypes/_Backmen/Entities/Surgery/scars.yml b/Resources/Prototypes/_Backmen/Entities/Surgery/scars.yml new file mode 100644 index 00000000000..3444e9970b5 --- /dev/null +++ b/Resources/Prototypes/_Backmen/Entities/Surgery/scars.yml @@ -0,0 +1,55 @@ +- type: entity + id: BluntScar + categories: [ HideSpawnMenu ] + components: + - type: Wound + woundType: External + woundVisibility: Always + canBeHealed: false + isScar: true + - type: PainInflicter + +- type: entity + id: PiercingScar + categories: [ HideSpawnMenu ] + components: + - type: Wound + woundType: External + woundVisibility: Always + canBeHealed: false + isScar: true + - type: PainInflicter + +- type: entity + id: SlashScar + categories: [ HideSpawnMenu ] + components: + - type: Wound + woundType: External + woundVisibility: Always + canBeHealed: false + isScar: true + - type: PainInflicter + +- type: entity + id: BurnScar + categories: [ HideSpawnMenu ] + components: + - type: Wound + woundType: External + woundVisibility: Always + canBeHealed: false + isScar: true + - type: PainInflicter + +- type: entity + id: RadiationScar + categories: [ HideSpawnMenu ] + components: + - type: Wound + woundType: External + woundVisibility: Always + canBeHealed: false + isScar: true + - type: PainInflicter + multiplier: 0.01 # lmao diff --git a/Resources/Prototypes/_Backmen/Entities/Surgery/surgeries.yml b/Resources/Prototypes/_Backmen/Entities/Surgery/surgeries.yml index b9efc875106..0991d7f3c13 100644 --- a/Resources/Prototypes/_Backmen/Entities/Surgery/surgeries.yml +++ b/Resources/Prototypes/_Backmen/Entities/Surgery/surgeries.yml @@ -41,7 +41,7 @@ - SurgeryStepSawBones - SurgeryStepPriseOpenBones - type: SurgeryPartCondition - part: Torso + part: Chest - type: entity parent: SurgeryBase @@ -56,7 +56,7 @@ - SurgeryStepClampInternalBleeders - SurgeryStepRemoveFeature - type: SurgeryPartCondition - part: Torso + part: Chest inverse: true # I fucking hate hardcoding all of this shit to accomodate for surgery BUI. @@ -74,7 +74,7 @@ - SurgeryStepInsertFeature - SurgeryStepSealWounds - type: SurgeryPartCondition - part: Torso + part: Chest - type: SurgeryPartRemovedCondition connection: head part: Head @@ -91,7 +91,7 @@ - SurgeryStepInsertFeature - SurgeryStepSealWounds - type: SurgeryPartCondition - part: Torso + part: Chest - type: SurgeryPartRemovedCondition connection: left arm part: Arm @@ -109,7 +109,7 @@ - SurgeryStepInsertFeature - SurgeryStepSealWounds - type: SurgeryPartCondition - part: Torso + part: Chest - type: SurgeryPartRemovedCondition connection: right arm part: Arm @@ -127,7 +127,7 @@ - SurgeryStepInsertFeature - SurgeryStepSealWounds - type: SurgeryPartCondition - part: Torso + part: Groin - type: SurgeryPartRemovedCondition connection: left leg part: Leg @@ -145,7 +145,7 @@ - SurgeryStepInsertFeature - SurgeryStepSealWounds - type: SurgeryPartCondition - part: Torso + part: Groin - type: SurgeryPartRemovedCondition connection: right leg part: Leg @@ -241,7 +241,7 @@ - SurgeryStepInsertFeature - SurgeryStepSealWounds - type: SurgeryPartCondition - part: Torso + part: Groin - type: SurgeryPartRemovedCondition connection: legs part: Leg @@ -259,7 +259,7 @@ - SurgeryStepInsertFeature - SurgeryStepSealWounds - type: SurgeryPartCondition - part: Torso + part: Chest - type: SurgeryPartRemovedCondition connection: hands part: Hand @@ -277,7 +277,7 @@ - SurgeryStepInsertFeature - SurgeryStepSealWounds - type: SurgeryPartCondition - part: Torso + part: Groin - type: SurgeryPartRemovedCondition connection: feet part: Foot @@ -294,7 +294,7 @@ - SurgeryStepInsertFeature - SurgeryStepSealWounds - type: SurgeryPartCondition - part: Torso + part: Groin - type: SurgeryPartRemovedCondition connection: tail part: Tail @@ -315,7 +315,7 @@ # - SurgeryStepRemoveLarva # - type: SurgeryLarvaCondition # - type: SurgeryPartCondition -# part: Torso +# part: Chest - type: entity parent: SurgeryBase @@ -355,7 +355,7 @@ - SurgeryStepInsertItem - SurgeryStepRemoveItem - type: SurgeryPartCondition - part: Torso + part: Chest # Note for any Organ manipulation surgeries. Most of the organs are only defined on the server. # I added some of them to the client too, but we should probably move them to a shared @@ -412,7 +412,7 @@ - SurgeryStepClampInternalBleeders - SurgeryStepRemoveOrgan - type: SurgeryPartCondition - part: Torso + part: Chest - type: SurgeryOrganCondition organ: - type: Heart @@ -430,7 +430,7 @@ - SurgeryStepInsertHeart - SurgeryStepSealOrganWound - type: SurgeryPartCondition - part: Torso + part: Chest - type: SurgeryOrganCondition organ: - type: Heart @@ -444,13 +444,13 @@ categories: [ HideSpawnMenu ] components: - type: Surgery - requirement: SurgeryOpenRibcage + requirement: SurgeryOpenIncision steps: - - SurgeryStepSawBones + - SurgeryStepCarefulIncisionScalpel - SurgeryStepClampInternalBleeders - SurgeryStepRemoveOrgan - type: SurgeryPartCondition - part: Torso + part: Groin - type: SurgeryOrganCondition organ: - type: Liver @@ -462,13 +462,12 @@ categories: [ HideSpawnMenu ] components: - type: Surgery - requirement: SurgeryOpenRibcage + requirement: SurgeryOpenIncision steps: - - SurgeryStepSawBones - SurgeryStepInsertLiver - SurgeryStepSealOrganWound - type: SurgeryPartCondition - part: Torso + part: Groin - type: SurgeryOrganCondition organ: - type: Liver @@ -488,7 +487,7 @@ - SurgeryStepClampInternalBleeders - SurgeryStepRemoveOrgan - type: SurgeryPartCondition - part: Torso + part: Chest - type: SurgeryOrganCondition organ: - type: Lung @@ -506,7 +505,7 @@ - SurgeryStepInsertLungs - SurgeryStepSealOrganWound - type: SurgeryPartCondition - part: Torso + part: Chest - type: SurgeryOrganCondition organ: - type: Lung @@ -520,13 +519,13 @@ categories: [ HideSpawnMenu ] components: - type: Surgery - requirement: SurgeryOpenRibcage + requirement: SurgeryOpenIncision steps: - - SurgeryStepSawBones + - SurgeryStepCarefulIncisionScalpel - SurgeryStepClampInternalBleeders - SurgeryStepRemoveOrgan - type: SurgeryPartCondition - part: Torso + part: Groin - type: SurgeryOrganCondition organ: - type: Stomach @@ -538,13 +537,12 @@ categories: [ HideSpawnMenu ] components: - type: Surgery - requirement: SurgeryOpenRibcage + requirement: SurgeryOpenIncision steps: - - SurgeryStepSawBones - SurgeryStepInsertStomach - SurgeryStepSealOrganWound - type: SurgeryPartCondition - part: Torso + part: Groin - type: SurgeryOrganCondition organ: - type: Stomach @@ -670,7 +668,7 @@ # steps: # - SurgeryStepAddFelinidTail # - type: SurgeryPartCondition -# part: Torso +# part: Groin # - type: SurgeryMarkingCondition # markingCategory: Tail # matchString: FelinidTail @@ -687,7 +685,7 @@ # steps: # - SurgeryStepRemoveFelinidTail # - type: SurgeryPartCondition -# part: Torso +# part: Groin # - type: SurgeryMarkingCondition # markingCategory: Tail # matchString: FelinidTail diff --git a/Resources/Prototypes/_Backmen/Entities/Surgery/wounds.yml b/Resources/Prototypes/_Backmen/Entities/Surgery/wounds.yml new file mode 100644 index 00000000000..cd6427bcd35 --- /dev/null +++ b/Resources/Prototypes/_Backmen/Entities/Surgery/wounds.yml @@ -0,0 +1,136 @@ +- type: entity + id: Blunt + categories: [ HideSpawnMenu ] + components: + - type: Wound + woundType: External + woundVisibility: Always + scarWound: BluntScar + integrityMultiplier: 0.5 #heheheha + bleedsScaling: 2 + traumasChances: + Dismemberment: -0.2 + OrganDamage: -0.2 + BoneDamage: 0.2 + VeinsDamage: 0 + NerveDamage: 0 + - type: PainInflicter + multiplier: 0.87 + - type: BleedInflicter + +- type: entity + id: Piercing + categories: [ HideSpawnMenu ] + components: + - type: Wound + woundType: External + woundVisibility: Always + scarWound: PiercingScar + integrityMultiplier: 0.3 + bleedsScaling: 0.8 + traumasChances: + Dismemberment: 0.14 + OrganDamage: 0.2 + BoneDamage: 0.2 + VeinsDamage: -0.4 + NerveDamage: -0.4 + - type: PainInflicter + multiplier: 0.87 + - type: BleedInflicter + +- type: entity + id: Slash + categories: [ HideSpawnMenu ] + components: + - type: Wound + woundType: External + woundVisibility: Always + scarWound: SlashScar + integrityMultiplier: 0.3 + bleedsScaling: 0.8 + traumasChances: + Dismemberment: 0.25 + OrganDamage: -0.34 + BoneDamage: -0.34 + VeinsDamage: 0 + NerveDamage: 0 + - type: PainInflicter + multiplier: 0.87 + - type: BleedInflicter + +- type: entity + id: Heat + categories: [ HideSpawnMenu ] + components: + - type: Wound + woundType: External + woundVisibility: Always + scarWound: BurnScar + integrityMultiplier: 0.34 + bleedsScaling: 0.17 + traumasChances: + Dismemberment: -0.5 # fire and lasers can't dismember, damage organs or bones. But they can damage veins and nerves pretty much easily + OrganDamage: -0.5 + BoneDamage: -0.7 + VeinsDamage: 0.27 + NerveDamage: 0.27 + - type: PainInflicter + multiplier: 1.34 + - type: BleedInflicter + +- type: entity + id: Cold + categories: [ HideSpawnMenu ] + components: + - type: Wound + woundType: External + woundVisibility: Always + scarWound: BurnScar + canBleed: false + integrityMultiplier: 0.1 + traumasChances: + Dismemberment: -1 + OrganDamage: -1 + BoneDamage: -1 + VeinsDamage: 0.5 + NerveDamage: 0.5 + - type: PainInflicter + multiplier: 1.5 + +- type: entity + id: Caustic + categories: [ HideSpawnMenu ] + components: + - type: Wound + woundType: External + woundVisibility: AdvancedScanner + scarWound: BurnScar + canBleed: false + integrityMultiplier: 0.01 + traumasChances: + Dismemberment: -1 + OrganDamage: -1 + BoneDamage: -1 + VeinsDamage: 0.5 + NerveDamage: 0.14 + - type: PainInflicter + multiplier: 0.12 # radiation and caustics are a slow killer. You do not notice how you perish. + +- type: entity + id: Radiation + categories: [ HideSpawnMenu ] + components: + - type: Wound + woundType: External + woundVisibility: HandScanner + scarWound: RadiationScar + canBleed: false + integrityMultiplier: 0.01 + traumasChances: + Dismemberment: -1 + OrganDamage: -1 + BoneDamage: -1 + VeinsDamage: 0.5 + NerveDamage: 0.14 + - type: PainInflicter + multiplier: 0.12 diff --git a/Resources/Prototypes/_Backmen/Species/arachne.yml b/Resources/Prototypes/_Backmen/Species/arachne.yml index f0a2fdeda78..d6c1ebd2f43 100644 --- a/Resources/Prototypes/_Backmen/Species/arachne.yml +++ b/Resources/Prototypes/_Backmen/Species/arachne.yml @@ -36,7 +36,7 @@ sprites: Head: MobHumanHead Hair: MobHumanoidAnyMarking - Chest: MobHumanTorso + Chest: MobHumanChest Eyes: MobArachneClassicEyes LArm: MobHumanLArm RArm: MobHumanRArm diff --git a/Resources/Prototypes/_Backmen/Species/foxes.yml b/Resources/Prototypes/_Backmen/Species/foxes.yml index 88cbc896852..458d392fd66 100644 --- a/Resources/Prototypes/_Backmen/Species/foxes.yml +++ b/Resources/Prototypes/_Backmen/Species/foxes.yml @@ -20,7 +20,8 @@ Hair: MobHumanoidAnyMarking FacialHair: MobHumanoidAnyMarking Snout: MobHumanoidAnyMarking - Chest: MobHumanoidFoxTorso + Chest: MobHumanoidFoxChest + Groin: MobHumanoidFoxGroin HeadTop: MobHumanoidAnyMarking HeadSide: MobHumanoidAnyMarking Tail: MobHumanoidAnyMarking @@ -77,22 +78,40 @@ state: head_f - type: humanoidBaseSprite - id: MobHumanoidFoxTorso + id: MobHumanoidFoxChest baseSprite: sprite: Backmen/Mobs/Species/HumanoidFox/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobHumanoidFoxTorsoMale + id: MobHumanoidFoxChestMale baseSprite: sprite: Backmen/Mobs/Species/HumanoidFox/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobHumanoidFoxTorsoFemale + id: MobHumanoidFoxChestFemale baseSprite: sprite: Backmen/Mobs/Species/HumanoidFox/parts.rsi - state: torso_f + state: chest_f + +- type: humanoidBaseSprite + id: MobHumanoidFoxGroin + baseSprite: + sprite: Backmen/Mobs/Species/HumanoidFox/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobHumanoidFoxGroinMale + baseSprite: + sprite: Backmen/Mobs/Species/HumanoidFox/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobHumanoidFoxGroinFemale + baseSprite: + sprite: Backmen/Mobs/Species/HumanoidFox/parts.rsi + state: groin_f - type: humanoidBaseSprite id: MobHumanoidFoxLLeg diff --git a/Resources/Prototypes/_Backmen/Species/kobold.yml b/Resources/Prototypes/_Backmen/Species/kobold.yml index 42542c29164..f25ebb836d7 100644 --- a/Resources/Prototypes/_Backmen/Species/kobold.yml +++ b/Resources/Prototypes/_Backmen/Species/kobold.yml @@ -14,7 +14,8 @@ sprites: Special: MobKoboldAnyMarking Head: MobKoboldHead - Chest: MobKoboldTorso + Chest: MobKoboldChest + Groin: MobKoboldGroin Tail: MobKoboldTail Eyes: MobKoboldEyes HeadTop: MobKoboldHorns @@ -60,22 +61,40 @@ state: head_f - type: humanoidBaseSprite - id: MobKoboldTorso + id: MobKoboldChest baseSprite: sprite: Mobs/Animals/kobold.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobKoboldTorsoMale + id: MobKoboldChestMale baseSprite: sprite: Mobs/Animals/kobold.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobKoboldTorsoFemale + id: MobKoboldChestFemale baseSprite: sprite: Mobs/Animals/kobold.rsi - state: torso_f + state: chest_f + +- type: humanoidBaseSprite + id: MobKoboldGroin + baseSprite: + sprite: Mobs/Animals/kobold.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobKoboldGroinMale + baseSprite: + sprite: Mobs/Animals/kobold.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobKoboldGroinFemale + baseSprite: + sprite: Mobs/Animals/kobold.rsi + state: groin_f - type: humanoidBaseSprite id: MobKoboldLLeg diff --git a/Resources/Prototypes/_Backmen/Species/monkey.yml b/Resources/Prototypes/_Backmen/Species/monkey.yml index 9102ea7acfa..8a0ae19d5a5 100644 --- a/Resources/Prototypes/_Backmen/Species/monkey.yml +++ b/Resources/Prototypes/_Backmen/Species/monkey.yml @@ -14,7 +14,8 @@ sprites: Special: MobMonkeyAnyMarking Head: MobMonkeyHead - Chest: MobMonkeyTorso + Chest: MobMonkeyChest + Groin: MobMonkeyGroin Tail: MobMonkeyTail Eyes: MobMonkeyEyes HeadTop: MobMonkeyAnyMarking @@ -53,22 +54,40 @@ state: head_f - type: humanoidBaseSprite - id: MobMonkeyTorso + id: MobMonkeyChest baseSprite: sprite: Mobs/Animals/monkey.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobMonkeyTorsoMale + id: MobMonkeyChestMale baseSprite: sprite: Mobs/Animals/monkey.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobMonkeyTorsoFemale + id: MobMonkeyChestFemale baseSprite: sprite: Mobs/Animals/monkey.rsi - state: torso_f + state: chest_f + +- type: humanoidBaseSprite + id: MobMonkeyGroin + baseSprite: + sprite: Mobs/Animals/monkey.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobMonkeyGroinMale + baseSprite: + sprite: Mobs/Animals/monkey.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobMonkeyGroinFemale + baseSprite: + sprite: Mobs/Animals/monkey.rsi + state: groin_f - type: humanoidBaseSprite id: MobMonkeyLLeg diff --git a/Resources/Prototypes/_Backmen/Species/shadowkin.yml b/Resources/Prototypes/_Backmen/Species/shadowkin.yml index cccfbe3af2b..038d5e4e8f9 100644 --- a/Resources/Prototypes/_Backmen/Species/shadowkin.yml +++ b/Resources/Prototypes/_Backmen/Species/shadowkin.yml @@ -29,7 +29,8 @@ HeadTop: MobShadowkinAnyMarkingFollowSkin HeadSide: MobShadowkinAnyMarkingFollowSkin Tail: MobShadowkinAnyMarkingFollowSkin - Chest: MobShadowkinTorso + Chest: MobShadowkinChest + Groin: MobShadowkinGroin Eyes: MobShadowkinEyes LArm: MobShadowkinLArm RArm: MobShadowkinRArm @@ -87,22 +88,40 @@ state: head_f - type: humanoidBaseSprite - id: MobShadowkinTorso + id: MobShadowkinChest baseSprite: sprite: Backmen/Mobs/Species/Shadowkin/parts.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobShadowkinTorsoMale + id: MobShadowkinChestMale baseSprite: sprite: Backmen/Mobs/Species/shadowkin.rsi - state: torso_m + state: chest_m - type: humanoidBaseSprite - id: MobShadowkinTorsoFemale + id: MobShadowkinChestFemale baseSprite: sprite: Backmen/Mobs/Species/shadowkin.rsi - state: torso_f + state: chest_f + +- type: humanoidBaseSprite + id: MobShadowkinGroin + baseSprite: + sprite: Backmen/Mobs/Species/Shadowkin/parts.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobShadowkinGroinMale + baseSprite: + sprite: Backmen/Mobs/Species/shadowkin.rsi + state: groin_m + +- type: humanoidBaseSprite + id: MobShadowkinGroinFemale + baseSprite: + sprite: Backmen/Mobs/Species/shadowkin.rsi + state: groin_f - type: humanoidBaseSprite id: MobShadowkinLLeg diff --git a/Resources/ServerInfo/Guidebook/Medical/PartManipulation.xml b/Resources/ServerInfo/Guidebook/Medical/PartManipulation.xml index cd67df0a089..39928d145d1 100644 --- a/Resources/ServerInfo/Guidebook/Medical/PartManipulation.xml +++ b/Resources/ServerInfo/Guidebook/Medical/PartManipulation.xml @@ -12,7 +12,8 @@ Normally a body has 10 main parts. Those being: - + + diff --git a/Resources/Textures/Backmen/LobbyScreens/Gachi.rsi/meta.json b/Resources/Textures/Backmen/LobbyScreens/Gachi.rsi/meta.json index 8b7d4ccb6ec..e8257ba36cc 100644 --- a/Resources/Textures/Backmen/LobbyScreens/Gachi.rsi/meta.json +++ b/Resources/Textures/Backmen/LobbyScreens/Gachi.rsi/meta.json @@ -54,8 +54,6 @@ 0.06, 0.06, 0.06 - - ] ] } diff --git a/Resources/Textures/Backmen/Mobs/Species/Golem/cult.rsi/cultgolem_chest.png b/Resources/Textures/Backmen/Mobs/Species/Golem/cult.rsi/cultgolem_chest.png index 5161ea9b576..6292b6f2cb2 100644 Binary files a/Resources/Textures/Backmen/Mobs/Species/Golem/cult.rsi/cultgolem_chest.png and b/Resources/Textures/Backmen/Mobs/Species/Golem/cult.rsi/cultgolem_chest.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Golem/cult.rsi/cultgolem_groin.png b/Resources/Textures/Backmen/Mobs/Species/Golem/cult.rsi/cultgolem_groin.png new file mode 100644 index 00000000000..3010fbecd09 Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/Golem/cult.rsi/cultgolem_groin.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Golem/cult.rsi/meta.json b/Resources/Textures/Backmen/Mobs/Species/Golem/cult.rsi/meta.json index 0d706f8146d..a4b3ef3cd30 100644 --- a/Resources/Textures/Backmen/Mobs/Species/Golem/cult.rsi/meta.json +++ b/Resources/Textures/Backmen/Mobs/Species/Golem/cult.rsi/meta.json @@ -15,6 +15,10 @@ "name": "cultgolem_chest", "directions": 4 }, + { + "name": "cultgolem_groin", + "directions": 4 + }, { "name": "cultgolem_r_arm", "directions": 4 diff --git a/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/chest_f.png b/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/chest_f.png new file mode 100644 index 00000000000..b79a6a1e2e6 Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/chest_m.png b/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/chest_m.png new file mode 100644 index 00000000000..637fa49baf5 Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/groin_f.png b/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/groin_f.png new file mode 100644 index 00000000000..f908208e71b Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/groin_f.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/groin_m.png b/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/groin_m.png new file mode 100644 index 00000000000..23452d875ba Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/groin_m.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/meta.json b/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/meta.json index 4073a762e89..c27509eef4f 100644 --- a/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/meta.json +++ b/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/meta.json @@ -51,11 +51,19 @@ "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", + "directions": 4 + }, + { + "name": "groin_f", + "directions": 4 + }, + { + "name": "groin_m", "directions": 4 } ] diff --git a/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/torso_f.png b/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/torso_f.png deleted file mode 100644 index 23dde35cd8e..00000000000 Binary files a/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/torso_m.png b/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/torso_m.png deleted file mode 100644 index 9a30fbfb574..00000000000 Binary files a/Resources/Textures/Backmen/Mobs/Species/Harpy/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/chest_f.png b/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/chest_f.png new file mode 100644 index 00000000000..5e7440ef078 Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/chest_m.png b/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/chest_m.png new file mode 100644 index 00000000000..034d304e71e Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/meta.json b/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/meta.json index fca9fdd423d..c0a0ffae748 100644 --- a/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/meta.json +++ b/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/meta.json @@ -260,7 +260,7 @@ ] }, { - "name": "torso_f", + "name": "chest_f", "directions": 4, "delays": [ [ @@ -278,43 +278,7 @@ ] }, { - "name": "torso_f_fat", - "directions": 4, - "delays": [ - [ - 1.0 - ], - [ - 1.0 - ], - [ - 1.0 - ], - [ - 1.0 - ] - ] - }, - { - "name": "torso_m", - "directions": 4, - "delays": [ - [ - 1.0 - ], - [ - 1.0 - ], - [ - 1.0 - ], - [ - 1.0 - ] - ] - }, - { - "name": "torso_m_fat", + "name": "chest_m", "directions": 4, "delays": [ [ diff --git a/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/torso_f.png b/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/torso_f.png deleted file mode 100644 index ddd66ce7050..00000000000 Binary files a/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/torso_f_fat.png b/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/torso_f_fat.png deleted file mode 100644 index ddd66ce7050..00000000000 Binary files a/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/torso_f_fat.png and /dev/null differ diff --git a/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/torso_m.png b/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/torso_m.png deleted file mode 100644 index 8bce721a619..00000000000 Binary files a/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/torso_m_fat.png b/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/torso_m_fat.png deleted file mode 100644 index 8bce721a619..00000000000 Binary files a/Resources/Textures/Backmen/Mobs/Species/HumanoidFox/parts.rsi/torso_m_fat.png and /dev/null differ diff --git a/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/chest_f.png b/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/chest_f.png new file mode 100644 index 00000000000..a1bf60db50c Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/chest_m.png b/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/chest_m.png new file mode 100644 index 00000000000..a2d516e9e22 Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/groin_f.png b/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/groin_f.png new file mode 100644 index 00000000000..c99708e4011 Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/groin_f.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/groin_m.png b/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/groin_m.png new file mode 100644 index 00000000000..3bf02449727 Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/groin_m.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/meta.json b/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/meta.json index 1463c57a060..998c96becd3 100644 --- a/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/meta.json +++ b/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/meta.json @@ -19,11 +19,19 @@ "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", + "directions": 4 + }, + { + "name": "groin_m", + "directions": 4 + }, + { + "name": "groin_f", "directions": 4 }, { diff --git a/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/torso_f.png b/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/torso_f.png deleted file mode 100644 index b36a2eed8c7..00000000000 Binary files a/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/torso_m.png b/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/torso_m.png deleted file mode 100644 index df2588b562d..00000000000 Binary files a/Resources/Textures/Backmen/Mobs/Species/IPC/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/chest_f.png b/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/chest_f.png new file mode 100644 index 00000000000..4dedeed81c9 Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/chest_m.png b/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/chest_m.png new file mode 100644 index 00000000000..f907d506563 Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/groin_f.png b/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/groin_f.png new file mode 100644 index 00000000000..9f2aed5d923 Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/groin_f.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/groin_m.png b/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/groin_m.png new file mode 100644 index 00000000000..50566a8e64e Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/groin_m.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/meta.json b/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/meta.json index 1960c64d391..d850312bf1b 100644 --- a/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/meta.json +++ b/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/meta.json @@ -54,11 +54,19 @@ "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", + "directions": 4 + }, + { + "name": "groin_f", + "directions": 4 + }, + { + "name": "groin_m", "directions": 4 } ] diff --git a/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/torso_f.png b/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/torso_f.png deleted file mode 100644 index c7a1d1223a4..00000000000 Binary files a/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/torso_m.png b/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/torso_m.png deleted file mode 100644 index 93680ef40f6..00000000000 Binary files a/Resources/Textures/Backmen/Mobs/Species/Moth/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/chest_f.png b/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/chest_f.png new file mode 100644 index 00000000000..a8b4b129c8f Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/chest_m.png b/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/chest_m.png new file mode 100644 index 00000000000..1253b25a7e1 Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/groin_f.png b/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/groin_f.png new file mode 100644 index 00000000000..6d0d204eeca Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/groin_f.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/groin_m.png b/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/groin_m.png new file mode 100644 index 00000000000..9a13f547d17 Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/groin_m.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/meta.json b/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/meta.json index a259ab696b8..7d57ee95b12 100644 --- a/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/meta.json +++ b/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/meta.json @@ -24,11 +24,19 @@ "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", + "directions": 4 + }, + { + "name": "groin_m", + "directions": 4 + }, + { + "name": "groin_f", "directions": 4 }, { diff --git a/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/torso_f.png b/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/torso_f.png deleted file mode 100644 index 83cc63cdd29..00000000000 Binary files a/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/torso_m.png b/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/torso_m.png deleted file mode 100644 index dafc83b65eb..00000000000 Binary files a/Resources/Textures/Backmen/Mobs/Species/Shadowkin/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/chest_f.png b/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/chest_f.png new file mode 100644 index 00000000000..a8b4b129c8f Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/chest_f.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/chest_m.png b/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/chest_m.png new file mode 100644 index 00000000000..1253b25a7e1 Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/chest_m.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/groin_f.png b/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/groin_f.png new file mode 100644 index 00000000000..6d0d204eeca Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/groin_f.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/groin_m.png b/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/groin_m.png new file mode 100644 index 00000000000..9a13f547d17 Binary files /dev/null and b/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/groin_m.png differ diff --git a/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/meta.json b/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/meta.json index 11752d51403..2f9436027e8 100644 --- a/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/meta.json +++ b/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/meta.json @@ -20,11 +20,19 @@ "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", + "directions": 4 + }, + { + "name": "groin_m", + "directions": 4 + }, + { + "name": "groin_f", "directions": 4 }, { diff --git a/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/torso_f.png b/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/torso_f.png deleted file mode 100644 index 83cc63cdd29..00000000000 Binary files a/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/torso_m.png b/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/torso_m.png deleted file mode 100644 index dafc83b65eb..00000000000 Binary files a/Resources/Textures/Backmen/Mobs/Species/shadowkin.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/chest_f.png b/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/chest_f.png new file mode 100644 index 00000000000..edfb938fa20 Binary files /dev/null and b/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/chest_m.png b/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/chest_m.png new file mode 100644 index 00000000000..7c74062b1e6 Binary files /dev/null and b/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/groin_f.png b/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/groin_f.png new file mode 100644 index 00000000000..0b8092491ac Binary files /dev/null and b/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/groin_f.png differ diff --git a/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/groin_m.png b/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/groin_m.png new file mode 100644 index 00000000000..533a25f2139 Binary files /dev/null and b/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/groin_m.png differ diff --git a/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/meta.json b/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/meta.json index 56d43aa0f9d..0b4cff7d74b 100644 --- a/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/meta.json +++ b/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/meta.json @@ -51,11 +51,19 @@ "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", + "directions": 4 + }, + { + "name": "groin_f", + "directions": 4 + }, + { + "name": "groin_m", "directions": 4 } ] diff --git a/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/torso_f.png b/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/torso_f.png deleted file mode 100644 index 253eeb4e8f8..00000000000 Binary files a/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/torso_m.png b/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/torso_m.png deleted file mode 100644 index 64c2f7be2da..00000000000 Binary files a/Resources/Textures/Corvax/Mobs/Species/Vulpkanin/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_0.png b/Resources/Textures/Interface/Targeting/Status/chest.rsi/chest_0.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_0.png rename to Resources/Textures/Interface/Targeting/Status/chest.rsi/chest_0.png diff --git a/Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_1.png b/Resources/Textures/Interface/Targeting/Status/chest.rsi/chest_1.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_1.png rename to Resources/Textures/Interface/Targeting/Status/chest.rsi/chest_1.png diff --git a/Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_2.png b/Resources/Textures/Interface/Targeting/Status/chest.rsi/chest_2.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_2.png rename to Resources/Textures/Interface/Targeting/Status/chest.rsi/chest_2.png diff --git a/Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_3.png b/Resources/Textures/Interface/Targeting/Status/chest.rsi/chest_3.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_3.png rename to Resources/Textures/Interface/Targeting/Status/chest.rsi/chest_3.png diff --git a/Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_4.png b/Resources/Textures/Interface/Targeting/Status/chest.rsi/chest_4.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_4.png rename to Resources/Textures/Interface/Targeting/Status/chest.rsi/chest_4.png diff --git a/Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_8.png b/Resources/Textures/Interface/Targeting/Status/chest.rsi/chest_5.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_8.png rename to Resources/Textures/Interface/Targeting/Status/chest.rsi/chest_5.png diff --git a/Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_6.png b/Resources/Textures/Interface/Targeting/Status/chest.rsi/chest_6unused.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_6.png rename to Resources/Textures/Interface/Targeting/Status/chest.rsi/chest_6unused.png diff --git a/Resources/Textures/Interface/Targeting/Status/torso.rsi/meta.json b/Resources/Textures/Interface/Targeting/Status/chest.rsi/meta.json similarity index 61% rename from Resources/Textures/Interface/Targeting/Status/torso.rsi/meta.json rename to Resources/Textures/Interface/Targeting/Status/chest.rsi/meta.json index 7baeebd0801..ee281eb8324 100644 --- a/Resources/Textures/Interface/Targeting/Status/torso.rsi/meta.json +++ b/Resources/Textures/Interface/Targeting/Status/chest.rsi/meta.json @@ -8,31 +8,25 @@ }, "states": [ { - "name": "torso_0" + "name": "chest_0" }, { - "name": "torso_1" + "name": "chest_1" }, { - "name": "torso_2" + "name": "chest_2" }, { - "name": "torso_3" + "name": "chest_3" }, { - "name": "torso_4" + "name": "chest_4" }, { - "name": "torso_5" + "name": "chest_5" }, { - "name": "torso_6" - }, - { - "name": "torso_7" - }, - { - "name": "torso_8" + "name": "chest_6unused" } ] } \ No newline at end of file diff --git a/Resources/Textures/Interface/Targeting/Status/groin.rsi/groin_5.png b/Resources/Textures/Interface/Targeting/Status/groin.rsi/groin_5.png index 3f260e12259..c23961f396b 100644 Binary files a/Resources/Textures/Interface/Targeting/Status/groin.rsi/groin_5.png and b/Resources/Textures/Interface/Targeting/Status/groin.rsi/groin_5.png differ diff --git a/Resources/Textures/Interface/Targeting/Status/groin.rsi/groin_6.png b/Resources/Textures/Interface/Targeting/Status/groin.rsi/groin_6unused.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/groin.rsi/groin_6.png rename to Resources/Textures/Interface/Targeting/Status/groin.rsi/groin_6unused.png diff --git a/Resources/Textures/Interface/Targeting/Status/groin.rsi/groin_7.png b/Resources/Textures/Interface/Targeting/Status/groin.rsi/groin_7.png deleted file mode 100644 index 0bb632ba388..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/groin.rsi/groin_7.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/groin.rsi/groin_8.png b/Resources/Textures/Interface/Targeting/Status/groin.rsi/groin_8.png deleted file mode 100644 index c23961f396b..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/groin.rsi/groin_8.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/groin.rsi/meta.json b/Resources/Textures/Interface/Targeting/Status/groin.rsi/meta.json index 6acd4a2c24b..0e0a37c2800 100644 --- a/Resources/Textures/Interface/Targeting/Status/groin.rsi/meta.json +++ b/Resources/Textures/Interface/Targeting/Status/groin.rsi/meta.json @@ -26,13 +26,7 @@ "name": "groin_5" }, { - "name": "groin_6" - }, - { - "name": "groin_7" - }, - { - "name": "groin_8" + "name": "groin_6unused" } ] } \ No newline at end of file diff --git a/Resources/Textures/Interface/Targeting/Status/head.rsi/head_5.png b/Resources/Textures/Interface/Targeting/Status/head.rsi/head_5.png index f6caf62d405..4d024c61f7f 100644 Binary files a/Resources/Textures/Interface/Targeting/Status/head.rsi/head_5.png and b/Resources/Textures/Interface/Targeting/Status/head.rsi/head_5.png differ diff --git a/Resources/Textures/Interface/Targeting/Status/head.rsi/head_6.png b/Resources/Textures/Interface/Targeting/Status/head.rsi/head_6unused.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/head.rsi/head_6.png rename to Resources/Textures/Interface/Targeting/Status/head.rsi/head_6unused.png diff --git a/Resources/Textures/Interface/Targeting/Status/head.rsi/head_7.png b/Resources/Textures/Interface/Targeting/Status/head.rsi/head_7.png deleted file mode 100644 index 74b58c642bb..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/head.rsi/head_7.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/head.rsi/head_8.png b/Resources/Textures/Interface/Targeting/Status/head.rsi/head_8.png deleted file mode 100644 index 4d024c61f7f..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/head.rsi/head_8.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/head.rsi/meta.json b/Resources/Textures/Interface/Targeting/Status/head.rsi/meta.json index 2c34f86c28e..d0faf3a6eb2 100644 --- a/Resources/Textures/Interface/Targeting/Status/head.rsi/meta.json +++ b/Resources/Textures/Interface/Targeting/Status/head.rsi/meta.json @@ -26,13 +26,7 @@ "name": "head_5" }, { - "name": "head_6" - }, - { - "name": "head_7" - }, - { - "name": "head_8" + "name": "head_6unused" } ] } \ No newline at end of file diff --git a/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/leftarm_5.png b/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/leftarm_5.png index 930a7b52ed1..a00a6b1822e 100644 Binary files a/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/leftarm_5.png and b/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/leftarm_5.png differ diff --git a/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/leftarm_6.png b/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/leftarm_6unused.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/leftarm.rsi/leftarm_6.png rename to Resources/Textures/Interface/Targeting/Status/leftarm.rsi/leftarm_6unused.png diff --git a/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/leftarm_7.png b/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/leftarm_7.png deleted file mode 100644 index efc7380c270..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/leftarm_7.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/leftarm_8.png b/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/leftarm_8.png deleted file mode 100644 index a00a6b1822e..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/leftarm_8.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/meta.json b/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/meta.json index dab3ed611da..0f7d2eab80c 100644 --- a/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/meta.json +++ b/Resources/Textures/Interface/Targeting/Status/leftarm.rsi/meta.json @@ -26,13 +26,7 @@ "name": "leftarm_5" }, { - "name": "leftarm_6" - }, - { - "name": "leftarm_7" - }, - { - "name": "leftarm_8" + "name": "leftarm_6unused" } ] } \ No newline at end of file diff --git a/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/leftfoot_5.png b/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/leftfoot_5.png index b4af7c1c036..bdaec2557cb 100644 Binary files a/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/leftfoot_5.png and b/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/leftfoot_5.png differ diff --git a/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/leftfoot_6.png b/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/leftfoot_6unused.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/leftfoot_6.png rename to Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/leftfoot_6unused.png diff --git a/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/leftfoot_7.png b/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/leftfoot_7.png deleted file mode 100644 index 9822dfba4cb..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/leftfoot_7.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/leftfoot_8.png b/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/leftfoot_8.png deleted file mode 100644 index bdaec2557cb..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/leftfoot_8.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/meta.json b/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/meta.json index 9396f537f80..d2798f9fad7 100644 --- a/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/meta.json +++ b/Resources/Textures/Interface/Targeting/Status/leftfoot.rsi/meta.json @@ -26,13 +26,7 @@ "name": "leftfoot_5" }, { - "name": "leftfoot_6" - }, - { - "name": "leftfoot_7" - }, - { - "name": "leftfoot_8" + "name": "leftfoot_6unused" } ] } \ No newline at end of file diff --git a/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/lefthand_5.png b/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/lefthand_5.png index 06946c97c74..2b33680d438 100644 Binary files a/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/lefthand_5.png and b/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/lefthand_5.png differ diff --git a/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/lefthand_6.png b/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/lefthand_6unused.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/lefthand.rsi/lefthand_6.png rename to Resources/Textures/Interface/Targeting/Status/lefthand.rsi/lefthand_6unused.png diff --git a/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/lefthand_7.png b/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/lefthand_7.png deleted file mode 100644 index 7d2ed496616..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/lefthand_7.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/lefthand_8.png b/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/lefthand_8.png deleted file mode 100644 index 2b33680d438..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/lefthand_8.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/meta.json b/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/meta.json index f7d5a595258..16d7c19ba3a 100644 --- a/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/meta.json +++ b/Resources/Textures/Interface/Targeting/Status/lefthand.rsi/meta.json @@ -26,13 +26,7 @@ "name": "lefthand_5" }, { - "name": "lefthand_6" - }, - { - "name": "lefthand_7" - }, - { - "name": "lefthand_8" + "name": "lefthand_6unused" } ] } \ No newline at end of file diff --git a/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/leftleg_5.png b/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/leftleg_5.png index 4e302cda649..75bd581d69b 100644 Binary files a/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/leftleg_5.png and b/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/leftleg_5.png differ diff --git a/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/leftleg_6.png b/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/leftleg_6unused.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/leftleg.rsi/leftleg_6.png rename to Resources/Textures/Interface/Targeting/Status/leftleg.rsi/leftleg_6unused.png diff --git a/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/leftleg_7.png b/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/leftleg_7.png deleted file mode 100644 index d36a43c441d..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/leftleg_7.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/leftleg_8.png b/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/leftleg_8.png deleted file mode 100644 index 75bd581d69b..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/leftleg_8.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/meta.json b/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/meta.json index 887c60f37cc..8be9e16780f 100644 --- a/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/meta.json +++ b/Resources/Textures/Interface/Targeting/Status/leftleg.rsi/meta.json @@ -26,13 +26,7 @@ "name": "leftleg_5" }, { - "name": "leftleg_6" - }, - { - "name": "leftleg_7" - }, - { - "name": "leftleg_8" + "name": "leftleg_6unused" } ] } \ No newline at end of file diff --git a/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/meta.json b/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/meta.json index eb19b5d4c47..0ffbf483e34 100644 --- a/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/meta.json +++ b/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/meta.json @@ -26,13 +26,7 @@ "name": "rightarm_5" }, { - "name": "rightarm_6" - }, - { - "name": "rightarm_7" - }, - { - "name": "rightarm_8" + "name": "rightarm_6unused" } ] } \ No newline at end of file diff --git a/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/rightarm_5.png b/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/rightarm_5.png index 1eb5f0eadd4..9f894b1bfb3 100644 Binary files a/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/rightarm_5.png and b/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/rightarm_5.png differ diff --git a/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/rightarm_6.png b/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/rightarm_6unused.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/rightarm.rsi/rightarm_6.png rename to Resources/Textures/Interface/Targeting/Status/rightarm.rsi/rightarm_6unused.png diff --git a/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/rightarm_7.png b/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/rightarm_7.png deleted file mode 100644 index 35eec2905a5..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/rightarm_7.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/rightarm_8.png b/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/rightarm_8.png deleted file mode 100644 index 9f894b1bfb3..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/rightarm.rsi/rightarm_8.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/meta.json b/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/meta.json index ce1b1f37e7b..5a233875fb4 100644 --- a/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/meta.json +++ b/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/meta.json @@ -26,13 +26,7 @@ "name": "rightfoot_5" }, { - "name": "rightfoot_6" - }, - { - "name": "rightfoot_7" - }, - { - "name": "rightfoot_8" + "name": "rightfoot_6unused" } ] } \ No newline at end of file diff --git a/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/rightfoot_5.png b/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/rightfoot_5.png index c824c98dfc2..06ab1d2519d 100644 Binary files a/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/rightfoot_5.png and b/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/rightfoot_5.png differ diff --git a/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/rightfoot_6.png b/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/rightfoot_6unused.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/rightfoot_6.png rename to Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/rightfoot_6unused.png diff --git a/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/rightfoot_7.png b/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/rightfoot_7.png deleted file mode 100644 index ebc654d70e9..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/rightfoot_7.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/rightfoot_8.png b/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/rightfoot_8.png deleted file mode 100644 index 06ab1d2519d..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/rightfoot.rsi/rightfoot_8.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/righthand.rsi/meta.json b/Resources/Textures/Interface/Targeting/Status/righthand.rsi/meta.json index 61c5b77862c..b6df331f7e4 100644 --- a/Resources/Textures/Interface/Targeting/Status/righthand.rsi/meta.json +++ b/Resources/Textures/Interface/Targeting/Status/righthand.rsi/meta.json @@ -26,13 +26,7 @@ "name": "righthand_5" }, { - "name": "righthand_6" - }, - { - "name": "righthand_7" - }, - { - "name": "righthand_8" + "name": "righthand_6unused" } ] } \ No newline at end of file diff --git a/Resources/Textures/Interface/Targeting/Status/righthand.rsi/righthand_5.png b/Resources/Textures/Interface/Targeting/Status/righthand.rsi/righthand_5.png index 5062dafc206..797e0683e8b 100644 Binary files a/Resources/Textures/Interface/Targeting/Status/righthand.rsi/righthand_5.png and b/Resources/Textures/Interface/Targeting/Status/righthand.rsi/righthand_5.png differ diff --git a/Resources/Textures/Interface/Targeting/Status/righthand.rsi/righthand_6.png b/Resources/Textures/Interface/Targeting/Status/righthand.rsi/righthand_6unused.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/righthand.rsi/righthand_6.png rename to Resources/Textures/Interface/Targeting/Status/righthand.rsi/righthand_6unused.png diff --git a/Resources/Textures/Interface/Targeting/Status/righthand.rsi/righthand_7.png b/Resources/Textures/Interface/Targeting/Status/righthand.rsi/righthand_7.png deleted file mode 100644 index 87e8f18ef82..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/righthand.rsi/righthand_7.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/righthand.rsi/righthand_8.png b/Resources/Textures/Interface/Targeting/Status/righthand.rsi/righthand_8.png deleted file mode 100644 index 797e0683e8b..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/righthand.rsi/righthand_8.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/meta.json b/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/meta.json index 7dded85e45f..ab2daaa76e1 100644 --- a/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/meta.json +++ b/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/meta.json @@ -26,13 +26,7 @@ "name": "rightleg_5" }, { - "name": "rightleg_6" - }, - { - "name": "rightleg_7" - }, - { - "name": "rightleg_8" + "name": "rightleg_6unused" } ] } \ No newline at end of file diff --git a/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/rightleg_5.png b/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/rightleg_5.png index d30e124e64d..70ccb309add 100644 Binary files a/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/rightleg_5.png and b/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/rightleg_5.png differ diff --git a/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/rightleg_6.png b/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/rightleg_6unused.png similarity index 100% rename from Resources/Textures/Interface/Targeting/Status/rightleg.rsi/rightleg_6.png rename to Resources/Textures/Interface/Targeting/Status/rightleg.rsi/rightleg_6unused.png diff --git a/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/rightleg_7.png b/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/rightleg_7.png deleted file mode 100644 index 9c4ee1f9038..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/rightleg_7.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/rightleg_8.png b/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/rightleg_8.png deleted file mode 100644 index 70ccb309add..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/rightleg.rsi/rightleg_8.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_5.png b/Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_5.png deleted file mode 100644 index 8f3a6ad7d0e..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_5.png and /dev/null differ diff --git a/Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_7.png b/Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_7.png deleted file mode 100644 index c289a454bdb..00000000000 Binary files a/Resources/Textures/Interface/Targeting/Status/torso.rsi/torso_7.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Animals/kobold.rsi/chest_f.png b/Resources/Textures/Mobs/Animals/kobold.rsi/chest_f.png new file mode 100644 index 00000000000..dfaed2f2695 Binary files /dev/null and b/Resources/Textures/Mobs/Animals/kobold.rsi/chest_f.png differ diff --git a/Resources/Textures/Mobs/Animals/kobold.rsi/chest_m.png b/Resources/Textures/Mobs/Animals/kobold.rsi/chest_m.png new file mode 100644 index 00000000000..cc50c6c8b7b Binary files /dev/null and b/Resources/Textures/Mobs/Animals/kobold.rsi/chest_m.png differ diff --git a/Resources/Textures/Mobs/Animals/kobold.rsi/groin_f.png b/Resources/Textures/Mobs/Animals/kobold.rsi/groin_f.png new file mode 100644 index 00000000000..184b477b6db Binary files /dev/null and b/Resources/Textures/Mobs/Animals/kobold.rsi/groin_f.png differ diff --git a/Resources/Textures/Mobs/Animals/kobold.rsi/groin_m.png b/Resources/Textures/Mobs/Animals/kobold.rsi/groin_m.png new file mode 100644 index 00000000000..4f193485975 Binary files /dev/null and b/Resources/Textures/Mobs/Animals/kobold.rsi/groin_m.png differ diff --git a/Resources/Textures/Mobs/Animals/kobold.rsi/meta.json b/Resources/Textures/Mobs/Animals/kobold.rsi/meta.json index 769f96a914e..027cc20dc52 100644 --- a/Resources/Textures/Mobs/Animals/kobold.rsi/meta.json +++ b/Resources/Textures/Mobs/Animals/kobold.rsi/meta.json @@ -55,11 +55,19 @@ "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", + "directions": 4 + }, + { + "name": "groin_f", + "directions": 4 + }, + { + "name": "groin_m", "directions": 4 }, { diff --git a/Resources/Textures/Mobs/Animals/kobold.rsi/torso_f.png b/Resources/Textures/Mobs/Animals/kobold.rsi/torso_f.png deleted file mode 100644 index 192d2b9849e..00000000000 Binary files a/Resources/Textures/Mobs/Animals/kobold.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Animals/kobold.rsi/torso_m.png b/Resources/Textures/Mobs/Animals/kobold.rsi/torso_m.png deleted file mode 100644 index 192d2b9849e..00000000000 Binary files a/Resources/Textures/Mobs/Animals/kobold.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Animals/monkey.rsi/chest_f.png b/Resources/Textures/Mobs/Animals/monkey.rsi/chest_f.png new file mode 100644 index 00000000000..83f516c953b Binary files /dev/null and b/Resources/Textures/Mobs/Animals/monkey.rsi/chest_f.png differ diff --git a/Resources/Textures/Mobs/Animals/monkey.rsi/chest_m.png b/Resources/Textures/Mobs/Animals/monkey.rsi/chest_m.png new file mode 100644 index 00000000000..66562f4f624 Binary files /dev/null and b/Resources/Textures/Mobs/Animals/monkey.rsi/chest_m.png differ diff --git a/Resources/Textures/Mobs/Animals/monkey.rsi/groin_f.png b/Resources/Textures/Mobs/Animals/monkey.rsi/groin_f.png new file mode 100644 index 00000000000..9d8ba2b5f36 Binary files /dev/null and b/Resources/Textures/Mobs/Animals/monkey.rsi/groin_f.png differ diff --git a/Resources/Textures/Mobs/Animals/monkey.rsi/groin_m.png b/Resources/Textures/Mobs/Animals/monkey.rsi/groin_m.png new file mode 100644 index 00000000000..b4d326bce76 Binary files /dev/null and b/Resources/Textures/Mobs/Animals/monkey.rsi/groin_m.png differ diff --git a/Resources/Textures/Mobs/Animals/monkey.rsi/meta.json b/Resources/Textures/Mobs/Animals/monkey.rsi/meta.json index d22ab1556c9..465a77bcb58 100644 --- a/Resources/Textures/Mobs/Animals/monkey.rsi/meta.json +++ b/Resources/Textures/Mobs/Animals/monkey.rsi/meta.json @@ -55,11 +55,19 @@ "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", + "directions": 4 + }, + { + "name": "groin_f", + "directions": 4 + }, + { + "name": "groin_m", "directions": 4 }, { diff --git a/Resources/Textures/Mobs/Animals/monkey.rsi/torso_f.png b/Resources/Textures/Mobs/Animals/monkey.rsi/torso_f.png deleted file mode 100644 index aa3c5ce5487..00000000000 Binary files a/Resources/Textures/Mobs/Animals/monkey.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Animals/monkey.rsi/torso_m.png b/Resources/Textures/Mobs/Animals/monkey.rsi/torso_m.png deleted file mode 100644 index aa3c5ce5487..00000000000 Binary files a/Resources/Textures/Mobs/Animals/monkey.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Chest_Minor.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Chest_Minor.png new file mode 100644 index 00000000000..d786f09a3c4 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Chest_Minor.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Chest_Minor_alt.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Chest_Minor_alt.png new file mode 100644 index 00000000000..a2918b21fce Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Chest_Minor_alt.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Chest_Severe.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Chest_Severe.png new file mode 100644 index 00000000000..b4410cd935d Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Chest_Severe.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Chest_Severe_alt.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Chest_Severe_alt.png new file mode 100644 index 00000000000..c6c5f32844a Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Chest_Severe_alt.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Groin_Minor.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Groin_Minor.png new file mode 100644 index 00000000000..56867c278a2 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Groin_Minor.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Groin_Minor_alt.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Groin_Minor_alt.png new file mode 100644 index 00000000000..b6ccde59728 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Groin_Minor_alt.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Groin_Severe.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Groin_Severe.png new file mode 100644 index 00000000000..e9a698eb828 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Groin_Severe.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Groin_Severe_alt.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Groin_Severe_alt.png new file mode 100644 index 00000000000..640d71f7070 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Groin_Severe_alt.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Head_Minor.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Head_Minor.png new file mode 100644 index 00000000000..f3690f34098 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Head_Minor.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Head_Minor_alt.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Head_Minor_alt.png new file mode 100644 index 00000000000..1d04b1ef5ce Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Head_Minor_alt.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Head_Severe.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Head_Severe.png new file mode 100644 index 00000000000..e3a7d6e46ac Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Head_Severe.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Head_Severe_alt.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Head_Severe_alt.png new file mode 100644 index 00000000000..5b57ced5750 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/Head_Severe_alt.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LArm_Minor.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LArm_Minor.png new file mode 100644 index 00000000000..cdedddff6d8 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LArm_Minor.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LArm_Minor_alt.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LArm_Minor_alt.png new file mode 100644 index 00000000000..6067feb516f Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LArm_Minor_alt.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LArm_Severe.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LArm_Severe.png new file mode 100644 index 00000000000..d12aecc619e Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LArm_Severe.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LArm_Severe_alt.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LArm_Severe_alt.png new file mode 100644 index 00000000000..532c269aea8 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LArm_Severe_alt.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LLeg_Minor.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LLeg_Minor.png new file mode 100644 index 00000000000..8dbfc162feb Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LLeg_Minor.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LLeg_Minor_alt.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LLeg_Minor_alt.png new file mode 100644 index 00000000000..7bda656abed Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LLeg_Minor_alt.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LLeg_Severe.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LLeg_Severe.png new file mode 100644 index 00000000000..cb7c7476c98 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/LLeg_Severe.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RArm_Minor.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RArm_Minor.png new file mode 100644 index 00000000000..1d31800a21d Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RArm_Minor.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RArm_Minor_alt.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RArm_Minor_alt.png new file mode 100644 index 00000000000..7820331aceb Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RArm_Minor_alt.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RArm_Severe.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RArm_Severe.png new file mode 100644 index 00000000000..93b0fae7c8c Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RArm_Severe.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RArm_Severe_alt.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RArm_Severe_alt.png new file mode 100644 index 00000000000..e7221db0d94 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RArm_Severe_alt.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RLeg_Minor.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RLeg_Minor.png new file mode 100644 index 00000000000..68537a25683 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RLeg_Minor.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RLeg_Minor_alt.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RLeg_Minor_alt.png new file mode 100644 index 00000000000..fa9b838a397 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RLeg_Minor_alt.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RLeg_Severe.png b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RLeg_Severe.png new file mode 100644 index 00000000000..9398bf7f2fd Binary files /dev/null and b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/RLeg_Severe.png differ diff --git a/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/meta.json b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/meta.json new file mode 100644 index 00000000000..499afbf64ce --- /dev/null +++ b/Resources/Textures/Mobs/Effects/bleeding_damage.rsi/meta.json @@ -0,0 +1,931 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "i forgo pls fill sm1", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "Head_Severe", + "directions": 4 + }, + { + "name": "Head_Minor", + "directions": 4, + "delays": [ + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ] + ] + }, + { + "name": "Head_Severe_alt", + "directions": 4 + }, + { + "name": "Head_Minor_alt", + "directions": 4, + "delays": [ + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ] + ] + }, + { + "name": "Chest_Severe", + "directions": 4 + }, + { + "name": "Chest_Severe_alt", + "directions": 4 + }, + { + "name": "Chest_Minor", + "directions": 4, + "delays": [ + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ] + ] + }, + { + "name": "Chest_Minor_alt", + "directions": 4, + "delays": [ + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ] + ] + }, + { + "name": "Groin_Severe", + "directions": 4 + }, + { + "name": "Groin_Severe_alt", + "directions": 4 + }, + { + "name": "Groin_Minor", + "directions": 4, + "delays": [ + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ] + ] + }, + { + "name": "Groin_Minor_alt", + "directions": 4, + "delays": [ + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ] + ] + }, + { + "name": "LArm_Severe", + "directions": 4 + }, + { + "name": "LArm_Severe_alt", + "directions": 4 + }, + { + "name": "LArm_Minor", + "directions": 4, + "delays": [ + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ] + ] + }, + { + "name": "LArm_Minor_alt", + "directions": 4, + "delays": [ + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ] + ] + }, + { + "name": "RArm_Severe", + "directions": 4 + }, + { + "name": "RArm_Severe_alt", + "directions": 4 + }, + { + "name": "RArm_Minor", + "directions": 4, + "delays": [ + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ] + ] + }, + { + "name": "RArm_Minor_alt", + "directions": 4, + "delays": [ + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ] + ] + }, + { + "name": "RLeg_Severe", + "directions": 4 + }, + { + "name": "RLeg_Minor", + "directions": 4, + "delays": [ + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ] + ] + }, + { + "name": "RLeg_Minor_alt", + "directions": 4, + "delays": [ + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ] + ] + }, + { + "name": "LLeg_Severe", + "directions": 4 + }, + { + "name": "LLeg_Minor", + "directions": 4, + "delays": [ + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ] + ] + }, + { + "name": "LLeg_Minor_alt", + "directions": 4, + "delays": [ + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ], + [ + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4, + 0.4 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_10.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_10.png index c790ff58668..3e642887972 100644 Binary files a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_10.png and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_10.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_100.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_100.png index f0d9b5741b1..14b1e44fc62 100644 Binary files a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_100.png and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_100.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_20.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_20.png index 2dff27f8512..f823b2a6e01 100644 Binary files a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_20.png and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_20.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_30.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_30.png index 05419cc533b..516c3ba170a 100644 Binary files a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_30.png and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_30.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_40.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_40.png index 05419cc533b..516c3ba170a 100644 Binary files a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_40.png and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_40.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_50.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_50.png index d2ed2552d4d..eb000933740 100644 Binary files a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_50.png and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_50.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_70.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_70.png index ea8be7c02d4..504d8d1a4d2 100644 Binary files a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_70.png and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Chest_Brute_70.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_10.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_10.png new file mode 100644 index 00000000000..f917b09ecfa Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_10.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_100.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_100.png new file mode 100644 index 00000000000..0c28aa9d97a Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_100.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_20.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_20.png new file mode 100644 index 00000000000..a1cb8e8e8ea Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_20.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_30.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_30.png new file mode 100644 index 00000000000..50ff83d4f43 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_30.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_40.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_40.png new file mode 100644 index 00000000000..50ff83d4f43 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_40.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_50.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_50.png new file mode 100644 index 00000000000..d7e3ac2d69f Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_50.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_70.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_70.png new file mode 100644 index 00000000000..9d6ea047474 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/Groin_Brute_70.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_10.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_10.png new file mode 100644 index 00000000000..ec768124c11 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_10.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_100.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_100.png new file mode 100644 index 00000000000..09e4f816fd9 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_100.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_20.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_20.png new file mode 100644 index 00000000000..ec768124c11 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_20.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_30.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_30.png new file mode 100644 index 00000000000..ec768124c11 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_30.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_40.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_40.png new file mode 100644 index 00000000000..fbf8176edf1 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_40.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_50.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_50.png new file mode 100644 index 00000000000..09e4f816fd9 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_50.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_70.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_70.png new file mode 100644 index 00000000000..09e4f816fd9 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LFoot_Brute_70.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_10.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_10.png new file mode 100644 index 00000000000..fda89e28a47 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_10.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_100.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_100.png new file mode 100644 index 00000000000..aaa5f99e2e6 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_100.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_20.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_20.png new file mode 100644 index 00000000000..fda89e28a47 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_20.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_30.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_30.png new file mode 100644 index 00000000000..fda89e28a47 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_30.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_40.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_40.png new file mode 100644 index 00000000000..edb0eb1a697 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_40.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_50.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_50.png new file mode 100644 index 00000000000..edb0eb1a697 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_50.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_70.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_70.png new file mode 100644 index 00000000000..edb0eb1a697 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/LHand_Brute_70.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_10.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_10.png new file mode 100644 index 00000000000..d3a0f31100c Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_10.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_100.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_100.png new file mode 100644 index 00000000000..0380426f559 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_100.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_20.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_20.png new file mode 100644 index 00000000000..d3a0f31100c Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_20.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_30.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_30.png new file mode 100644 index 00000000000..d3a0f31100c Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_30.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_40.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_40.png new file mode 100644 index 00000000000..d63211650e3 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_40.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_50.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_50.png new file mode 100644 index 00000000000..d63211650e3 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_50.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_70.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_70.png new file mode 100644 index 00000000000..0380426f559 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RFoot_Brute_70.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_10.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_10.png new file mode 100644 index 00000000000..70efc3583ee Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_10.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_100.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_100.png new file mode 100644 index 00000000000..5616f6f91f8 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_100.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_20.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_20.png new file mode 100644 index 00000000000..70efc3583ee Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_20.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_30.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_30.png new file mode 100644 index 00000000000..70efc3583ee Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_30.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_40.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_40.png new file mode 100644 index 00000000000..22d66efd209 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_40.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_50.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_50.png new file mode 100644 index 00000000000..22d66efd209 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_50.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_70.png b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_70.png new file mode 100644 index 00000000000..5616f6f91f8 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/brute_damage.rsi/RHand_Brute_70.png differ diff --git a/Resources/Textures/Mobs/Effects/brute_damage.rsi/meta.json b/Resources/Textures/Mobs/Effects/brute_damage.rsi/meta.json index f249803b4bf..68069ba8f40 100644 --- a/Resources/Textures/Mobs/Effects/brute_damage.rsi/meta.json +++ b/Resources/Textures/Mobs/Effects/brute_damage.rsi/meta.json @@ -7,44 +7,79 @@ {"name": "Head_Brute_10", "directions": 4}, {"name": "LArm_Brute_10", "directions": 4}, {"name": "LLeg_Brute_10", "directions": 4}, + {"name": "LHand_Brute_10", "directions": 4}, + {"name": "LFoot_Brute_10", "directions": 4}, {"name": "RArm_Brute_10", "directions": 4}, {"name": "RLeg_Brute_10", "directions": 4}, + {"name": "RHand_Brute_10", "directions": 4}, + {"name": "RFoot_Brute_10", "directions": 4}, {"name": "Chest_Brute_10", "directions": 4}, + {"name": "Groin_Brute_10", "directions": 4}, {"name": "Head_Brute_20", "directions": 4}, {"name": "LArm_Brute_20", "directions": 4}, {"name": "LLeg_Brute_20", "directions": 4}, + {"name": "LHand_Brute_20", "directions": 4}, + {"name": "LFoot_Brute_20", "directions": 4}, {"name": "RArm_Brute_20", "directions": 4}, {"name": "RLeg_Brute_20", "directions": 4}, + {"name": "RHand_Brute_20", "directions": 4}, + {"name": "RFoot_Brute_20", "directions": 4}, {"name": "Chest_Brute_20", "directions": 4}, + {"name": "Groin_Brute_20", "directions": 4}, {"name": "Head_Brute_30", "directions": 4}, {"name": "LArm_Brute_30", "directions": 4}, {"name": "LLeg_Brute_30", "directions": 4}, + {"name": "LHand_Brute_30", "directions": 4}, + {"name": "LFoot_Brute_30", "directions": 4}, {"name": "RArm_Brute_30", "directions": 4}, {"name": "RLeg_Brute_30", "directions": 4}, + {"name": "RHand_Brute_30", "directions": 4}, + {"name": "RFoot_Brute_30", "directions": 4}, {"name": "Chest_Brute_30", "directions": 4}, - {"name": "Head_Brute_40", "directions": 4}, - {"name": "LArm_Brute_40", "directions": 4}, - {"name": "LLeg_Brute_40", "directions": 4}, - {"name": "RArm_Brute_40", "directions": 4}, - {"name": "RLeg_Brute_40", "directions": 4}, - {"name": "Chest_Brute_40", "directions": 4}, + {"name": "Groin_Brute_30", "directions": 4}, + {"name": "Head_Brute_40", "directions": 4}, + {"name": "LArm_Brute_40", "directions": 4}, + {"name": "LLeg_Brute_40", "directions": 4}, + {"name": "LHand_Brute_40", "directions": 4}, + {"name": "LFoot_Brute_40", "directions": 4}, + {"name": "RArm_Brute_40", "directions": 4}, + {"name": "RLeg_Brute_40", "directions": 4}, + {"name": "RHand_Brute_40", "directions": 4}, + {"name": "RFoot_Brute_40", "directions": 4}, + {"name": "Chest_Brute_40", "directions": 4}, + {"name": "Groin_Brute_40", "directions": 4}, {"name": "Head_Brute_50", "directions": 4}, {"name": "LArm_Brute_50", "directions": 4}, {"name": "LLeg_Brute_50", "directions": 4}, + {"name": "LHand_Brute_50", "directions": 4}, + {"name": "LFoot_Brute_50", "directions": 4}, {"name": "RArm_Brute_50", "directions": 4}, {"name": "RLeg_Brute_50", "directions": 4}, + {"name": "RHand_Brute_50", "directions": 4}, + {"name": "RFoot_Brute_50", "directions": 4}, {"name": "Chest_Brute_50", "directions": 4}, + {"name": "Groin_Brute_50", "directions": 4}, {"name": "Head_Brute_70", "directions": 4}, {"name": "LArm_Brute_70", "directions": 4}, {"name": "LLeg_Brute_70", "directions": 4}, + {"name": "LHand_Brute_70", "directions": 4}, + {"name": "LFoot_Brute_70", "directions": 4}, {"name": "RArm_Brute_70", "directions": 4}, {"name": "RLeg_Brute_70", "directions": 4}, + {"name": "RHand_Brute_70", "directions": 4}, + {"name": "RFoot_Brute_70", "directions": 4}, {"name": "Chest_Brute_70", "directions": 4}, + {"name": "Groin_Brute_70", "directions": 4}, {"name": "Head_Brute_100", "directions": 4}, {"name": "LArm_Brute_100", "directions": 4}, {"name": "LLeg_Brute_100", "directions": 4}, + {"name": "LHand_Brute_100", "directions": 4}, + {"name": "LFoot_Brute_100", "directions": 4}, {"name": "RArm_Brute_100", "directions": 4}, {"name": "RLeg_Brute_100", "directions": 4}, - {"name": "Chest_Brute_100", "directions": 4} + {"name": "RHand_Brute_100", "directions": 4}, + {"name": "RFoot_Brute_100", "directions": 4}, + {"name": "Chest_Brute_100", "directions": 4}, + {"name": "Groin_Brute_100", "directions": 4} ] -} +} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_10.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_10.png index bb29391fa06..6b164bf05dc 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_10.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_10.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_100.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_100.png index c4058b6b224..532a811985b 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_100.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_100.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_20.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_20.png index bb29391fa06..6b164bf05dc 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_20.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_20.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_30.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_30.png index 5a68c6fd861..6b164bf05dc 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_30.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_30.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_40.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_40.png new file mode 100644 index 00000000000..c1eea5eff61 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_40.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_50.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_50.png index 5a68c6fd861..c1eea5eff61 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_50.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_50.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_70.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_70.png index 2ca0dc67f15..532a811985b 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_70.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Chest_Burn_70.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_10.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_10.png new file mode 100644 index 00000000000..2ba596157a1 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_10.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_100.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_100.png new file mode 100644 index 00000000000..1dc4cca3f54 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_100.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_20.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_20.png new file mode 100644 index 00000000000..2ba596157a1 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_20.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_30.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_30.png new file mode 100644 index 00000000000..2ba596157a1 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_30.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_40.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_40.png new file mode 100644 index 00000000000..39ac67ac60d Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_40.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_50.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_50.png new file mode 100644 index 00000000000..39ac67ac60d Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_50.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_70.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_70.png new file mode 100644 index 00000000000..1dc4cca3f54 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Groin_Burn_70.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_10.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_10.png index f91dae519af..147a3004c16 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_10.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_10.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_100.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_100.png index 753e8c5cbf6..ed7484eef76 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_100.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_100.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_20.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_20.png index f91dae519af..147a3004c16 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_20.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_20.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_30.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_30.png index 90d69223b6d..147a3004c16 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_30.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_30.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_40.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_40.png new file mode 100644 index 00000000000..747ff96402d Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_40.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_50.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_50.png index 90d69223b6d..747ff96402d 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_50.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_50.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_70.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_70.png index 36b91148162..ed7484eef76 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_70.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/Head_Burn_70.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_10.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_10.png index bc8f7bf9cae..a1adf532878 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_10.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_10.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_100.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_100.png index cfac53ac3bc..9749f6107e4 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_100.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_100.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_20.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_20.png index bc8f7bf9cae..a1adf532878 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_20.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_20.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_30.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_30.png index 7c8da637caf..a1adf532878 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_30.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_30.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_40.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_40.png new file mode 100644 index 00000000000..690f1727fcc Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_40.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_50.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_50.png index 7c8da637caf..690f1727fcc 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_50.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_50.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_70.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_70.png index 2dc53776594..9749f6107e4 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_70.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LArm_Burn_70.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_10.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_10.png new file mode 100644 index 00000000000..80b8acadf5e Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_10.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_100.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_100.png new file mode 100644 index 00000000000..d3c2a7c53ec Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_100.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_20.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_20.png new file mode 100644 index 00000000000..80b8acadf5e Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_20.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_30.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_30.png new file mode 100644 index 00000000000..80b8acadf5e Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_30.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_40.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_40.png new file mode 100644 index 00000000000..68336153bd7 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_40.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_50.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_50.png new file mode 100644 index 00000000000..68336153bd7 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_50.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_70.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_70.png new file mode 100644 index 00000000000..d3c2a7c53ec Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LFoot_Burn_70.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_10.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_10.png new file mode 100644 index 00000000000..a2e2322b009 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_10.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_100.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_100.png new file mode 100644 index 00000000000..6c765f56f4a Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_100.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_20.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_20.png new file mode 100644 index 00000000000..a2e2322b009 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_20.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_30.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_30.png new file mode 100644 index 00000000000..a2e2322b009 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_30.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_40.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_40.png new file mode 100644 index 00000000000..cc19fcc10a6 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_40.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_50.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_50.png new file mode 100644 index 00000000000..cc19fcc10a6 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_50.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_70.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_70.png new file mode 100644 index 00000000000..6c765f56f4a Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LHand_Burn_70.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_10.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_10.png index 70b91d88244..16f0674219d 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_10.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_10.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_100.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_100.png index 4a55dd5b725..0c5f33d26a2 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_100.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_100.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_20.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_20.png index 70b91d88244..16f0674219d 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_20.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_20.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_30.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_30.png index a84ef88da87..16f0674219d 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_30.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_30.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_40.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_40.png new file mode 100644 index 00000000000..1f016662bef Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_40.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_50.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_50.png index a84ef88da87..1f016662bef 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_50.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_50.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_70.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_70.png index c18e5545414..0c5f33d26a2 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_70.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/LLeg_Burn_70.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_10.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_10.png index 96b96b566bf..3b6726b5598 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_10.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_10.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_100.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_100.png index 45d10bff5c5..d30d2bf41b2 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_100.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_100.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_20.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_20.png index 96b96b566bf..3b6726b5598 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_20.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_20.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_30.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_30.png index 1d0c791e388..3b6726b5598 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_30.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_30.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_40.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_40.png new file mode 100644 index 00000000000..d8b1dc445ec Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_40.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_50.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_50.png index 1d0c791e388..d8b1dc445ec 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_50.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_50.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_70.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_70.png index 77e463d02f2..d30d2bf41b2 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_70.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RArm_Burn_70.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_10.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_10.png new file mode 100644 index 00000000000..efea8f31add Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_10.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_100.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_100.png new file mode 100644 index 00000000000..596bdd2652b Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_100.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_20.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_20.png new file mode 100644 index 00000000000..efea8f31add Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_20.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_30.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_30.png new file mode 100644 index 00000000000..efea8f31add Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_30.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_40.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_40.png new file mode 100644 index 00000000000..8ad11c79c53 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_40.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_50.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_50.png new file mode 100644 index 00000000000..8ad11c79c53 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_50.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_70.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_70.png new file mode 100644 index 00000000000..596bdd2652b Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RFoot_Burn_70.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_10.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_10.png new file mode 100644 index 00000000000..d290b7f4b2d Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_10.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_100.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_100.png new file mode 100644 index 00000000000..2721d1ff2aa Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_100.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_20.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_20.png new file mode 100644 index 00000000000..d290b7f4b2d Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_20.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_30.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_30.png new file mode 100644 index 00000000000..d290b7f4b2d Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_30.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_40.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_40.png new file mode 100644 index 00000000000..37a6067c588 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_40.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_50.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_50.png new file mode 100644 index 00000000000..37a6067c588 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_50.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_70.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_70.png new file mode 100644 index 00000000000..2721d1ff2aa Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RHand_Burn_70.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_10.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_10.png index 5f5d390792b..121bea1bb91 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_10.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_10.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_100.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_100.png index 1541b5c78fe..10f8fc99c7b 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_100.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_100.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_20.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_20.png index 5f5d390792b..121bea1bb91 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_20.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_20.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_30.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_30.png index efe3ad8b539..121bea1bb91 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_30.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_30.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_40.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_40.png new file mode 100644 index 00000000000..1c920919763 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_40.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_50.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_50.png index efe3ad8b539..1c920919763 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_50.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_50.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_70.png b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_70.png index 978e01358f9..10f8fc99c7b 100644 Binary files a/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_70.png and b/Resources/Textures/Mobs/Effects/burn_damage.rsi/RLeg_Burn_70.png differ diff --git a/Resources/Textures/Mobs/Effects/burn_damage.rsi/meta.json b/Resources/Textures/Mobs/Effects/burn_damage.rsi/meta.json index 3649a05cc1a..8e5e8b20f06 100644 --- a/Resources/Textures/Mobs/Effects/burn_damage.rsi/meta.json +++ b/Resources/Textures/Mobs/Effects/burn_damage.rsi/meta.json @@ -1,44 +1,85 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from https://github.com/Citadel-Station-13/Citadel-Station-13/blob/971ddef989f7f4f365a714ef3d4df5dea2d53d9a/icons/mob/dam_mob.dmi, 100 drawn by Ubaser.", + "copyright": "Drawn by Ubaser.", "size": {"x": 32, "y": 32}, "states": [ {"name": "Head_Burn_10", "directions": 4}, {"name": "LArm_Burn_10", "directions": 4}, {"name": "LLeg_Burn_10", "directions": 4}, + {"name": "LHand_Burn_10", "directions": 4}, + {"name": "LFoot_Burn_10", "directions": 4}, {"name": "RArm_Burn_10", "directions": 4}, {"name": "RLeg_Burn_10", "directions": 4}, + {"name": "RHand_Burn_10", "directions": 4}, + {"name": "RFoot_Burn_10", "directions": 4}, {"name": "Chest_Burn_10", "directions": 4}, + {"name": "Groin_Burn_10", "directions": 4}, {"name": "Head_Burn_20", "directions": 4}, {"name": "LArm_Burn_20", "directions": 4}, {"name": "LLeg_Burn_20", "directions": 4}, + {"name": "LHand_Burn_20", "directions": 4}, + {"name": "LFoot_Burn_20", "directions": 4}, {"name": "RArm_Burn_20", "directions": 4}, {"name": "RLeg_Burn_20", "directions": 4}, + {"name": "RHand_Burn_20", "directions": 4}, + {"name": "RFoot_Burn_20", "directions": 4}, {"name": "Chest_Burn_20", "directions": 4}, + {"name": "Groin_Burn_20", "directions": 4}, {"name": "Head_Burn_30", "directions": 4}, {"name": "LArm_Burn_30", "directions": 4}, {"name": "LLeg_Burn_30", "directions": 4}, + {"name": "LHand_Burn_30", "directions": 4}, + {"name": "LFoot_Burn_30", "directions": 4}, {"name": "RArm_Burn_30", "directions": 4}, {"name": "RLeg_Burn_30", "directions": 4}, + {"name": "RHand_Burn_30", "directions": 4}, + {"name": "RFoot_Burn_30", "directions": 4}, {"name": "Chest_Burn_30", "directions": 4}, + {"name": "Groin_Burn_30", "directions": 4}, + {"name": "Head_Burn_40", "directions": 4}, + {"name": "LArm_Burn_40", "directions": 4}, + {"name": "LLeg_Burn_40", "directions": 4}, + {"name": "LHand_Burn_40", "directions": 4}, + {"name": "LFoot_Burn_40", "directions": 4}, + {"name": "RArm_Burn_40", "directions": 4}, + {"name": "RLeg_Burn_40", "directions": 4}, + {"name": "RHand_Burn_40", "directions": 4}, + {"name": "RFoot_Burn_40", "directions": 4}, + {"name": "Chest_Burn_40", "directions": 4}, + {"name": "Groin_Burn_40", "directions": 4}, {"name": "Head_Burn_50", "directions": 4}, {"name": "LArm_Burn_50", "directions": 4}, {"name": "LLeg_Burn_50", "directions": 4}, + {"name": "LHand_Burn_50", "directions": 4}, + {"name": "LFoot_Burn_50", "directions": 4}, {"name": "RArm_Burn_50", "directions": 4}, {"name": "RLeg_Burn_50", "directions": 4}, + {"name": "RHand_Burn_50", "directions": 4}, + {"name": "RFoot_Burn_50", "directions": 4}, {"name": "Chest_Burn_50", "directions": 4}, + {"name": "Groin_Burn_50", "directions": 4}, {"name": "Head_Burn_70", "directions": 4}, {"name": "LArm_Burn_70", "directions": 4}, {"name": "LLeg_Burn_70", "directions": 4}, + {"name": "LHand_Burn_70", "directions": 4}, + {"name": "LFoot_Burn_70", "directions": 4}, {"name": "RArm_Burn_70", "directions": 4}, {"name": "RLeg_Burn_70", "directions": 4}, + {"name": "RHand_Burn_70", "directions": 4}, + {"name": "RFoot_Burn_70", "directions": 4}, {"name": "Chest_Burn_70", "directions": 4}, + {"name": "Groin_Burn_70", "directions": 4}, {"name": "Head_Burn_100", "directions": 4}, {"name": "LArm_Burn_100", "directions": 4}, {"name": "LLeg_Burn_100", "directions": 4}, + {"name": "LHand_Burn_100", "directions": 4}, + {"name": "LFoot_Burn_100", "directions": 4}, {"name": "RArm_Burn_100", "directions": 4}, {"name": "RLeg_Burn_100", "directions": 4}, - {"name": "Chest_Burn_100", "directions": 4} + {"name": "RHand_Burn_100", "directions": 4}, + {"name": "RFoot_Burn_100", "directions": 4}, + {"name": "Chest_Burn_100", "directions": 4}, + {"name": "Groin_Burn_100", "directions": 4} ] -} +} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/chest_f.png b/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/chest_f.png new file mode 100644 index 00000000000..3329952c500 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/chest_m.png b/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/chest_m.png new file mode 100644 index 00000000000..5cf7f505172 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/groin_f.png b/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/groin_f.png new file mode 100644 index 00000000000..61b31604ddf Binary files /dev/null and b/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/groin_f.png differ diff --git a/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/groin_m.png b/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/groin_m.png new file mode 100644 index 00000000000..1879d335a49 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/groin_m.png differ diff --git a/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/meta.json b/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/meta.json index a09c655a2b0..2659a7fdf88 100644 --- a/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/meta.json +++ b/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/meta.json @@ -51,11 +51,19 @@ "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", + "directions": 4 + }, + { + "name": "groin_f", + "directions": 4 + }, + { + "name": "groin_m", "directions": 4 }, { diff --git a/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/torso_f.png b/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/torso_f.png deleted file mode 100644 index 10f3a3b0e4c..00000000000 Binary files a/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/torso_m.png b/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/torso_m.png deleted file mode 100644 index 10f3a3b0e4c..00000000000 Binary files a/Resources/Textures/Mobs/Species/Arachnid/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Diona/parts.rsi/chest_f.png b/Resources/Textures/Mobs/Species/Diona/parts.rsi/chest_f.png new file mode 100644 index 00000000000..7595fa0e506 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Diona/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Mobs/Species/Diona/parts.rsi/chest_m.png b/Resources/Textures/Mobs/Species/Diona/parts.rsi/chest_m.png new file mode 100644 index 00000000000..172a9d2501b Binary files /dev/null and b/Resources/Textures/Mobs/Species/Diona/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Mobs/Species/Diona/parts.rsi/groin_f.png b/Resources/Textures/Mobs/Species/Diona/parts.rsi/groin_f.png new file mode 100644 index 00000000000..ebdd9efcde2 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Diona/parts.rsi/groin_f.png differ diff --git a/Resources/Textures/Mobs/Species/Diona/parts.rsi/groin_m.png b/Resources/Textures/Mobs/Species/Diona/parts.rsi/groin_m.png new file mode 100644 index 00000000000..a5363dd5c9f Binary files /dev/null and b/Resources/Textures/Mobs/Species/Diona/parts.rsi/groin_m.png differ diff --git a/Resources/Textures/Mobs/Species/Diona/parts.rsi/meta.json b/Resources/Textures/Mobs/Species/Diona/parts.rsi/meta.json index bc90b509a1d..18a4112ec7e 100644 --- a/Resources/Textures/Mobs/Species/Diona/parts.rsi/meta.json +++ b/Resources/Textures/Mobs/Species/Diona/parts.rsi/meta.json @@ -51,11 +51,19 @@ "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", + "directions": 4 + }, + { + "name": "groin_f", + "directions": 4 + }, + { + "name": "groin_m", "directions": 4 } ] diff --git a/Resources/Textures/Mobs/Species/Diona/parts.rsi/torso_f.png b/Resources/Textures/Mobs/Species/Diona/parts.rsi/torso_f.png deleted file mode 100644 index 6aaf688a4a2..00000000000 Binary files a/Resources/Textures/Mobs/Species/Diona/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Diona/parts.rsi/torso_m.png b/Resources/Textures/Mobs/Species/Diona/parts.rsi/torso_m.png deleted file mode 100644 index 6aaf688a4a2..00000000000 Binary files a/Resources/Textures/Mobs/Species/Diona/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/chest_f.png b/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/chest_f.png new file mode 100644 index 00000000000..e58314eeaec Binary files /dev/null and b/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/chest_m.png b/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/chest_m.png new file mode 100644 index 00000000000..161d13f167d Binary files /dev/null and b/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/groin_f.png b/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/groin_f.png new file mode 100644 index 00000000000..f2c3af9dfae Binary files /dev/null and b/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/groin_f.png differ diff --git a/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/groin_m.png b/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/groin_m.png new file mode 100644 index 00000000000..f2c3af9dfae Binary files /dev/null and b/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/groin_m.png differ diff --git a/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/meta.json b/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/meta.json index fec31a494d2..ef64f337be3 100644 --- a/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/meta.json +++ b/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/meta.json @@ -51,11 +51,19 @@ "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", + "directions": 4 + }, + { + "name": "groin_f", + "directions": 4 + }, + { + "name": "groin_m", "directions": 4 } ] diff --git a/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/torso_f.png b/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/torso_f.png deleted file mode 100644 index bde0508ffda..00000000000 Binary files a/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/torso_m.png b/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/torso_m.png deleted file mode 100644 index bde0508ffda..00000000000 Binary files a/Resources/Textures/Mobs/Species/Gingerbread/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/chest_f.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/chest_f.png new file mode 100644 index 00000000000..e2575610859 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Human/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/chest_m.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/chest_m.png new file mode 100644 index 00000000000..a1aa0f6c775 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Human/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/groin_f.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/groin_f.png new file mode 100644 index 00000000000..d3131d9337d Binary files /dev/null and b/Resources/Textures/Mobs/Species/Human/parts.rsi/groin_f.png differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/groin_m.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/groin_m.png new file mode 100644 index 00000000000..6040a030f20 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Human/parts.rsi/groin_m.png differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/head_f.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/head_f.png index 1b790023dbf..b705d2d50e8 100644 Binary files a/Resources/Textures/Mobs/Species/Human/parts.rsi/head_f.png and b/Resources/Textures/Mobs/Species/Human/parts.rsi/head_f.png differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/head_m.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/head_m.png index 15806d9f145..e555d030bea 100644 Binary files a/Resources/Textures/Mobs/Species/Human/parts.rsi/head_m.png and b/Resources/Textures/Mobs/Species/Human/parts.rsi/head_m.png differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/l_arm.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/l_arm.png index 5086d947497..cf3997a120c 100644 Binary files a/Resources/Textures/Mobs/Species/Human/parts.rsi/l_arm.png and b/Resources/Textures/Mobs/Species/Human/parts.rsi/l_arm.png differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/l_foot.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/l_foot.png index 59db0183c3e..c448837af23 100644 Binary files a/Resources/Textures/Mobs/Species/Human/parts.rsi/l_foot.png and b/Resources/Textures/Mobs/Species/Human/parts.rsi/l_foot.png differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/l_hand.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/l_hand.png index 7f68ac81ba7..7bf47c949a5 100644 Binary files a/Resources/Textures/Mobs/Species/Human/parts.rsi/l_hand.png and b/Resources/Textures/Mobs/Species/Human/parts.rsi/l_hand.png differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/l_leg.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/l_leg.png index f8d1e10a5b9..b3ce27ba862 100644 Binary files a/Resources/Textures/Mobs/Species/Human/parts.rsi/l_leg.png and b/Resources/Textures/Mobs/Species/Human/parts.rsi/l_leg.png differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/meta.json b/Resources/Textures/Mobs/Species/Human/parts.rsi/meta.json index ce03292c8a9..57b09bfe64f 100644 --- a/Resources/Textures/Mobs/Species/Human/parts.rsi/meta.json +++ b/Resources/Textures/Mobs/Species/Human/parts.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/tgstation/tgstation/blob/8024397cc81c5f47f74cf4279e35728487d0a1a7/icons/mob/human_parts_greyscale.dmi and modified by DrSmugleaf", + "copyright": "https://github.com/tgstation/tgstation/blob/8024397cc81c5f47f74cf4279e35728487d0a1a7/icons/mob/human_parts_greyscale.dmi and modified by DrSmugleaf. WD TEAM EDIT", "size": { "x": 32, "y": 32 @@ -51,11 +51,19 @@ "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", + "directions": 4 + }, + { + "name": "groin_f", + "directions": 4 + }, + { + "name": "groin_m", "directions": 4 } ] diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/r_arm.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/r_arm.png index c99576f6b4d..8887c30fa27 100644 Binary files a/Resources/Textures/Mobs/Species/Human/parts.rsi/r_arm.png and b/Resources/Textures/Mobs/Species/Human/parts.rsi/r_arm.png differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/r_foot.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/r_foot.png index 82f8b5fc1a7..8d51a591a45 100644 Binary files a/Resources/Textures/Mobs/Species/Human/parts.rsi/r_foot.png and b/Resources/Textures/Mobs/Species/Human/parts.rsi/r_foot.png differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/r_hand.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/r_hand.png index 4036a8cadd0..a4810281263 100644 Binary files a/Resources/Textures/Mobs/Species/Human/parts.rsi/r_hand.png and b/Resources/Textures/Mobs/Species/Human/parts.rsi/r_hand.png differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/r_leg.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/r_leg.png index 3db45089c5b..67917397a1e 100644 Binary files a/Resources/Textures/Mobs/Species/Human/parts.rsi/r_leg.png and b/Resources/Textures/Mobs/Species/Human/parts.rsi/r_leg.png differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/torso_f.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/torso_f.png deleted file mode 100644 index f205121b6c4..00000000000 Binary files a/Resources/Textures/Mobs/Species/Human/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Human/parts.rsi/torso_m.png b/Resources/Textures/Mobs/Species/Human/parts.rsi/torso_m.png deleted file mode 100644 index f0a4aeb57ed..00000000000 Binary files a/Resources/Textures/Mobs/Species/Human/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Moth/parts.rsi/chest_f.png b/Resources/Textures/Mobs/Species/Moth/parts.rsi/chest_f.png new file mode 100644 index 00000000000..bafd4bc8061 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Moth/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Mobs/Species/Moth/parts.rsi/chest_m.png b/Resources/Textures/Mobs/Species/Moth/parts.rsi/chest_m.png new file mode 100644 index 00000000000..32acc4a6e8f Binary files /dev/null and b/Resources/Textures/Mobs/Species/Moth/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Mobs/Species/Moth/parts.rsi/groin_f.png b/Resources/Textures/Mobs/Species/Moth/parts.rsi/groin_f.png new file mode 100644 index 00000000000..af9cd908d12 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Moth/parts.rsi/groin_f.png differ diff --git a/Resources/Textures/Mobs/Species/Moth/parts.rsi/groin_m.png b/Resources/Textures/Mobs/Species/Moth/parts.rsi/groin_m.png new file mode 100644 index 00000000000..3781e195c6b Binary files /dev/null and b/Resources/Textures/Mobs/Species/Moth/parts.rsi/groin_m.png differ diff --git a/Resources/Textures/Mobs/Species/Moth/parts.rsi/meta.json b/Resources/Textures/Mobs/Species/Moth/parts.rsi/meta.json index 016f008fc91..3ef0880b3ad 100644 --- a/Resources/Textures/Mobs/Species/Moth/parts.rsi/meta.json +++ b/Resources/Textures/Mobs/Species/Moth/parts.rsi/meta.json @@ -51,11 +51,19 @@ "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", + "directions": 4 + }, + { + "name": "groin_f", + "directions": 4 + }, + { + "name": "groin_m", "directions": 4 }, { diff --git a/Resources/Textures/Mobs/Species/Moth/parts.rsi/torso_f.png b/Resources/Textures/Mobs/Species/Moth/parts.rsi/torso_f.png deleted file mode 100644 index 233dd6d7222..00000000000 Binary files a/Resources/Textures/Mobs/Species/Moth/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Moth/parts.rsi/torso_m.png b/Resources/Textures/Mobs/Species/Moth/parts.rsi/torso_m.png deleted file mode 100644 index a2722c22730..00000000000 Binary files a/Resources/Textures/Mobs/Species/Moth/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/chest_f.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/chest_f.png new file mode 100644 index 00000000000..63e5a614425 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/chest_m.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/chest_m.png new file mode 100644 index 00000000000..097a5ebb571 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/groin_f.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/groin_f.png new file mode 100644 index 00000000000..df32374b81b Binary files /dev/null and b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/groin_f.png differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/groin_m.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/groin_m.png new file mode 100644 index 00000000000..4921508fc1a Binary files /dev/null and b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/groin_m.png differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/head_f.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/head_f.png index fcd500afae0..b0d7991413a 100644 Binary files a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/head_f.png and b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/head_f.png differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/head_m.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/head_m.png index 95f6de4e52b..5f97e34921a 100644 Binary files a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/head_m.png and b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/head_m.png differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_arm.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_arm.png index 53510c49417..a0e2c96fda6 100644 Binary files a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_arm.png and b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_arm.png differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_foot.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_foot.png index 06c9c98b20a..ce0d6b70b97 100644 Binary files a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_foot.png and b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_foot.png differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_hand.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_hand.png index 02b34405186..bc206249ea5 100644 Binary files a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_hand.png and b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_hand.png differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_leg.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_leg.png index 463ebd21ad5..34cafa2269d 100644 Binary files a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_leg.png and b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/l_leg.png differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/meta.json b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/meta.json index 87197a14f3d..59b2a4747ba 100644 --- a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/meta.json +++ b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/tgstation/tgstation/blob/08898964e67a0d517ca4e47eec7039394b694ac2/icons/mob/species/lizard/bodyparts.dmi", + "copyright": "https://github.com/tgstation/tgstation/blob/8024397cc81c5f47f74cf4279e35728487d0a1a7/icons/mob/human_parts_greyscale.dmi", "size": { "x": 32, "y": 32 @@ -51,11 +51,19 @@ "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", + "directions": 4 + }, + { + "name": "groin_f", + "directions": 4 + }, + { + "name": "groin_m", "directions": 4 } ] diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_arm.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_arm.png index cb696e84d93..de8edc447d1 100644 Binary files a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_arm.png and b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_arm.png differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_foot.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_foot.png index ec467675367..d39a9244c05 100644 Binary files a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_foot.png and b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_foot.png differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_hand.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_hand.png index 21d572b305c..8f292ffe0d2 100644 Binary files a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_hand.png and b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_hand.png differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_leg.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_leg.png index b9353474f99..e761dd9250c 100644 Binary files a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_leg.png and b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/r_leg.png differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/torso_f.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/torso_f.png deleted file mode 100644 index e9ae3189c39..00000000000 Binary files a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/torso_m.png b/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/torso_m.png deleted file mode 100644 index 21741816c02..00000000000 Binary files a/Resources/Textures/Mobs/Species/Reptilian/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/chest_f.png b/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/chest_f.png new file mode 100644 index 00000000000..a2b59f6a133 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/chest_m.png b/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/chest_m.png new file mode 100644 index 00000000000..81e325b9060 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/groin_f.png b/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/groin_f.png new file mode 100644 index 00000000000..f3ded9c31a7 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/groin_f.png differ diff --git a/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/groin_m.png b/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/groin_m.png new file mode 100644 index 00000000000..3cc23cd3e97 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/groin_m.png differ diff --git a/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/meta.json b/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/meta.json index 78e0a89e04d..bdef8ff90e1 100644 --- a/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/meta.json +++ b/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/meta.json @@ -55,11 +55,19 @@ "directions": 1 }, { - "name": "torso_f", + "name": "chest_f", "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", + "directions": 4 + }, + { + "name": "groin_f", + "directions": 4 + }, + { + "name": "groin_m", "directions": 4 } ] diff --git a/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/torso_f.png b/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/torso_f.png deleted file mode 100644 index 6eb022a0962..00000000000 Binary files a/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/torso_m.png b/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/torso_m.png deleted file mode 100644 index 22f860dc919..00000000000 Binary files a/Resources/Textures/Mobs/Species/Skeleton/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Slime/parts.rsi/chest_f.png b/Resources/Textures/Mobs/Species/Slime/parts.rsi/chest_f.png new file mode 100644 index 00000000000..2c0cd16f733 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Slime/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Mobs/Species/Slime/parts.rsi/chest_m.png b/Resources/Textures/Mobs/Species/Slime/parts.rsi/chest_m.png new file mode 100644 index 00000000000..9c3572e394a Binary files /dev/null and b/Resources/Textures/Mobs/Species/Slime/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Mobs/Species/Slime/parts.rsi/groin_f.png b/Resources/Textures/Mobs/Species/Slime/parts.rsi/groin_f.png new file mode 100644 index 00000000000..fee712bda76 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Slime/parts.rsi/groin_f.png differ diff --git a/Resources/Textures/Mobs/Species/Slime/parts.rsi/groin_m.png b/Resources/Textures/Mobs/Species/Slime/parts.rsi/groin_m.png new file mode 100644 index 00000000000..a3e458df06e Binary files /dev/null and b/Resources/Textures/Mobs/Species/Slime/parts.rsi/groin_m.png differ diff --git a/Resources/Textures/Mobs/Species/Slime/parts.rsi/meta.json b/Resources/Textures/Mobs/Species/Slime/parts.rsi/meta.json index a7822a9e6ce..7cfc519700d 100644 --- a/Resources/Textures/Mobs/Species/Slime/parts.rsi/meta.json +++ b/Resources/Textures/Mobs/Species/Slime/parts.rsi/meta.json @@ -51,11 +51,19 @@ "directions": 4 }, { - "name": "torso_f", + "name": "chest_f", "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", + "directions": 4 + }, + { + "name": "groin_f", + "directions": 4 + }, + { + "name": "groin_m", "directions": 4 } ] diff --git a/Resources/Textures/Mobs/Species/Slime/parts.rsi/torso_f.png b/Resources/Textures/Mobs/Species/Slime/parts.rsi/torso_f.png deleted file mode 100644 index bd61739a505..00000000000 Binary files a/Resources/Textures/Mobs/Species/Slime/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Slime/parts.rsi/torso_m.png b/Resources/Textures/Mobs/Species/Slime/parts.rsi/torso_m.png deleted file mode 100644 index 5ea1a483f46..00000000000 Binary files a/Resources/Textures/Mobs/Species/Slime/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Terminator/parts.rsi/chest_f.png b/Resources/Textures/Mobs/Species/Terminator/parts.rsi/chest_f.png new file mode 100644 index 00000000000..c15fe198283 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Terminator/parts.rsi/chest_f.png differ diff --git a/Resources/Textures/Mobs/Species/Terminator/parts.rsi/chest_m.png b/Resources/Textures/Mobs/Species/Terminator/parts.rsi/chest_m.png new file mode 100644 index 00000000000..886b462b966 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Terminator/parts.rsi/chest_m.png differ diff --git a/Resources/Textures/Mobs/Species/Terminator/parts.rsi/groin_f.png b/Resources/Textures/Mobs/Species/Terminator/parts.rsi/groin_f.png new file mode 100644 index 00000000000..3b058544ccd Binary files /dev/null and b/Resources/Textures/Mobs/Species/Terminator/parts.rsi/groin_f.png differ diff --git a/Resources/Textures/Mobs/Species/Terminator/parts.rsi/groin_m.png b/Resources/Textures/Mobs/Species/Terminator/parts.rsi/groin_m.png new file mode 100644 index 00000000000..a5685582461 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Terminator/parts.rsi/groin_m.png differ diff --git a/Resources/Textures/Mobs/Species/Terminator/parts.rsi/meta.json b/Resources/Textures/Mobs/Species/Terminator/parts.rsi/meta.json index 688877a32d0..b146ad203f9 100644 --- a/Resources/Textures/Mobs/Species/Terminator/parts.rsi/meta.json +++ b/Resources/Textures/Mobs/Species/Terminator/parts.rsi/meta.json @@ -55,11 +55,19 @@ "directions": 1 }, { - "name": "torso_f", + "name": "chest_f", "directions": 4 }, { - "name": "torso_m", + "name": "chest_m", + "directions": 4 + }, + { + "name": "groin_f", + "directions": 4 + }, + { + "name": "groin_m", "directions": 4 } ] diff --git a/Resources/Textures/Mobs/Species/Terminator/parts.rsi/torso_f.png b/Resources/Textures/Mobs/Species/Terminator/parts.rsi/torso_f.png deleted file mode 100644 index 2bcb3cc9eba..00000000000 Binary files a/Resources/Textures/Mobs/Species/Terminator/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Terminator/parts.rsi/torso_m.png b/Resources/Textures/Mobs/Species/Terminator/parts.rsi/torso_m.png deleted file mode 100644 index 2bcb3cc9eba..00000000000 Binary files a/Resources/Textures/Mobs/Species/Terminator/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/chest.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/chest.png new file mode 100644 index 00000000000..90e9dee45e5 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/chest.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin.png index ec0dd8402e5..dc520573735 100644 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin.png and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/meta.json b/Resources/Textures/Mobs/Species/Vox/parts.rsi/meta.json index 4704e093b40..8dbe18014d0 100644 --- a/Resources/Textures/Mobs/Species/Vox/parts.rsi/meta.json +++ b/Resources/Textures/Mobs/Species/Vox/parts.rsi/meta.json @@ -59,7 +59,7 @@ "directions": 4 }, { - "name": "torso", + "name": "chest", "directions": 4 }, { diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/torso.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/torso.png deleted file mode 100644 index 3910fb39a67..00000000000 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/torso.png and /dev/null differ diff --git a/Resources/Textures/Structures/Doors/Airlocks/Standard/external.rsi/closed.png b/Resources/Textures/Structures/Doors/Airlocks/Standard/external.rsi/closed.png index 972a78e44db..4a6123c0997 100644 Binary files a/Resources/Textures/Structures/Doors/Airlocks/Standard/external.rsi/closed.png and b/Resources/Textures/Structures/Doors/Airlocks/Standard/external.rsi/closed.png differ diff --git a/Resources/Textures/Tiles/Planet/Snow/snow_double_edge_south.png b/Resources/Textures/Tiles/Planet/Snow/snow_double_edge_south.png index 7b45cd388c3..1c540597853 100644 Binary files a/Resources/Textures/Tiles/Planet/Snow/snow_double_edge_south.png and b/Resources/Textures/Tiles/Planet/Snow/snow_double_edge_south.png differ diff --git a/Resources/Textures/Tiles/attributions.yml b/Resources/Textures/Tiles/attributions.yml index 458269c96a7..18b63a24170 100644 --- a/Resources/Textures/Tiles/attributions.yml +++ b/Resources/Textures/Tiles/attributions.yml @@ -38,10 +38,10 @@ - files: ["blue_circuit.png", "cropped_parallax.png", "eighties.png", "gold.png", "ironsand1.png", "ironsand2.png", "ironsand3.png", "ironsand4.png", "lattice.png", "plating.png", "reinforced.png", "silver.png", "snow.png", "wood.png"] license: "CC-BY-SA-3.0" - copyright: "tgstation commit 8abb19545828230d92ba18827feeb42a67a55d49, cropped_parallax modified from parallax, [reinforced, snow] modified by Ko4erga (discord), wood resprited by Meowstushka and modified by Ko4erga (discord)" + copyright: "tgstation commit 8abb19545828230d92ba18827feeb42a67a55d49, cropped_parallax modified from parallax, reinforced modified by Ko4erga (discord), wood resprited by Meowstushka and modified by Ko4erga (discord)" source: "https://github.com/tgstation/tgstation/" -- files: ["grass.png", "junglegrass.png", "grassdark.png", "grassjungle.png", "grasslight.png"] # Corvax +- files: ["grass.png", "junglegrass.png", "grassdark.png", "grassjungle.png", "grasslight.png"] #Corvax license: "CC-BY-SA-3.0" copyright: "Created by Ko4erga (discord)" source: "https://github.com/space-wizards/space-station-14/pull/29134" diff --git a/Resources/Textures/_Shitmed/Mobs/Aliens/Carps/carp_parts.rsi/chest.png b/Resources/Textures/_Shitmed/Mobs/Aliens/Carps/carp_parts.rsi/chest.png new file mode 100644 index 00000000000..dc86b317133 Binary files /dev/null and b/Resources/Textures/_Shitmed/Mobs/Aliens/Carps/carp_parts.rsi/chest.png differ diff --git a/Resources/Textures/_Shitmed/Mobs/Aliens/Carps/carp_parts.rsi/groin.png b/Resources/Textures/_Shitmed/Mobs/Aliens/Carps/carp_parts.rsi/groin.png new file mode 100644 index 00000000000..f06137c246b Binary files /dev/null and b/Resources/Textures/_Shitmed/Mobs/Aliens/Carps/carp_parts.rsi/groin.png differ diff --git a/Resources/Textures/_Shitmed/Mobs/Aliens/Carps/carp_parts.rsi/meta.json b/Resources/Textures/_Shitmed/Mobs/Aliens/Carps/carp_parts.rsi/meta.json index cdecf550def..245a68a7fbe 100644 --- a/Resources/Textures/_Shitmed/Mobs/Aliens/Carps/carp_parts.rsi/meta.json +++ b/Resources/Textures/_Shitmed/Mobs/Aliens/Carps/carp_parts.rsi/meta.json @@ -11,7 +11,10 @@ "name": "tail" }, { - "name": "torso" + "name": "chest" + }, + { + "name": "groin" } ] } diff --git a/Resources/Textures/_Shitmed/Mobs/Aliens/Carps/carp_parts.rsi/torso.png b/Resources/Textures/_Shitmed/Mobs/Aliens/Carps/carp_parts.rsi/torso.png deleted file mode 100644 index ab0f5ff82f0..00000000000 Binary files a/Resources/Textures/_Shitmed/Mobs/Aliens/Carps/carp_parts.rsi/torso.png and /dev/null differ diff --git a/Resources/keybinds.yml b/Resources/keybinds.yml index 912954c318a..d8fdd275278 100644 --- a/Resources/keybinds.yml +++ b/Resources/keybinds.yml @@ -609,9 +609,13 @@ binds: - function: TargetHead type: State key: NumpadNum8 -- function: TargetTorso +- function: TargetChest type: State key: NumpadNum5 +- function: TargetGroin + type: State + key: NumpadNum5 + mod1: NumpadNum5 - function: TargetLeftArm type: State key: NumpadNum6 diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings index 1be357b0cdb..20d8adb9ec1 100644 --- a/SpaceStation14.sln.DotSettings +++ b/SpaceStation14.sln.DotSettings @@ -707,6 +707,7 @@ public sealed partial class $CLASS$ : Shared$CLASS$ { True True True + True True True True @@ -753,6 +754,8 @@ public sealed partial class $CLASS$ : Shared$CLASS$ { True True True + True + True True True True