Generalize ResistanceSets into DamageModifierSets (#4619)

* generalize ResistanceSets into DamageModifierSets

* remove unneeded test prototype
This commit is contained in:
mirrorcult
2021-09-15 15:51:13 -07:00
committed by GitHub
parent cd6c2bb373
commit cc52ebb9b5
57 changed files with 131 additions and 112 deletions

View File

@@ -1,27 +1,22 @@
using System;
using System;
using System.Collections.Generic;
using Robust.Shared.Prototypes;
using Content.Shared.Damage.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
using Robust.Shared.ViewVariables;
namespace Content.Shared.Damage.Prototypes
namespace Content.Shared.Damage
{
/// <summary>
/// Prototype of damage resistance sets. Can be applied to <see cref="DamageSpecifier"/> using <see
/// cref="DamageSpecifier.ApplyResistanceSet(ResistanceSetPrototype)"/>. This can be done several times as the
/// A set of coefficients or flat modifiers to damage types.. Can be applied to <see cref="DamageSpecifier"/> using <see
/// cref="DamageSpecifier.ApplyModifierSet(DamageSpecifier, DamageModifierSet)"/>. This can be done several times as the
/// <see cref="DamageSpecifier"/> is passed to it's final target. By default the receiving <see cref="DamageableComponent"/>, will
/// also apply it's own <see cref="ResistanceSetPrototype"/>.
/// also apply it's own <see cref="DamageModifierSet"/>.
/// </summary>
[Prototype("resistanceSet")]
[DataDefinition]
[Serializable, NetSerializable]
public class ResistanceSetPrototype : IPrototype
public class DamageModifierSet
{
[ViewVariables]
[DataField("id", required: true)]
public string ID { get; } = default!;
[DataField("coefficients", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<float, DamageTypePrototype>))]
public Dictionary<string, float> Coefficients = new();

View File

@@ -41,7 +41,7 @@ namespace Content.Shared.Damage
{
if (_damageDict == null)
DeserializeDamage();
return _damageDict!;
return _damageDict!;
}
set => _damageDict = value;
}
@@ -120,7 +120,7 @@ namespace Content.Shared.Damage
// This can happen if deserialized before prototypes are loaded.
Logger.Error($"Unknown damage group given to DamageSpecifier: {entry.Key}");
continue;
}
}
// Simply distribute evenly (except for rounding).
// We do this by reducing remaining the # of types and damage every loop.
@@ -141,12 +141,12 @@ namespace Content.Shared.Damage
}
/// <summary>
/// Reduce (or increase) damages by applying a resistance set.
/// Reduce (or increase) damages by applying a damage modifier set.
/// </summary>
/// <remarks>
/// Only applies resistance to a damage type if it is dealing damage, not healing.
/// </remarks>
public static DamageSpecifier ApplyResistanceSet(DamageSpecifier damageSpec, ResistanceSetPrototype resistanceSet)
public static DamageSpecifier ApplyModifierSet(DamageSpecifier damageSpec, DamageModifierSet modifierSet)
{
// Make a copy of the given data. Don't modify the one passed to this function. I did this before, and weapons became
// duller as you hit walls. Neat, but not intended. And confusing, when you realize your fists don't work no
@@ -159,9 +159,9 @@ namespace Content.Shared.Damage
float newValue = entry.Value;
if (resistanceSet.FlatReduction.TryGetValue(entry.Key, out var reduction))
if (modifierSet.FlatReduction.TryGetValue(entry.Key, out var reduction))
{
newValue -= reduction;
newValue -= reduction;
if (newValue <= 0)
{
// flat reductions cannot heal you
@@ -170,7 +170,7 @@ namespace Content.Shared.Damage
}
}
if (resistanceSet.Coefficients.TryGetValue(entry.Key, out var coefficient))
if (modifierSet.Coefficients.TryGetValue(entry.Key, out var coefficient))
{
// negative coefficients **can** heal you.
newValue = MathF.Round(newValue*coefficient, MidpointRounding.AwayFromZero);

View File

@@ -19,7 +19,7 @@ namespace Content.Shared.Damage
/// </summary>
/// <remarks>
/// The supported damage types are specified using a <see cref="DamageContainerPrototype"/>s. DamageContainers
/// may also have resistances to certain damage types, defined via a <see cref="ResistanceSetPrototype"/>.
/// may also have resistances to certain damage types, defined via a <see cref="DamageModifierSetPrototype"/>.
/// </remarks>
[RegisterComponent]
[NetworkedComponent()]
@@ -36,12 +36,16 @@ namespace Content.Shared.Damage
public string? DamageContainerID;
/// <summary>
/// This <see cref="ResistanceSetPrototype"/> will be applied to any damage that is dealt to this container,
/// This <see cref="DamageModifierSetPrototype"/> will be applied to any damage that is dealt to this container,
/// unless the damage explicitly ignores resistances.
/// </summary>
/// <remarks>
/// Though DamageModifierSets can be deserialized directly, we only want to use the prototype version here
/// to reduce duplication.
/// </remarks>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("resistanceSet", customTypeSerializer: typeof(PrototypeIdSerializer<ResistanceSetPrototype>))]
public string? ResistanceSetID;
[DataField("damageModifierSet", customTypeSerializer: typeof(PrototypeIdSerializer<DamageModifierSetPrototype>))]
public string? DamageModifierSetId;
/// <summary>
/// All the damage information is stored in this <see cref="DamageSpecifier"/>.
@@ -116,14 +120,14 @@ namespace Content.Shared.Damage
public class DamageableComponentState : ComponentState
{
public readonly Dictionary<string, int> DamageDict;
public readonly string? ResistanceSetID;
public readonly string? ModifierSetId;
public DamageableComponentState(
Dictionary<string, int> damageDict,
string? resistanceSetID)
string? modifierSetId)
{
DamageDict = damageDict;
ResistanceSetID = resistanceSetID;
ModifierSetId = modifierSetId;
}
}
}

View File

@@ -25,7 +25,7 @@ namespace Content.Shared.Damage
/// </summary>
private void DamageableInit(EntityUid uid, DamageableComponent component, ComponentInit _)
{
if (component.DamageContainerID != null &&
if (component.DamageContainerID != null &&
_prototypeManager.TryIndex<DamageContainerPrototype>(component.DamageContainerID,
out var damageContainerPrototype))
{
@@ -118,11 +118,11 @@ namespace Content.Shared.Damage
}
// Apply resistances
if (!ignoreResistances && damageable.ResistanceSetID != null)
if (!ignoreResistances && damageable.DamageModifierSetId != null)
{
if (_prototypeManager.TryIndex<ResistanceSetPrototype>(damageable.ResistanceSetID, out var resistanceSet))
if (_prototypeManager.TryIndex<DamageModifierSetPrototype>(damageable.DamageModifierSetId, out var modifierSet))
{
damage = DamageSpecifier.ApplyResistanceSet(damage, resistanceSet);
damage = DamageSpecifier.ApplyModifierSet(damage, modifierSet);
}
if (damage.Empty)
@@ -174,7 +174,7 @@ namespace Content.Shared.Damage
private void DamageableGetState(EntityUid uid, DamageableComponent component, ref ComponentGetState args)
{
args.State = new DamageableComponentState(component.Damage.DamageDict, component.ResistanceSetID);
args.State = new DamageableComponentState(component.Damage.DamageDict, component.DamageModifierSetId);
}
private void DamageableHandleState(EntityUid uid, DamageableComponent component, ref ComponentHandleState args)
@@ -184,7 +184,7 @@ namespace Content.Shared.Damage
return;
}
component.ResistanceSetID = state.ResistanceSetID;
component.DamageModifierSetId = state.ModifierSetId;
// Has the damage actually changed?
DamageSpecifier newDamage = new() { DamageDict = state.DamageDict };
@@ -202,7 +202,7 @@ namespace Content.Shared.Damage
public class DamageChangedEvent : EntityEventArgs
{
/// <summary>
/// This is the component whose damage was changed.
/// This is the component whose damage was changed.
/// </summary>
/// <remarks>
/// Given that nearly every component that cares about a change in the damage, needs to know the

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
using Robust.Shared.ViewVariables;
namespace Content.Shared.Damage.Prototypes
{
/// <summary>
/// A version of DamageModifierSet that can be serialized as a prototype, but is functionally identical.
/// </summary>
/// <remarks>
/// Done to avoid removing the 'required' tag on the ID and passing around a 'prototype' when we really
/// just want normal data to be deserialized.
/// </remarks>
[Prototype("damageModifierSet")]
public class DamageModifierSetPrototype : DamageModifierSet, IPrototype
{
[ViewVariables]
[DataField("id", required: true)]
public string ID { get; } = default!;
}
}