This commit is contained in:
Princess Cheeseballs 2026-06-01 19:50:53 -07:00
parent 07b54e056e
commit 5dfd4e57f3
6 changed files with 88 additions and 31 deletions

View file

@ -230,7 +230,11 @@ public sealed partial class ExplosionSystem
totalDamageTarget = _destructibleSystem.DestroyedAt(uid, destructible);
}
if (totalDamageTarget == FixedPoint2.MaxValue || !_injurableQuery.TryGetComponent(uid, out var injurable))
// We are assuming airtight entities don't need to relay since they shouldn't have inventories.
var modifiers = _damageableSystem.GetDamageModifierSet(uid);
var explosionComp = _explosionResistanceQuery.CompOrNull(uid);
if (totalDamageTarget == FixedPoint2.MaxValue || !_injurableQuery.TryComp(uid, out var injurable))
{
for (var i = 0; i < explosionTolerance.Length; i++)
{
@ -254,30 +258,89 @@ public sealed partial class ExplosionSystem
// evaluate the damage that this damage type would do to this entity
var damagePerIntensity = FixedPoint2.Zero;
// Create a dictionary of intensity thresholds which dictates when damagePerIntensity increases!
var damageThresholds = new SortedDictionary<FixedPoint2, FixedPoint2>();
foreach (var (type, value) in explosionType.DamagePerIntensity.DamageDict)
{
if (!_damageableSystem.CanBeDamagedBy((uid, injurable), type))
continue;
// TODO EXPLOSION SYSTEM
// add a variant of the event that gets raised once, instead of once per prototype.
// Or better yet, just calculate this manually w/o the event.
// The event mainly exists for indirect resistances via things like inventory & clothing
// But this shouldn't matter for airtight entities.
var ev = new GetExplosionResistanceEvent(explosionType.ID);
RaiseLocalEvent(uid, ref ev);
var modifier = mod;
if (explosionComp != null)
{
modifier *= explosionComp.DamageCoefficient;
if (explosionComp.Modifiers.TryGetValue(explosionType.ID, out var typeMod))
modifier *= typeMod;
}
damagePerIntensity += value * mod * Math.Max(0, ev.DamageCoefficient);
if (modifiers != null)
{
if (modifiers.Coefficients.TryGetValue(type, out var armorMod))
modifier *= armorMod;
if (modifiers.FlatReduction.TryGetValue(type, out var flat))
{
if (flat > 0)
{
// If the flat modifier is reducing damage, we cache the extra damage per intensity for later!
var intensity = flat / value;
var damage = damageThresholds.GetValueOrDefault(intensity);
damageThresholds[intensity] = value * Math.Max(0, modifier) + damage;
continue;
}
}
}
damagePerIntensity += value * Math.Max(0, modifier);
}
var toleranceValue = damagePerIntensity > 0
? (float) ((totalDamageTarget - _damageableSystem.GetTotalDamage(uid)) / damagePerIntensity)
: ToleranceValues.Invulnerable;
explosionTolerance[index] = toleranceValue;
explosionTolerance[index] += GetExplosionTolerance(uid, totalDamageTarget, damagePerIntensity, damageThresholds);
}
}
private FixedPoint2 GetExplosionTolerance(EntityUid uid,
FixedPoint2 totalDamageTarget,
FixedPoint2 damagePerIntensity,
SortedDictionary<FixedPoint2, FixedPoint2> damageThresholds)
{
return GetExplosionTolerance(totalDamageTarget - _damageableSystem.GetTotalDamage(uid),
damagePerIntensity,
damageThresholds);
}
private FixedPoint2 GetExplosionTolerance(FixedPoint2 damageTarget,
FixedPoint2 damagePerIntensity,
SortedDictionary<FixedPoint2, FixedPoint2> damageThresholds)
{
var tolerance = damagePerIntensity > 0 ? damageTarget / damagePerIntensity : ToleranceValues.Invulnerable;
var prevIntensity = FixedPoint2.Zero;
/*
* Calculated through a pretty simple equation which relies on this dictionary being sorted.
* We precalculate the intensity at which an explosion's damage type exceeds the flat reduction of an entity's armor
* That is done above and stored in our `damageThresholds` SortedDictionary. If you can find a more mem efficient way to do this be my guest,
* but these values *have* to be sorted.
*/
foreach (var (intensity, damage) in damageThresholds)
{
// Check if the object would break before hitting this threshold, if so, return the current tolerance value
if (intensity > tolerance)
return tolerance;
/*
* If the object breaks after this threshold, reduce the HP left by the amount of HP lost between the last flat reduction and this one
* Then adjust our damagePerIntensity and new tolerance values accordingly.
* Lastly store this intensity value so we can calculate the delta next loop.
*/
damageTarget -= (intensity - prevIntensity) * damagePerIntensity;
damagePerIntensity += damage;
tolerance = intensity + damageTarget / damagePerIntensity;
prevIntensity = intensity;
}
return tolerance;
}
private void OnAirtightGridRemoved(EntityUid entity)
{
if (!TryComp(entity, out ExplosionAirtightGridComponent? airtightGrid))

View file

@ -452,7 +452,7 @@ public sealed partial class ExplosionSystem
continue;
// TODO EXPLOSIONS turn explosions into entities, and pass the the entity in as the damage origin.
_damageableSystem.ChangeDamage((entity, damageable), damage, ignoreResistances: true);
_damageableSystem.ChangeDamage((entity, damageable), damage);
if (_actorQuery.HasComp(entity))
{

View file

@ -6,6 +6,7 @@ using Content.Server.Atmos.EntitySystems;
using Content.Server.Destructible;
using Content.Server.NodeContainer.EntitySystems;
using Content.Server.NPC.Pathfinding;
using Content.Shared.Armor;
using Content.Shared.Atmos.Components;
using Content.Shared.Camera;
using Content.Shared.CCVar;
@ -60,6 +61,7 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
[Dependency] private EntityQuery<ActorComponent> _actorQuery = default!;
[Dependency] private EntityQuery<DestructibleComponent> _destructibleQuery = default!;
[Dependency] private EntityQuery<DamageableComponent> _damageableQuery = default!;
[Dependency] private EntityQuery<ExplosionResistanceComponent> _explosionResistanceQuery = default!;
[Dependency] private EntityQuery<InjurableComponent> _injurableQuery = default!;
[Dependency] private EntityQuery<AirtightComponent> _airtightQuery = default!;
[Dependency] private EntityQuery<TileHistoryComponent> _tileHistoryQuery = default!;

View file

@ -1,2 +1,2 @@
explosion-resistance-coefficient-value = - [color=orange]Explosion[/color] damage reduced by [color=lightblue]{$value}%[/color].
explosion-resistance-coefficient-value = - [color=orange]Explosion[/color] damage reduced by an additional [color=lightblue]{$value}%[/color].
explosion-resistance-contents-coefficient-value = - [color=orange]Explosion[/color] damage [color=white]to contents[/color] reduced by [color=lightblue]{$value}%[/color].

View file

@ -114,8 +114,6 @@
Piercing: 0.6
Heat: 0.5
Caustic: 0.9
- type: ExplosionResistance
damageCoefficient: 0.65
- type: GroupExamine
- type: entity
@ -184,8 +182,6 @@
Heat: 0.3
Radiation: 0.5
Caustic: 0.5
- type: ExplosionResistance
damageCoefficient: 0.5
- type: FireProtection
reduction: 0.85
- type: StaticPrice
@ -235,8 +231,6 @@
Piercing: 0.35
Heat: 0.35
Caustic: 0.5
- type: ExplosionResistance
damageCoefficient: 0.35
- type: StaminaResistance # do not add these to other equipment or mobs, we don't want to microbalance these everywhere
damageCoefficient: 0.45
- type: ClothingSpeedModifier
@ -422,7 +416,7 @@
sprintModifier: 0.65
- type: HeldSpeedModifier
- type: ExplosionResistance
damageCoefficient: 0.5
damageCoefficient: 0.75
- type: GroupExamine
- type: ProtectedFromStepTriggers
slots: WITHOUT_POCKET
@ -448,7 +442,7 @@
sprintModifier: 0.8
- type: HeldSpeedModifier
- type: ExplosionResistance
damageCoefficient: 0.4
damageCoefficient: 0.6
- type: GroupExamine
- type: Construction
graph: BoneArmor

View file

@ -159,7 +159,7 @@
highPressureMultiplier: 0.5
lowPressureMultiplier: 1000
- type: ExplosionResistance
damageCoefficient: 0.3
damageCoefficient: 0.5
- type: Armor
modifiers:
coefficients:
@ -228,7 +228,7 @@
highPressureMultiplier: 0.5
lowPressureMultiplier: 1000
- type: ExplosionResistance
damageCoefficient: 0.4
damageCoefficient: 0.5
- type: Armor
modifiers:
coefficients:
@ -290,7 +290,7 @@
highPressureMultiplier: 0.5
lowPressureMultiplier: 1000
- type: ExplosionResistance
damageCoefficient: 0.4
damageCoefficient: 0.5
- type: Armor
modifiers:
coefficients:
@ -321,7 +321,7 @@
highPressureMultiplier: 0.02
lowPressureMultiplier: 1000
- type: ExplosionResistance
damageCoefficient: 0.5
damageCoefficient: 0.7
- type: Armor
modifiers:
coefficients:
@ -601,7 +601,7 @@
highPressureMultiplier: 0.02
lowPressureMultiplier: 1000
- type: ExplosionResistance
damageCoefficient: 0.2
damageCoefficient: 0.3
- type: FireProtection
reduction: 0.8
- type: StaminaResistance # do not add these to other equipment or mobs, we don't want to microbalance these everywhere
@ -683,8 +683,6 @@
- type: PressureProtection
highPressureMultiplier: 0.2
lowPressureMultiplier: 1000
- type: ExplosionResistance
damageCoefficient: 0.3
# - type: StaminaResistance # Should not have stamina resistance, this is purely so people know it was not forgotten.
- type: Armor
modifiers: