Revert "Refactor Damage to use Protoypes (#4262)"

This reverts commit 20bf5739a9.
This commit is contained in:
Silver
2021-08-24 00:50:39 -06:00
committed by Silver
parent 20bf5739a9
commit e708091518
121 changed files with 711 additions and 10237 deletions

View File

@@ -18,242 +18,67 @@ namespace Content.Shared.Damage.Components
{
/// <summary>
/// Component that allows attached entities to take damage.
/// This basic version never dies (thus can take an indefinite amount of damage).
/// </summary>
/// <remarks>
/// The supported damage types are specified using a <see cref="DamageContainerPrototype"/>s. DamageContainers
/// are effectively a dictionary of damage types and damage numbers, along with functions to modify them. Damage
/// groups are collections of damage types. A damage group is 'applicable' to a damageable component if it
/// supports at least one damage type in that group. A subset of these groups may be 'fully supported' when every
/// member of the group is supported by the container. This basic version never dies (thus can take an
/// indefinite amount of damage).
/// </remarks>
[RegisterComponent]
[ComponentReference(typeof(IDamageableComponent))]
[NetworkedComponent()]
public class DamageableComponent : Component, IDamageableComponent, IRadiationAct, ISerializationHooks
{
<<<<<<< refs/remotes/origin/master
<<<<<<< refs/remotes/origin/master
=======
=======
>>>>>>> fix a few bugs
public override string Name => "Damageable";
public override uint? NetID => ContentNetIDs.DAMAGEABLE;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
<<<<<<< refs/remotes/origin/master
>>>>>>> update damagecomponent across shared and server
=======
>>>>>>> Fix Merge issues
// TODO define these in yaml?
public const string DefaultResistanceSet = "defaultResistances";
public const string DefaultDamageContainer = "metallicDamageContainer";
=======
/// <summary>
/// The main damage dictionary. All the damage information is stored in this dictionary with <see cref="DamageTypePrototype"/> keys.
/// </summary>
private Dictionary<DamageTypePrototype, int> _damageDict = new();
>>>>>>> Refactor damageablecomponent update (#4406)
<<<<<<< refs/remotes/origin/master
private readonly Dictionary<DamageType, int> _damageList = DamageTypeExtensions.ToNewDictionary();
[DataField("resistances")] public string ResistanceSetId = DefaultResistanceSet;
=======
[DataField("resistances")]
public string ResistanceSetId { get; set; } = "defaultResistances";
[ViewVariables] public ResistanceSet Resistances { get; set; } = new();
>>>>>>> Merge fixes
// TODO DAMAGE Use as default values, specify overrides in a separate property through yaml for better (de)serialization
<<<<<<< refs/remotes/origin/master
[ViewVariables] [DataField("damageContainer")] public string DamageContainerId { get; set; } = DefaultDamageContainer;
=======
/// <summary>
/// The main damage dictionary. All the damage information is stored in this dictionary with <see cref="DamageTypePrototype"/> keys.
/// </summary>
private Dictionary<DamageTypePrototype, int> _damageDict = new();
[DataField("resistances")]
public string ResistanceSetId { get; set; } = "defaultResistances";
>>>>>>> refactor-damageablecomponent
[ViewVariables] public ResistanceSet Resistances { get; set; } = new();
=======
[ViewVariables]
[DataField("damageContainer")]
<<<<<<< refs/remotes/origin/master
public string DamageContainerId { get; set; } = DefaultDamageContainer;
>>>>>>> fix a few bugs
// TODO DAMAGE Use as default values, specify overrides in a separate property through yaml for better (de)serialization
[ViewVariables]
[DataField("damageContainer")]
public string DamageContainerId { get; set; } = "metallicDamageContainer";
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
[ViewVariables] public IReadOnlyDictionary<DamageClass, int> DamageClasses => _damageList.ToClassDictionary();
=======
// TODO DAMAGE Cache this
// When moving logic from damageableComponent --> Damage System, make damageSystem update these on damage change.
[ViewVariables] public int TotalDamage => _damageDict.Values.Sum();
[ViewVariables] public IReadOnlyDictionary<DamageTypePrototype, int> GetDamagePerType => _damageDict;
[ViewVariables] public IReadOnlyDictionary<DamageGroupPrototype, int> GetDamagePerApplicableGroup => DamageTypeDictToDamageGroupDict(_damageDict, ApplicableDamageGroups);
[ViewVariables] public IReadOnlyDictionary<DamageGroupPrototype, int> GetDamagePerFullySupportedGroup => DamageTypeDictToDamageGroupDict(_damageDict, FullySupportedDamageGroups);
>>>>>>> refactor-damageablecomponent
[ViewVariables] public int TotalDamage => _damageList.Values.Sum();
// Whenever sending over network, also need a <string, int> dictionary
// TODO DAMAGE MAYBE Cache this?
public IReadOnlyDictionary<string, int> GetDamagePerApplicableGroupIDs => ConvertDictKeysToIDs(GetDamagePerApplicableGroup);
public IReadOnlyDictionary<string, int> GetDamagePerFullySupportedGroupIDs => ConvertDictKeysToIDs(GetDamagePerFullySupportedGroup);
public IReadOnlyDictionary<string, int> GetDamagePerTypeIDs => ConvertDictKeysToIDs(_damageDict);
[ViewVariables] public IReadOnlyDictionary<DamageClass, int> DamageClasses => _damageList.ToClassDictionary();
// TODO PROTOTYPE Replace these datafield variables with prototype references, once they are supported.
// Also requires appropriate changes in OnExplosion() and RadiationAct()
[ViewVariables]
[DataField("radiationDamageTypes")]
public List<string> RadiationDamageTypeIDs { get; set; } = new() {"Radiation"};
[ViewVariables]
[DataField("explosionDamageTypes")]
public List<string> ExplosionDamageTypeIDs { get; set; } = new() { "Piercing", "Heat" };
[ViewVariables] public IReadOnlyDictionary<DamageType, int> DamageTypes => _damageList;
public HashSet<DamageGroupPrototype> ApplicableDamageGroups { get; } = new();
[ViewVariables] public HashSet<DamageType> SupportedTypes { get; } = new();
[ViewVariables] public HashSet<DamageClass> SupportedClasses { get; } = new();
<<<<<<< HEAD
public bool SupportsDamageClass(DamageClass @class)
{
return SupportedClasses.Contains(@class);
=======
public HashSet<DamageGroupPrototype> SupportedGroups { get; } = new();
=======
public string DamageContainerId { get; set; } = "metallicDamageContainer";
// TODO DAMAGE Cache this
// When moving logic from damageableComponent --> Damage System, make damageSystem update these on damage change.
[ViewVariables] public int TotalDamage => _damageDict.Values.Sum();
[ViewVariables] public IReadOnlyDictionary<DamageTypePrototype, int> GetDamagePerType => _damageDict;
[ViewVariables] public IReadOnlyDictionary<DamageGroupPrototype, int> GetDamagePerApplicableGroup => DamageTypeDictToDamageGroupDict(_damageDict, ApplicableDamageGroups);
[ViewVariables] public IReadOnlyDictionary<DamageGroupPrototype, int> GetDamagePerFullySupportedGroup => DamageTypeDictToDamageGroupDict(_damageDict, FullySupportedDamageGroups);
// Whenever sending over network, also need a <string, int> dictionary
// TODO DAMAGE MAYBE Cache this?
public IReadOnlyDictionary<string, int> GetDamagePerApplicableGroupIDs => ConvertDictKeysToIDs(GetDamagePerApplicableGroup);
public IReadOnlyDictionary<string, int> GetDamagePerFullySupportedGroupIDs => ConvertDictKeysToIDs(GetDamagePerFullySupportedGroup);
public IReadOnlyDictionary<string, int> GetDamagePerTypeIDs => ConvertDictKeysToIDs(_damageDict);
// TODO PROTOTYPE Replace these datafield variables with prototype references, once they are supported.
// Also requires appropriate changes in OnExplosion() and RadiationAct()
[ViewVariables]
[DataField("radiationDamageTypes")]
public List<string> RadiationDamageTypeIDs { get; set; } = new() {"Radiation"};
[ViewVariables]
[DataField("explosionDamageTypes")]
public List<string> ExplosionDamageTypeIDs { get; set; } = new() { "Piercing", "Heat" };
public HashSet<DamageGroupPrototype> ApplicableDamageGroups { get; } = new();
>>>>>>> Refactor damageablecomponent update (#4406)
public HashSet<DamageGroupPrototype> FullySupportedDamageGroups { get; } = new();
public HashSet<DamageTypePrototype> SupportedDamageTypes { get; } = new();
<<<<<<< refs/remotes/origin/master
public bool SupportsDamageClass(DamageGroupPrototype damageGroup)
{
return SupportedGroups.Contains(damageGroup);
>>>>>>> Merge fixes
}
=======
public HashSet<DamageGroupPrototype> FullySupportedDamageGroups { get; } = new();
>>>>>>> refactor-damageablecomponent
public HashSet<DamageTypePrototype> SupportedDamageTypes { get; } = new();
public bool SupportsDamageType(DamageType type)
{
return SupportedTypes.Contains(type);
}
=======
>>>>>>> update damagecomponent across shared and server
protected override void Initialize()
{
base.Initialize();
<<<<<<< refs/remotes/origin/master
<<<<<<< refs/remotes/origin/master
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
=======
>>>>>>> refactor-damageablecomponent
// TODO DAMAGE Serialize damage done and resistance changes
var damageContainerPrototype = _prototypeManager.Index<DamageContainerPrototype>(DamageContainerId);
var damagePrototype = prototypeManager.Index<DamageContainerPrototype>(DamageContainerId);
ApplicableDamageGroups.Clear();
FullySupportedDamageGroups.Clear();
SupportedDamageTypes.Clear();
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
SupportedClasses.Clear();
SupportedTypes.Clear();
=======
=======
>>>>>>> fix a few bugs
_prototypeManager = IoCManager.Resolve<IPrototypeManager>();
=======
>>>>>>> Refactor damageablecomponent update (#4406)
// TODO DAMAGE Serialize damage done and resistance changes
var damageContainerPrototype = _prototypeManager.Index<DamageContainerPrototype>(DamageContainerId);
>>>>>>> update damagecomponent across shared and server
<<<<<<< refs/remotes/origin/master
DamageContainerId = damagePrototype.ID;
SupportedClasses.UnionWith(damagePrototype.SupportedClasses);
SupportedTypes.UnionWith(damagePrototype.SupportedTypes);
=======
SupportedGroups.Clear();
SupportedTypes.Clear();
=======
ApplicableDamageGroups.Clear();
FullySupportedDamageGroups.Clear();
SupportedDamageTypes.Clear();
>>>>>>> Refactor damageablecomponent update (#4406)
//Get Damage groups/types from the DamageContainerPrototype.
DamageContainerId = damageContainerPrototype.ID;
<<<<<<< refs/remotes/origin/master
SupportedGroups.UnionWith(damageContainerPrototype.SupportedDamageGroups);
SupportedTypes.UnionWith(damageContainerPrototype.SupportedDamageTypes);
>>>>>>> Merge fixes
=======
ApplicableDamageGroups.UnionWith(damageContainerPrototype.ApplicableDamageGroups);
FullySupportedDamageGroups.UnionWith(damageContainerPrototype.FullySupportedDamageGroups);
SupportedDamageTypes.UnionWith(damageContainerPrototype.SupportedDamageTypes);
>>>>>>> Refactor damageablecomponent update (#4406)
=======
//Get Damage groups/types from the DamageContainerPrototype.
DamageContainerId = damageContainerPrototype.ID;
ApplicableDamageGroups.UnionWith(damageContainerPrototype.ApplicableDamageGroups);
FullySupportedDamageGroups.UnionWith(damageContainerPrototype.FullySupportedDamageGroups);
SupportedDamageTypes.UnionWith(damageContainerPrototype.SupportedDamageTypes);
>>>>>>> refactor-damageablecomponent
//initialize damage dictionary 0 damage
_damageDict = new(SupportedDamageTypes.Count);
foreach (var type in SupportedDamageTypes)
{
_damageDict.Add(type, 0);
}
Resistances = new ResistanceSet(_prototypeManager.Index<ResistanceSetPrototype>(ResistanceSetId));
var resistancePrototype = prototypeManager.Index<ResistanceSetPrototype>(ResistanceSetId);
Resistances = new ResistanceSet(resistancePrototype);
}
protected override void Startup()
@@ -263,25 +88,9 @@ namespace Content.Shared.Damage.Components
ForceHealthChangedEvent();
}
<<<<<<< refs/remotes/origin/master
<<<<<<< refs/remotes/origin/master
=======
public DamageTypePrototype GetDamageType(string ID)
{
return _prototypeManager.Index<DamageTypePrototype>(ID);
}
public DamageGroupPrototype GetDamageGroup(string ID)
{
return _prototypeManager.Index<DamageGroupPrototype>(ID);
}
>>>>>>> update damagecomponent across shared and server
=======
>>>>>>> Refactor damageablecomponent update (#4406)
public override ComponentState GetComponentState(ICommonSession player)
{
return new DamageableComponentState(GetDamagePerTypeIDs);
return new DamageableComponentState(_damageList);
}
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
@@ -293,104 +102,49 @@ namespace Content.Shared.Damage.Components
return;
}
_damageDict.Clear();
_damageList.Clear();
foreach (var (type, damage) in state.DamageDict)
foreach (var (type, damage) in state.DamageList)
{
_damageDict[_prototypeManager.Index<DamageTypePrototype>(type)] = damage;
_damageList[type] = damage;
}
}
public int GetDamage(DamageTypePrototype type)
public int GetDamage(DamageType type)
{
return GetDamagePerType.GetValueOrDefault(type);
return _damageList.GetValueOrDefault(type);
}
public bool TryGetDamage(DamageTypePrototype type, out int damage)
public bool TryGetDamage(DamageType type, out int damage)
{
return GetDamagePerType.TryGetValue(type, out damage);
return _damageList.TryGetValue(type, out damage);
}
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
public int GetDamage(DamageClass @class)
{
if (!SupportsDamageClass(@class))
{
return 0;
}
=======
public int GetDamage(DamageGroupPrototype group)
{
return GetDamagePerApplicableGroup.GetValueOrDefault(group);
}
>>>>>>> Refactor damageablecomponent update (#4406)
=======
public int GetDamage(DamageGroupPrototype group)
{
return GetDamagePerApplicableGroup.GetValueOrDefault(group);
}
>>>>>>> refactor-damageablecomponent
public bool TryGetDamage(DamageGroupPrototype group, out int damage)
{
return GetDamagePerApplicableGroup.TryGetValue(group, out damage);
}
var damage = 0;
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
foreach (var type in @class.ToTypes())
{
damage += GetDamage(type);
}
=======
=======
>>>>>>> refactor-damageablecomponent
public bool IsApplicableDamageGroup(DamageGroupPrototype group)
{
return ApplicableDamageGroups.Contains(group);
return damage;
}
public bool IsFullySupportedDamageGroup(DamageGroupPrototype group)
{
return FullySupportedDamageGroups.Contains(group);
<<<<<<< HEAD
=======
}
public bool IsSupportedDamageType(DamageTypePrototype type)
{
return SupportedDamageTypes.Contains(type);
>>>>>>> refactor-damageablecomponent
}
>>>>>>> Refactor damageablecomponent update (#4406)
<<<<<<< HEAD
public bool IsSupportedDamageType(DamageTypePrototype type)
{
return SupportedDamageTypes.Contains(type);
}
<<<<<<< refs/remotes/origin/master
public bool TryGetDamage(DamageClass @class, out int damage)
{
if (!SupportsDamageClass(@class))
=======
public bool TrySetDamage(DamageGroupPrototype group, int newValue)
{
if (!ApplicableDamageGroups.Contains(group))
>>>>>>> Refactor damageablecomponent update (#4406)
=======
public bool TrySetDamage(DamageGroupPrototype group, int newValue)
{
if (!ApplicableDamageGroups.Contains(group))
>>>>>>> refactor-damageablecomponent
{
damage = 0;
return false;
}
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
damage = GetDamage(@class);
return true;
}
@@ -402,90 +156,44 @@ namespace Content.Shared.Damage.Components
/// True if successful, false if this container does not support that type.
/// </returns>
public bool TrySetDamage(DamageType type, int newValue)
=======
if (newValue < 0)
{
// invalid value
return false;
}
foreach (var type in group.DamageTypes)
{
TrySetDamage(type, newValue);
}
return true;
}
public bool TrySetAllDamage(int newValue)
>>>>>>> Refactor damageablecomponent update (#4406)
=======
if (newValue < 0)
{
// invalid value
return false;
}
foreach (var type in group.DamageTypes)
{
TrySetDamage(type, newValue);
}
return true;
}
public bool TrySetAllDamage(int newValue)
>>>>>>> refactor-damageablecomponent
{
if (newValue < 0)
{
// invalid value
return false;
}
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
<<<<<<< refs/remotes/origin/master
var damageClass = type.ToClass();
if (SupportedClasses.Contains(damageClass))
=======
if (SupportedTypes.Contains(type))
>>>>>>> Merge fixes
=======
foreach (var type in SupportedDamageTypes)
>>>>>>> Refactor damageablecomponent update (#4406)
=======
foreach (var type in SupportedDamageTypes)
>>>>>>> refactor-damageablecomponent
{
TrySetDamage(type, newValue);
var old = _damageList[type] = newValue;
_damageList[type] = newValue;
var delta = newValue - old;
var datum = new DamageChangeData(type, newValue, delta);
var data = new List<DamageChangeData> {datum};
OnHealthChanged(data);
return true;
}
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
return false;
}
public void Heal(DamageType type)
{
SetDamage(type, 0);
=======
return true;
>>>>>>> Refactor damageablecomponent update (#4406)
=======
return true;
>>>>>>> refactor-damageablecomponent
}
public bool TryChangeDamage(DamageTypePrototype type, int amount, bool ignoreDamageResistances = false)
public void Heal()
{
// Check if damage type is supported, and get the current value if it is.
if (!GetDamagePerType.TryGetValue(type, out var current))
foreach (var type in SupportedTypes)
{
return false;
Heal(type);
}
}
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
public bool ChangeDamage(
DamageType type,
int amount,
@@ -494,19 +202,13 @@ namespace Content.Shared.Damage.Components
DamageChangeParams? extraParams = null)
{
if (!SupportsDamageType(type))
=======
if (amount == 0)
>>>>>>> Refactor damageablecomponent update (#4406)
=======
if (amount == 0)
>>>>>>> refactor-damageablecomponent
{
return false;
}
// Apply resistances (does nothing if amount<0)
var finalDamage = amount;
if (!ignoreDamageResistances)
if (!ignoreResistances)
{
finalDamage = Resistances.CalculateDamage(type, amount);
}
@@ -514,23 +216,24 @@ namespace Content.Shared.Damage.Components
if (finalDamage == 0)
return false;
// Are we healing below zero?
if (!_damageList.TryGetValue(type, out var current))
{
return false;
}
if (current + finalDamage < 0)
{
if (current == 0)
// Damage type is supported, but there is nothing to do
return false;
// Cap healing down to zero
_damageDict[type] = 0;
_damageList[type] = 0;
finalDamage = -current;
}
else
{
_damageDict[type] = current + finalDamage;
_damageList[type] = current + finalDamage;
}
current = _damageDict[type];
current = _damageList[type];
var datum = new DamageChangeData(type, current, finalDamage);
var data = new List<DamageChangeData> {datum};
@@ -540,8 +243,6 @@ namespace Content.Shared.Damage.Components
return true;
}
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
public bool ChangeDamage(DamageClass @class, int amount, bool ignoreResistances,
IEntity? source = null,
DamageChangeParams? extraParams = null)
@@ -551,149 +252,98 @@ namespace Content.Shared.Damage.Components
return false;
}
<<<<<<< refs/remotes/origin/master
var types = @class.ToTypes();
=======
var types = damageGroup.DamageTypes.ToArray();
>>>>>>> Merge fixes
=======
public bool TryChangeDamage(DamageGroupPrototype group, int amount, bool ignoreDamageResistances = false)
{
var types = group.DamageTypes.ToArray();
>>>>>>> Refactor damageablecomponent update (#4406)
=======
public bool TryChangeDamage(DamageGroupPrototype group, int amount, bool ignoreDamageResistances = false)
{
var types = group.DamageTypes.ToArray();
>>>>>>> refactor-damageablecomponent
if (amount < 0)
{
// We are Healing. Keep track of how much we can hand out (with a better var name for readability).
var availableHealing = -amount;
// Changing multiple types is a bit more complicated. Might be a better way (formula?) to do this,
// but essentially just loops between each damage category until all healing is used up.
var healingLeft = -amount;
var healThisCycle = 1;
// Get total group damage.
var damageToHeal = GetDamagePerApplicableGroup[group];
<<<<<<< HEAD
// Is there any damage to even heal?
if (damageToHeal == 0)
return false;
=======
// Is there any damage to even heal?
if (damageToHeal == 0)
return false;
>>>>>>> refactor-damageablecomponent
// If total healing is more than there is damage, just set to 0 and return.
if (damageToHeal <= availableHealing)
// While we have healing left...
while (healingLeft > 0 && healThisCycle != 0)
{
TrySetDamage(group, 0);
return true;
}
// Infinite loop fallback, if no healing was done in a cycle
// then exit
healThisCycle = 0;
// Partially heal each damage group
int healing, damage;
foreach (var type in types)
{
if (!_damageDict.TryGetValue(type, out damage))
int healPerType;
if (healingLeft < types.Count)
{
// Damage Type is not supported. Continue without reducing availableHealing
continue;
// Say we were to distribute 2 healing between 3
// this will distribute 1 to each (and stop after 2 are given)
healPerType = 1;
}
else
{
// Say we were to distribute 62 healing between 3
// this will distribute 20 to each, leaving 2 for next loop
healPerType = healingLeft / types.Count;
}
// Apply healing to the damage type. The healing amount may be zero if either damage==0, or if
// integer rounding made it zero (i.e., damage is small)
healing = (availableHealing * damage) / damageToHeal;
TryChangeDamage(type, -healing, ignoreDamageResistances);
// remove this damage type from the damage we consider for future loops, regardless of how much we
// actually healed this type.
damageToHeal -= damage;
availableHealing -= healing;
// If we now healed all the damage, exit. otherwise 1/0 and universe explodes.
if (damageToHeal == 0)
foreach (var type in types)
{
break;
var damage = GetDamage(type);
var healAmount = Math.Min(healingLeft, damage);
healAmount = Math.Min(healAmount, healPerType);
ChangeDamage(type, -healAmount, true);
healThisCycle += healAmount;
healingLeft -= healAmount;
}
}
// Damage type is supported, there was damage to heal, and resistances were ignored
// --> Damage must have changed
return true;
}
else if (amount > 0)
var damageLeft = amount;
while (damageLeft > 0)
{
// Resistances may result in no actual damage change. We need to keep track if any damage got through.
var damageChanged = false;
int damagePerType;
// We are adding damage. Keep track of how much we can dish out (with a better var name for readability).
var availableDamage = amount;
if (damageLeft < types.Count)
{
damagePerType = 1;
}
else
{
damagePerType = damageLeft / types.Count;
}
// How many damage types do we have to distribute over?.
var numberDamageTypes = types.Length;
// Apply damage to each damage group
int damage;
foreach (var type in types)
{
// Distribute the remaining damage over the remaining damage types.
damage = availableDamage / numberDamageTypes;
// Try apply the damage type. If damage type is not supported, this has no effect.
// We also use the return value to check whether any damage has changed
damageChanged = TryChangeDamage(type, damage, ignoreDamageResistances) || damageChanged;
// regardless of whether we dealt damage, reduce the amount to distribute.
availableDamage -= damage;
numberDamageTypes -= 1;
var damageAmount = Math.Min(damagePerType, damageLeft);
ChangeDamage(type, damageAmount, true);
damageLeft -= damageAmount;
}
return damageChanged;
}
// amount==0 no damage change.
return false;
return true;
}
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
<<<<<<< refs/remotes/origin/master
public bool SetDamage(DamageType type, int newValue, IEntity? source = null, DamageChangeParams? extraParams = null)
=======
public bool SetDamage(DamageTypePrototype type, int newValue, IEntity? source = null, DamageChangeParams? extraParams = null)
>>>>>>> Fix Merge issues
=======
public bool TrySetDamage(DamageTypePrototype type, int newValue)
>>>>>>> Refactor damageablecomponent update (#4406)
=======
public bool TrySetDamage(DamageTypePrototype type, int newValue)
>>>>>>> refactor-damageablecomponent
{
if (!_damageDict.TryGetValue(type, out var oldValue))
if (newValue >= TotalDamage)
{
return false;
}
if (newValue < 0)
{
// invalid value
return false;
}
if (oldValue == newValue)
if (!_damageList.ContainsKey(type))
{
// No health change.
// But we are trying to set, not trying to change.
return true;
return false;
}
_damageDict[type] = newValue;
var old = _damageList[type];
_damageList[type] = newValue;
var delta = newValue - oldValue;
var delta = newValue - old;
var datum = new DamageChangeData(type, 0, delta);
var data = new List<DamageChangeData> {datum};
@@ -706,7 +356,7 @@ namespace Content.Shared.Damage.Components
{
var data = new List<DamageChangeData>();
foreach (var type in SupportedDamageTypes)
foreach (var type in SupportedTypes)
{
var damage = GetDamage(type);
var datum = new DamageChangeData(type, damage, 0);
@@ -722,32 +372,6 @@ namespace Content.Shared.Damage.Components
OnHealthChanged(args);
}
<<<<<<< refs/remotes/origin/master
<<<<<<< refs/remotes/origin/master
=======
private IReadOnlyDictionary<DamageGroupPrototype, int> damageListToDamageGroup(IReadOnlyDictionary<DamageTypePrototype, int> damagelist)
{
var damageGroupDict = new Dictionary<DamageGroupPrototype, int>();
int damageGroupSumDamage = 0;
int damageTypeDamage = 0;
foreach (var damageGroup in SupportedGroups)
{
damageGroupSumDamage = 0;
foreach (var damageType in SupportedTypes)
{
damageTypeDamage = 0;
damagelist.TryGetValue(damageType, out damageTypeDamage);
damageGroupSumDamage += damageTypeDamage;
}
damageGroupDict.Add(damageGroup, damageGroupSumDamage);
}
return damageGroupDict;
}
>>>>>>> Merge fixes
=======
>>>>>>> Refactor damageablecomponent update (#4406)
protected virtual void OnHealthChanged(DamageChangedEventArgs e)
{
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, e);
@@ -758,25 +382,11 @@ namespace Content.Shared.Damage.Components
Dirty();
}
public void RadiationAct(float frameTime, SharedRadiationPulseComponent radiation)
void IRadiationAct.RadiationAct(float frameTime, SharedRadiationPulseComponent radiation)
{
var totalDamage = Math.Max((int)(frameTime * radiation.RadsPerSecond), 1);
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
ChangeDamage(DamageType.Radiation, totalDamage, false, radiation.Owner);
=======
=======
>>>>>>> refactor-damageablecomponent
foreach (var typeID in RadiationDamageTypeIDs)
{
TryChangeDamage(_prototypeManager.Index<DamageTypePrototype>(typeID), totalDamage);
}
<<<<<<< HEAD
>>>>>>> Refactor damageablecomponent update (#4406)
=======
>>>>>>> refactor-damageablecomponent
}
public void OnExplosion(ExplosionEventArgs eventArgs)
@@ -789,99 +399,19 @@ namespace Content.Shared.Damage.Components
_ => throw new ArgumentOutOfRangeException()
};
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
ChangeDamage(DamageType.Piercing, damage, false);
ChangeDamage(DamageType.Heat, damage, false);
=======
=======
>>>>>>> refactor-damageablecomponent
foreach (var typeID in ExplosionDamageTypeIDs)
{
TryChangeDamage(_prototypeManager.Index<DamageTypePrototype>(typeID), damage);
}
}
/// <summary>
/// Take a dictionary with <see cref="IPrototype"/> keys and return a dictionary using <see cref="IPrototype.ID"/> as keys
/// instead.
/// </summary>
/// <remarks>
/// Useful when sending damage type and group prototypes dictionaries over the network.
/// </remarks>
public static IReadOnlyDictionary<string, int>
ConvertDictKeysToIDs<TPrototype>(IReadOnlyDictionary<TPrototype, int> prototypeDict)
where TPrototype : IPrototype
{
Dictionary<string, int> idDict = new(prototypeDict.Count);
foreach (var entry in prototypeDict)
{
idDict.Add(entry.Key.ID, entry.Value);
}
return idDict;
<<<<<<< HEAD
>>>>>>> Refactor damageablecomponent update (#4406)
=======
>>>>>>> refactor-damageablecomponent
}
/// <summary>
/// Convert a dictionary with damage type keys to a dictionary of damage groups keys.
/// </summary>
/// <remarks>
/// Takes a dictionary with damage types as keys and integers as values, and an iterable list of damage
/// groups. Returns a dictionary with damage group keys, with values calculated by adding up the values for
/// each damage type in that group. If a damage type is associated with more than one supported damage
/// group, it will contribute to the total of each group. Conversely, some damage types may not contribute
/// to the new dictionary if their associated group(s) are not in given list of groups.
/// </remarks>
public static IReadOnlyDictionary<DamageGroupPrototype, int>
DamageTypeDictToDamageGroupDict(IReadOnlyDictionary<DamageTypePrototype, int> damageTypeDict, IEnumerable<DamageGroupPrototype> groupKeys)
{
var damageGroupDict = new Dictionary<DamageGroupPrototype, int>();
int damageGroupSumDamage, damageTypeDamage;
// iterate over the list of group keys for our new dictionary
foreach (var group in groupKeys)
{
// For each damage type in this group, add up the damage present in the given dictionary
damageGroupSumDamage = 0;
foreach (var type in group.DamageTypes)
{
// if the damage type is in the dictionary, add it's damage to the group total.
if (damageTypeDict.TryGetValue(type, out damageTypeDamage))
{
damageGroupSumDamage += damageTypeDamage;
}
}
damageGroupDict.Add(group, damageGroupSumDamage);
}
return damageGroupDict;
}
}
[Serializable, NetSerializable]
public class DamageableComponentState : ComponentState
{
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
public readonly Dictionary<DamageType, int> DamageList;
public DamageableComponentState(Dictionary<DamageType, int> damageList)
=======
public readonly IReadOnlyDictionary<string, int> DamageDict;
public DamageableComponentState(IReadOnlyDictionary<string, int> damageDict)
>>>>>>> Refactor damageablecomponent update (#4406)
=======
public readonly IReadOnlyDictionary<string, int> DamageDict;
public DamageableComponentState(IReadOnlyDictionary<string, int> damageDict)
>>>>>>> refactor-damageablecomponent
{
DamageDict = damageDict;
DamageList = damageList;
}
}
}

View File

@@ -8,212 +8,75 @@ namespace Content.Shared.Damage.Components
public interface IDamageableComponent : IComponent, IExAct
{
/// <summary>
/// The sum of all damages types in the DamageableComponent.
/// Sum of all damages taken.
/// </summary>
int TotalDamage { get; }
/// <summary>
/// Returns a dictionary of the damage in the container, indexed by applicable <see cref="DamageGroupPrototype"/>.
/// The amount of damage mapped by <see cref="DamageClass"/>.
/// </summary>
/// <remarks>
/// The values represent the sum of all damage in each group. If a supported damage type is a member of more than one group, it will contribute to each one.
/// Therefore, the sum of the values may be greater than the sum of the values in the dictionary returned by <see cref="GetDamagePerType"/>
/// </remarks>
IReadOnlyDictionary<DamageGroupPrototype, int> GetDamagePerApplicableGroup { get; }
IReadOnlyDictionary<DamageClass, int> DamageClasses { get; }
/// <summary>
/// Returns a dictionary of the damage in the container, indexed by fully supported instances of <see
/// cref="DamageGroupPrototype"/>.
/// The amount of damage mapped by <see cref="DamageType"/>.
/// </summary>
/// <remarks>
/// The values represent the sum of all damage in each group. As the damage container may have some damage
/// types that are not part of a fully supported damage group, the sum of the values may be less of the values
/// in the dictionary returned by <see cref="GetDamagePerType"/>. On the other hand, if a supported damage type
/// is a member of more than one group, it will contribute to each one. Therefore, the sum may also be greater
/// instead.
/// </remarks>
IReadOnlyDictionary<DamageGroupPrototype, int> GetDamagePerFullySupportedGroup { get; }
IReadOnlyDictionary<DamageType, int> DamageTypes { get; }
/// <summary>
/// Returns a dictionary of the damage in the container, indexed by <see cref="DamageTypePrototype"/>.
/// </summary>
IReadOnlyDictionary<DamageTypePrototype, int> GetDamagePerType { get; }
HashSet<DamageType> SupportedTypes { get; }
/// <summary>
/// Like <see cref="GetDamagePerApplicableGroup"/>, but indexed by <see cref="DamageGroupPrototype.ID"/>
/// </summary>
IReadOnlyDictionary<string, int> GetDamagePerApplicableGroupIDs { get; }
HashSet<DamageClass> SupportedClasses { get; }
/// <summary>
/// Like <see cref="GetDamagePerFullySupportedGroup"/>, but indexed by <see cref="DamageGroupPrototype.ID"/>
/// </summary>
IReadOnlyDictionary<string, int> GetDamagePerFullySupportedGroupIDs { get; }
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
bool SupportsDamageClass(DamageClass @class);
bool SupportsDamageType(DamageType type);
=======
/// <summary>
/// Like <see cref="GetDamagePerType"/>, but indexed by <see cref="DamageTypePrototype.ID"/>
/// </summary>
IReadOnlyDictionary<string, int> GetDamagePerTypeIDs { get; }
/// <summary>
/// Collection of damage types supported by this DamageableComponent.
/// </summary>
/// <remarks>
/// Each of these damage types is fully supported. If any of these damage types is a
/// member of a damage group, these groups are represented in <see cref="ApplicableDamageGroups"></see>
/// </remarks>
HashSet<DamageTypePrototype> SupportedDamageTypes { get; }
/// <summary>
/// Collection of damage groups that are fully supported by DamageableComponent.
/// </summary>
/// <remarks>
/// This describes what damage groups this damage container explicitly supports. It supports every damage type
/// contained in these damage groups. It may also support other damage types not in these groups. To see all
/// damage types <see cref="SupportedDamageTypes"/>, and to see all applicable damage groups <see
/// cref="ApplicableDamageGroups"/>.
/// </remarks>
HashSet<DamageGroupPrototype> FullySupportedDamageGroups { get; }
>>>>>>> Refactor damageablecomponent update (#4406)
/// <summary>
/// Collection of damage groups that could apply damage to this DamageableComponent.
/// </summary>
/// <remarks>
/// This describes what damage groups could have an effect on this damage container. However not every damage
/// group has to be fully supported. For example, the container may support ONLY the piercing damage type. It should
/// therefore be affected by instances of brute damage, but does not necessarily support blunt or slash damage.
/// For a list of supported damage types, see <see cref="SupportedDamageTypes"/>.
/// </remarks>
HashSet<DamageGroupPrototype> ApplicableDamageGroups { get; }
=======
/// <summary>
/// Like <see cref="GetDamagePerType"/>, but indexed by <see cref="DamageTypePrototype.ID"/>
/// </summary>
IReadOnlyDictionary<string, int> GetDamagePerTypeIDs { get; }
/// <summary>
/// Collection of damage types supported by this DamageableComponent.
/// </summary>
/// <remarks>
/// Each of these damage types is fully supported. If any of these damage types is a
/// member of a damage group, these groups are represented in <see cref="ApplicableDamageGroups"></see>
/// </remarks>
HashSet<DamageTypePrototype> SupportedDamageTypes { get; }
/// <summary>
/// Collection of damage groups that are fully supported by DamageableComponent.
/// </summary>
/// <remarks>
/// This describes what damage groups this damage container explicitly supports. It supports every damage type
/// contained in these damage groups. It may also support other damage types not in these groups. To see all
/// damage types <see cref="SupportedDamageTypes"/>, and to see all applicable damage groups <see
/// cref="ApplicableDamageGroups"/>.
/// </remarks>
HashSet<DamageGroupPrototype> FullySupportedDamageGroups { get; }
/// <summary>
/// Collection of damage groups that could apply damage to this DamageableComponent.
/// </summary>
/// <remarks>
/// This describes what damage groups could have an effect on this damage container. However not every damage
/// group has to be fully supported. For example, the container may support ONLY the piercing damage type. It should
/// therefore be affected by instances of brute damage, but does not necessarily support blunt or slash damage.
/// For a list of supported damage types, see <see cref="SupportedDamageTypes"/>.
/// </remarks>
HashSet<DamageGroupPrototype> ApplicableDamageGroups { get; }
>>>>>>> refactor-damageablecomponent
/// <summary>
/// The resistances of this component.
/// </summary>
ResistanceSet Resistances { get; }
bool SupportsDamageClass(DamageClass @class);
bool SupportsDamageType(DamageType type);
/// <summary>
/// Tries to get the amount of damage of a type.
/// Gets the amount of damage of a type.
/// </summary>
/// <param name="type">The type to get the damage of.</param>
/// <param name="damage">The amount of damage of that type.</param>
/// <returns>
/// True if the given <see cref="type"/> is supported, false otherwise.
/// </returns>
bool TryGetDamage(DamageTypePrototype type, out int damage);
bool TryGetDamage(DamageType type, out int damage);
/// <summary>
/// Returns the amount of damage of a given type, or zero if it is not supported.
/// Gets the amount of damage of a class.
/// </summary>
int GetDamage(DamageTypePrototype type);
/// <summary>
<<<<<<< HEAD
/// Returns the amount of damage of a given type, or zero if it is not supported.
/// </summary>
int GetDamage(DamageTypePrototype type);
/// <summary>
/// Tries to get the total amount of damage in a damage group.
/// </summary>
=======
/// Tries to get the total amount of damage in a damage group.
/// </summary>
>>>>>>> refactor-damageablecomponent
/// <param name="group">The group to get the damage of.</param>
/// <param name="damage">The amount of damage in that group.</param>
/// <param name="class">The class to get the damage of.</param>
/// <param name="damage">The amount of damage of that class.</param>
/// <returns>
/// True if the given group is applicable to this container, false otherwise.
/// True if the given <see cref="@class"/> is supported, false otherwise.
/// </returns>
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
bool TryGetDamage(DamageClass @class, out int damage);
/// <summary>
/// Changes the specified <see cref="DamageType"/>, applying
/// resistance values only if it is damage.
=======
bool TryGetDamage(DamageGroupPrototype group, out int damage);
/// <summary>
/// Returns the amount of damage present in an applicable group, or zero if no members are supported.
/// </summary>
int GetDamage(DamageGroupPrototype group);
/// <summary>
/// Tries to change the specified <see cref="DamageTypePrototype"/>, applying
/// resistance values only if it is dealing damage.
>>>>>>> Refactor damageablecomponent update (#4406)
=======
bool TryGetDamage(DamageGroupPrototype group, out int damage);
/// <summary>
/// Returns the amount of damage present in an applicable group, or zero if no members are supported.
/// </summary>
int GetDamage(DamageGroupPrototype group);
/// <summary>
/// Tries to change the specified <see cref="DamageTypePrototype"/>, applying
/// resistance values only if it is dealing damage.
>>>>>>> refactor-damageablecomponent
/// </summary>
/// <param name="type">Type of damage being changed.</param>
/// <param name="amount">
/// Amount of damage being received (positive for damage, negative for heals).
/// </param>
/// <param name="ignoreDamageResistances">
/// Whether or not to ignore resistances when taking damage.
/// <param name="ignoreResistances">
/// Whether or not to ignore resistances.
/// Healing always ignores resistances, regardless of this input.
/// </param>
/// <param name="source">
/// The entity that dealt or healed the damage, if any.
/// </param>
/// <param name="extraParams">
/// Extra parameters that some components may require, such as a specific limb to target.
/// </param>
/// <returns>
/// False if the given type is not supported or no damage change occurred; true otherwise.
/// False if the given type is not supported or improper
/// <see cref="DamageChangeParams"/> were provided; true otherwise.
/// </returns>
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
bool ChangeDamage(
DamageType type,
int amount,
@@ -226,47 +89,24 @@ namespace Content.Shared.Damage.Components
/// resistance values only if it is damage.
/// Spreads amount evenly between the <see cref="DamageType"></see>s
/// represented by that class.
=======
bool TryChangeDamage(DamageTypePrototype type, int amount, bool ignoreDamageResistances = false);
/// <summary>
/// Tries to change damage of the specified <see cref="DamageGroupPrototype"/>, applying resistance values
/// only if it is damage.
>>>>>>> Refactor damageablecomponent update (#4406)
=======
bool TryChangeDamage(DamageTypePrototype type, int amount, bool ignoreDamageResistances = false);
/// <summary>
/// Tries to change damage of the specified <see cref="DamageGroupPrototype"/>, applying resistance values
/// only if it is damage.
>>>>>>> refactor-damageablecomponent
/// </summary>
/// <remarks>
/// <para>
/// If dealing damage, this spreads the damage change amount evenly between the <see
/// cref="DamageTypePrototype"></see>s in this group (subject to integer rounding). If only a subset of the
/// damage types in the group are actually supported, then the total damage dealt may be less than expected
/// (unsupported damage is ignored).
/// </para>
/// <para>
/// If healing damage, this spreads the damage change proportional to the current damage value of each <see
/// cref="DamageTypePrototype"></see> (subject to integer rounding). If there is less damage than is being
/// healed, some healing is wasted. Unsupported damage types do not waste healing.
/// </para>
/// </remarks>
/// <param name="group">group of damage being changed.</param>
/// <param name="class">Class of damage being changed.</param>
/// <param name="amount">
/// Amount of damage being received (positive for damage, negative for heals).
/// </param>
/// <param name="ignoreDamageResistances">
/// Whether to ignore resistances when taking damage. Healing always ignores resistances, regardless of this
/// input.
/// <param name="ignoreResistances">
/// Whether to ignore resistances.
/// Healing always ignores resistances, regardless of this input.
/// </param>
/// <param name="source">Entity that dealt or healed the damage, if any.</param>
/// <param name="extraParams">
/// Extra parameters that some components may require,
/// such as a specific limb to target.
/// </param>
/// <returns>
/// Returns false if the given group is not applicable or no damage change occurred; true otherwise.
/// Returns false if the given class is not supported or improper
/// <see cref="DamageChangeParams"/> were provided; true otherwise.
/// </returns>
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
bool ChangeDamage(
DamageClass @class,
int amount,
@@ -277,110 +117,28 @@ namespace Content.Shared.Damage.Components
/// <summary>
/// Forcefully sets the specified <see cref="DamageType"/> to the given
/// value, ignoring resistance values.
=======
bool TryChangeDamage(DamageGroupPrototype group, int amount, bool ignoreDamageResistances = false);
/// <summary>
=======
bool TryChangeDamage(DamageGroupPrototype group, int amount, bool ignoreDamageResistances = false);
/// <summary>
>>>>>>> refactor-damageablecomponent
/// Forcefully sets the specified <see cref="DamageTypePrototype"/> to the given value, ignoring resistance
/// values.
/// </summary>
/// <param name="type">Type of damage being set.</param>
<<<<<<< HEAD
/// <param name="type">Type of damage being changed.</param>
/// <param name="newValue">New damage value to be set.</param>
/// <param name="source">Entity that set the new damage value.</param>
/// <param name="extraParams">
/// Extra parameters that some components may require,
/// such as a specific limb to target.
/// </param>
/// <returns>
/// Returns false if a given type is not supported or a negative value is provided; true otherwise.
/// Returns false if the given type is not supported or improper
/// <see cref="DamageChangeParams"/> were provided; true otherwise.
/// </returns>
bool TrySetDamage(DamageTypePrototype type, int newValue);
/// <summary>
/// Forcefully sets all damage types in a specified damage group using <see cref="TrySetDamage"></see>.
/// </summary>
/// <remarks>
/// Note that the actual damage of this group will be equal to the given value times the number damage group
/// members that this container supports.
/// </remarks>
/// <param name="group">Group of damage being set.</param>
/// <param name="newValue">New damage value to be set.</param>
/// <returns>
/// Returns false if the given group is not applicable or a negative value is provided; true otherwise.
/// </returns>
bool TrySetDamage(DamageGroupPrototype group, int newValue);
/// <summary>
/// Sets all supported damage types to specified value using <see cref="TrySetDamage"></see>.
>>>>>>> Refactor damageablecomponent update (#4406)
/// </summary>
/// <param name="newValue">New damage value to be set.</param>
/// <returns>
/// Returns false if a negative value is provided; true otherwise.
/// </returns>
<<<<<<< refs/remotes/origin/master
bool SetDamage(
DamageType type,
int newValue,
IEntity? source = null,
DamageChangeParams? extraParams = null);
=======
bool TrySetAllDamage(int newValue);
/// <summary>
/// Returns true if the given damage group is applicable to this damage container.
/// Sets all damage values to zero.
/// </summary>
=======
/// <param name="newValue">New damage value to be set.</param>
/// <returns>
/// Returns false if a given type is not supported or a negative value is provided; true otherwise.
/// </returns>
bool TrySetDamage(DamageTypePrototype type, int newValue);
/// <summary>
/// Forcefully sets all damage types in a specified damage group using <see cref="TrySetDamage"></see>.
/// </summary>
/// <remarks>
/// Note that the actual damage of this group will be equal to the given value times the number damage group
/// members that this container supports.
/// </remarks>
/// <param name="group">Group of damage being set.</param>
/// <param name="newValue">New damage value to be set.</param>
/// <returns>
/// Returns false if the given group is not applicable or a negative value is provided; true otherwise.
/// </returns>
bool TrySetDamage(DamageGroupPrototype group, int newValue);
/// <summary>
/// Sets all supported damage types to specified value using <see cref="TrySetDamage"></see>.
/// </summary>
/// <param name="newValue">New damage value to be set.</param>
/// <returns>
/// Returns false if a negative value is provided; true otherwise.
/// </returns>
bool TrySetAllDamage(int newValue);
/// <summary>
/// Returns true if the given damage group is applicable to this damage container.
/// </summary>
>>>>>>> refactor-damageablecomponent
public bool IsApplicableDamageGroup(DamageGroupPrototype group);
/// <summary>
/// Returns true if the given damage group is fully supported by this damage container.
/// </summary>
public bool IsFullySupportedDamageGroup(DamageGroupPrototype group);
<<<<<<< HEAD
>>>>>>> Refactor damageablecomponent update (#4406)
=======
>>>>>>> refactor-damageablecomponent
/// <summary>
/// Returns true if the given damage type is supported by this damage container.
/// </summary>
public bool IsSupportedDamageType(DamageTypePrototype type);
void Heal();
/// <summary>
/// Invokes the HealthChangedEvent with the current values of health.

View File

@@ -1,6 +1,5 @@
using System;
using System;
using System.Collections.Generic;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
@@ -9,287 +8,46 @@ using Robust.Shared.ViewVariables;
namespace Content.Shared.Damage.Container
{
/// <summary>
/// A damage container which can be used to specify support for various damage types.
/// Prototype for the DamageContainer class.
/// </summary>
/// <remarks>
/// This is effectively just a list of damage types that can be specified in YAML files using both damage types
/// and damage groups. Currently this is only used to specify what damage types a <see
/// cref="Components.DamageableComponent"/> should support.
/// </remarks>
[Prototype("damageContainer")]
[Serializable, NetSerializable]
public class DamageContainerPrototype : IPrototype, ISerializationHooks
{
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
=======
=======
>>>>>>> refactor-damageablecomponent
private IPrototypeManager _prototypeManager = default!;
[DataField("supportAll")] private bool _supportAll;
[DataField("supportedClasses")] private HashSet<DamageClass> _supportedClasses = new();
[DataField("supportedTypes")] private HashSet<DamageType> _supportedTypes = new();
// TODO NET 5 IReadOnlySet
[ViewVariables] public IReadOnlyCollection<DamageClass> SupportedClasses => _supportedClasses;
[ViewVariables] public IReadOnlyCollection<DamageType> SupportedTypes => _supportedTypes;
[ViewVariables]
[DataField("id", required: true)]
public string ID { get; } = default!;
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
>>>>>>> update damagecomponent across shared and server
=======
/// <summary>
/// Determines whether this DamageContainerPrototype will support ALL damage types and groups. If true,
/// ignore all other options.
/// </summary>
>>>>>>> refactor-damageablecomponent
[DataField("supportAll")] private bool _supportAll;
[DataField("supportedGroups")] private HashSet<string> _supportedDamageGroupIDs = new();
[DataField("supportedTypes")] private HashSet<string> _supportedDamageTypeIDs = new();
private HashSet<DamageGroupPrototype> _applicableDamageGroups = new();
private HashSet<DamageGroupPrototype> _fullySupportedDamageGroups = new();
private HashSet<DamageTypePrototype> _supportedDamageTypes = new();
// TODO NET 5 IReadOnlySet
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
[ViewVariables] public IReadOnlyCollection<DamageClass> SupportedClasses => _supportedClasses;
[ViewVariables] public IReadOnlyCollection<DamageType> SupportedTypes => _supportedTypes;
=======
[ViewVariables] public IReadOnlyCollection<DamageGroupPrototype> SupportedDamageGroups => _supportedDamageGroups;
=======
/// <summary>
/// Determines whether this DamageContainerPrototype will support ALL damage types and groups. If true,
/// ignore all other options.
/// </summary>
[DataField("supportAll")] private bool _supportAll;
[DataField("supportedGroups")] private HashSet<string> _supportedDamageGroupIDs = new();
[DataField("supportedTypes")] private HashSet<string> _supportedDamageTypeIDs = new();
private HashSet<DamageGroupPrototype> _applicableDamageGroups = new();
private HashSet<DamageGroupPrototype> _fullySupportedDamageGroups = new();
private HashSet<DamageTypePrototype> _supportedDamageTypes = new();
// TODO NET 5 IReadOnlySet
/// <summary>
/// Collection of damage groups that can affect this container.
/// </summary>
/// <remarks>
/// This describes what damage groups can have an effect on this damage container. However not every damage
/// group has to be fully supported. For example, the container may support ONLY the piercing damage type.
/// It should therefore be affected by instances of brute group damage, but does not necessarily support
/// blunt or slash damage. If damage containers are only specified by supported damage groups, and every
/// damage type is in only one damage group, then SupportedDamageTypes should be equal to
/// ApplicableDamageGroups. For a list of supported damage types, see <see cref="SupportedDamageTypes"/>.
/// </remarks>
[ViewVariables] public IReadOnlyCollection<DamageGroupPrototype> ApplicableDamageGroups => _applicableDamageGroups;
=======
/// <summary>
/// Collection of damage groups that can affect this container.
/// </summary>
/// <remarks>
/// This describes what damage groups can have an effect on this damage container. However not every damage
/// group has to be fully supported. For example, the container may support ONLY the piercing damage type.
/// It should therefore be affected by instances of brute group damage, but does not necessarily support
/// blunt or slash damage. If damage containers are only specified by supported damage groups, and every
/// damage type is in only one damage group, then SupportedDamageTypes should be equal to
/// ApplicableDamageGroups. For a list of supported damage types, see <see cref="SupportedDamageTypes"/>.
/// </remarks>
[ViewVariables] public IReadOnlyCollection<DamageGroupPrototype> ApplicableDamageGroups => _applicableDamageGroups;
>>>>>>> refactor-damageablecomponent
/// <summary>
/// Collection of damage groups that are fully supported by this container.
/// </summary>
/// <remarks>
/// This describes what damage groups this damage container explicitly supports. It supports every damage
/// type contained in these damage groups. It may also support other damage types not in these groups. To
/// see all damage types <see cref="SupportedDamageTypes"/>, and to see all applicable damage groups <see
/// cref="ApplicableDamageGroups"/>.
/// </remarks>
[ViewVariables] public IReadOnlyCollection<DamageGroupPrototype> FullySupportedDamageGroups => _fullySupportedDamageGroups;
/// <summary>
/// Collection of damage types supported by this container.
/// </summary>
/// <remarks>
/// Each of these damage types is fully supported by the DamageContainer. If any of these damage types is a
/// member of a damage group, these groups are added to <see cref="ApplicableDamageGroups"></see>
/// </remarks>
<<<<<<< HEAD
>>>>>>> Refactor damageablecomponent update (#4406)
[ViewVariables] public IReadOnlyCollection<DamageTypePrototype> SupportedDamageTypes => _supportedDamageTypes;
>>>>>>> update damagecomponent across shared and server
=======
[ViewVariables] public IReadOnlyCollection<DamageTypePrototype> SupportedDamageTypes => _supportedDamageTypes;
>>>>>>> refactor-damageablecomponent
void ISerializationHooks.AfterDeserialization()
{
_prototypeManager = IoCManager.Resolve<IPrototypeManager>();
if (_supportAll)
{
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
<<<<<<< refs/remotes/origin/master
_supportedClasses.UnionWith(Enum.GetValues<DamageClass>());
_supportedTypes.UnionWith(Enum.GetValues<DamageType>());
=======
foreach (var DamageGroup in _prototypeManager.EnumeratePrototypes<DamageGroupPrototype>())
=======
foreach (var group in _prototypeManager.EnumeratePrototypes<DamageGroupPrototype>())
>>>>>>> Refactor damageablecomponent update (#4406)
=======
foreach (var group in _prototypeManager.EnumeratePrototypes<DamageGroupPrototype>())
>>>>>>> refactor-damageablecomponent
{
_applicableDamageGroups.Add(group);
_fullySupportedDamageGroups.Add(group);
}
foreach (var type in _prototypeManager.EnumeratePrototypes<DamageTypePrototype>())
{
_supportedDamageTypes.Add(type);
}
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
>>>>>>> fix a few bugs
=======
>>>>>>> refactor-damageablecomponent
return;
}
// Add fully supported damage groups
foreach (var groupID in _supportedDamageGroupIDs)
foreach (var supportedClass in _supportedClasses)
{
var group = _prototypeManager.Index<DamageGroupPrototype>(groupID);
_fullySupportedDamageGroups.Add(group);
foreach (var type in group.DamageTypes)
{
_supportedDamageTypes.Add(type);
}
}
// Add individual damage types, that are either not part of a group, or whose groups are (possibly) not fully supported
foreach (var supportedTypeID in _supportedDamageTypeIDs)
{
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
foreach (var supportedType in supportedClass.ToTypes())
=======
var type = _prototypeManager.Index<DamageTypePrototype>(supportedTypeID);
_supportedDamageTypes.Add(type);
}
// For whatever reason, someone may have listed all members of a group as supported instead of just listing
// the group as supported. Check for this.
foreach (var group in _prototypeManager.EnumeratePrototypes<DamageGroupPrototype>())
{
if (_fullySupportedDamageGroups.Contains(group))
>>>>>>> refactor-damageablecomponent
{
continue;
}
// The group is not in the list of fully supported groups. Should it be?
var allMembersSupported = true;
foreach (var type in group.DamageTypes)
{
if (!_supportedDamageTypes.Contains(type))
{
// not all members are supported
allMembersSupported = false;
break;
}
}
if (allMembersSupported) {
// All members are supported. The silly goose should have just used a damage group.
_fullySupportedDamageGroups.Add(group);
}
}
// For each supported damage type, check whether it is in any existing group, If it is add it to _applicableDamageGroups
foreach (var type in _supportedDamageTypes)
{
foreach (var group in _prototypeManager.EnumeratePrototypes<DamageGroupPrototype>())
{
if (group.DamageTypes.Contains(type))
{
_applicableDamageGroups.Add(group);
}
}
}
=======
var DamageGroup= _prototypeManager.Index<DamageGroupPrototype>(supportedClassID);
_supportedDamageGroups.Add(DamageGroup);
foreach (var DamageType in DamageGroup.DamageTypes)
=======
return;
}
// Add fully supported damage groups
foreach (var groupID in _supportedDamageGroupIDs)
{
var group = _prototypeManager.Index<DamageGroupPrototype>(groupID);
_fullySupportedDamageGroups.Add(group);
foreach (var type in group.DamageTypes)
>>>>>>> Refactor damageablecomponent update (#4406)
{
_supportedDamageTypes.Add(type);
_supportedTypes.Add(supportedType);
}
}
<<<<<<< refs/remotes/origin/master
>>>>>>> fix a few bugs
=======
// Add individual damage types, that are either not part of a group, or whose groups are (possibly) not fully supported
foreach (var supportedTypeID in _supportedDamageTypeIDs)
foreach (var originalType in _supportedTypes)
{
var type = _prototypeManager.Index<DamageTypePrototype>(supportedTypeID);
_supportedDamageTypes.Add(type);
_supportedClasses.Add(originalType.ToClass());
}
// For whatever reason, someone may have listed all members of a group as supported instead of just listing
// the group as supported. Check for this.
foreach (var group in _prototypeManager.EnumeratePrototypes<DamageGroupPrototype>())
{
if (_fullySupportedDamageGroups.Contains(group))
{
continue;
}
// The group is not in the list of fully supported groups. Should it be?
var allMembersSupported = true;
foreach (var type in group.DamageTypes)
{
if (!_supportedDamageTypes.Contains(type))
{
// not all members are supported
allMembersSupported = false;
break;
}
}
if (allMembersSupported) {
// All members are supported. The silly goose should have just used a damage group.
_fullySupportedDamageGroups.Add(group);
}
}
// For each supported damage type, check whether it is in any existing group, If it is add it to _applicableDamageGroups
foreach (var type in _supportedDamageTypes)
{
foreach (var group in _prototypeManager.EnumeratePrototypes<DamageGroupPrototype>())
{
if (group.DamageTypes.Contains(type))
{
_applicableDamageGroups.Add(group);
}
}
}
>>>>>>> Refactor damageablecomponent update (#4406)
}
}
}

View File

@@ -2,14 +2,14 @@
{
/// <summary>
/// Data class with information on how the value of a
/// single <see cref="DamageTypePrototype"/> has changed.
/// single <see cref="DamageType"/> has changed.
/// </summary>
public struct DamageChangeData
{
/// <summary>
/// Type of damage that changed.
/// </summary>
public DamageTypePrototype Type;
public DamageType Type;
/// <summary>
/// The new current value for that damage.
@@ -21,7 +21,7 @@
/// </summary>
public int Delta;
public DamageChangeData(DamageTypePrototype type, int newValue, int delta)
public DamageChangeData(DamageType type, int newValue, int delta)
{
Type = type;
NewValue = newValue;

View File

@@ -0,0 +1,18 @@
using System;
using Content.Shared.Body.Components;
using Content.Shared.Damage.Components;
namespace Content.Shared.Damage
{
/// <summary>
/// Data class with information on how to damage a
/// <see cref="IDamageableComponent"/>.
/// While not necessary to damage for all instances, classes such as
/// <see cref="SharedBodyComponent"/> may require it for extra data
/// (such as selecting which limb to target).
/// </summary>
// TODO BODY: Remove and pretend it never existed
public class DamageChangeParams : EventArgs
{
}
}

View File

@@ -12,7 +12,7 @@ namespace Content.Shared.Damage
Data = data;
}
public DamageChangedEventArgs(IDamageableComponent damageable, DamageTypePrototype type, int newValue, int delta)
public DamageChangedEventArgs(IDamageableComponent damageable, DamageType type, int newValue, int delta)
{
Damageable = damageable;
@@ -28,7 +28,7 @@ namespace Content.Shared.Damage
public IDamageableComponent Damageable { get; }
/// <summary>
/// List containing data on each <see cref="DamageTypePrototype"/> that was changed.
/// List containing data on each <see cref="DamageType"/> that was changed.
/// </summary>
public IReadOnlyList<DamageChangeData> Data { get; }
}

View File

@@ -12,7 +12,7 @@ namespace Content.Shared.Damage
Data = data;
}
public DamageChangedMessage(IDamageableComponent damageable, DamageTypePrototype type, int newValue, int delta)
public DamageChangedMessage(IDamageableComponent damageable, DamageType type, int newValue, int delta)
{
Damageable = damageable;
@@ -28,7 +28,7 @@ namespace Content.Shared.Damage
public IDamageableComponent Damageable { get; }
/// <summary>
/// List containing data on each <see cref="DamageTypePrototype"/> that was changed.
/// List containing data on each <see cref="DamageType"/> that was changed.
/// </summary>
public IReadOnlyList<DamageChangeData> Data { get; }

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Robust.Shared.Serialization;
namespace Content.Shared.Damage
{
[Serializable, NetSerializable]
public enum DamageClass
{
Brute,
Burn,
Toxin,
Airloss,
Genetic
}
public static class DamageClassExtensions
{
public static ImmutableList<DamageType> ToTypes(this DamageClass @class)
{
return DamageSystem.ClassToType[@class];
}
public static Dictionary<DamageClass, T> ToNewDictionary<T>() where T : struct
{
return Enum.GetValues(typeof(DamageClass))
.Cast<DamageClass>()
.ToDictionary(@class => @class, _ => default(T));
}
public static Dictionary<DamageClass, int> ToNewDictionary()
{
return ToNewDictionary<int>();
}
}
}

View File

@@ -1,74 +0,0 @@
#nullable enable
using System;
using System.Collections.Generic;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Shared.Damage.DamageContainer
{
/// <summary>
/// Prototype for the DamageContainer class.
/// </summary>
[Prototype("damageContainer")]
[Serializable, NetSerializable]
public class DamageContainerPrototype : IPrototype, ISerializationHooks
{
[Dependency]
private readonly IPrototypeManager _prototypeManager = default!;
[DataField("supportAll")] private bool _supportAll;
[DataField("supportedClasses")] private HashSet<string> _supportedDamageGroupsButAsStrings = new();
[DataField("supportedTypes")] private HashSet<string> _supportedDamageTypesButAsStrings = new();
private HashSet<DamageGroupPrototype> _supportedDamageGroups = new();
private HashSet<DamageTypePrototype> _supportedDamageTypes = new();
// TODO NET 5 IReadOnlySet
[ViewVariables] public IReadOnlyCollection<DamageGroupPrototype> SupportedDamageGroups => _supportedDamageGroups;
[ViewVariables] public IReadOnlyCollection<DamageTypePrototype> SupportedDamageTypes => _supportedDamageTypes;
[ViewVariables]
[DataField("id", required: true)]
public string ID { get; } = default!;
void ISerializationHooks.AfterDeserialization()
{
if (_supportAll)
{
// _supportedClasses.UnionWith(Enum.GetValues<DamageClass>());
//_supportedTypes.UnionWith(Enum.GetValues<DamageType>());
foreach (var DamageGroup in _prototypeManager.EnumeratePrototypes<DamageGroupPrototype>())
{
_supportedDamageGroups.Add(DamageGroup);
foreach (var SupportedDamageType in DamageGroup.DamageTypes)
{
_supportedDamageTypes.Add(SupportedDamageType);
}
}
return;
}
foreach (var supportedClassID in _supportedDamageGroupsButAsStrings)
{
var resolvedDamageGroup= _prototypeManager.Index<DamageGroupPrototype>(supportedClassID);
foreach (var supportedType in resolvedDamageGroup.DamageTypes)
{
_supportedDamageTypes.Add(supportedType);
}
}
//reverse link type to group because smug said so ask him
foreach (var originalType in _supportedDamageTypes)
{
_supportedDamageTypes.Add(originalType);
}
}
}
}

View File

@@ -1,42 +0,0 @@
using System;
using System.Collections.Generic;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Shared.Damage
{
/// <summary>
/// A Group of <see cref="DamageTypePrototype"/>s.
/// </summary>
/// <remarks>
/// These groups can be used to specify supported damage types of a <see
/// cref="Container.DamageContainerPrototype"/>, or to change/get/set damage in a <see
/// cref="Components.DamageableComponent"/>.
/// </remarks>
[Prototype("damageGroup")]
[Serializable, NetSerializable]
public class DamageGroupPrototype : IPrototype, ISerializationHooks
{
private IPrototypeManager _prototypeManager = default!;
[DataField("id", required: true)] public string ID { get; } = default!;
[DataField("damageTypes", required: true)]
public List<string> TypeIDs { get; } = default!;
public HashSet<DamageTypePrototype> DamageTypes { get; } = new();
// Create set of damage types
void ISerializationHooks.AfterDeserialization()
{
_prototypeManager = IoCManager.Resolve<IPrototypeManager>();
foreach (var typeID in TypeIDs)
{
DamageTypes.Add(_prototypeManager.Index<DamageTypePrototype>(typeID));
}
}
}
}

View File

@@ -8,6 +8,59 @@ namespace Content.Shared.Damage
[UsedImplicitly]
public class DamageSystem : EntitySystem
{
public static ImmutableDictionary<DamageClass, ImmutableList<DamageType>> ClassToType { get; } = DefaultClassToType();
public static ImmutableDictionary<DamageType, DamageClass> TypeToClass { get; } = DefaultTypeToClass();
private static ImmutableDictionary<DamageClass, ImmutableList<DamageType>> DefaultClassToType()
{
return new Dictionary<DamageClass, ImmutableList<DamageType>>
{
[DamageClass.Brute] = new List<DamageType>
{
DamageType.Blunt,
DamageType.Slash,
DamageType.Piercing
}.ToImmutableList(),
[DamageClass.Burn] = new List<DamageType>
{
DamageType.Heat,
DamageType.Shock,
DamageType.Cold
}.ToImmutableList(),
[DamageClass.Toxin] = new List<DamageType>
{
DamageType.Poison,
DamageType.Radiation
}.ToImmutableList(),
[DamageClass.Airloss] = new List<DamageType>
{
DamageType.Asphyxiation,
DamageType.Bloodloss
}.ToImmutableList(),
[DamageClass.Genetic] = new List<DamageType>
{
DamageType.Cellular
}.ToImmutableList()
}.ToImmutableDictionary();
}
private static ImmutableDictionary<DamageType, DamageClass> DefaultTypeToClass()
{
return new Dictionary<DamageType, DamageClass>
{
{DamageType.Blunt, DamageClass.Brute},
{DamageType.Slash, DamageClass.Brute},
{DamageType.Piercing, DamageClass.Brute},
{DamageType.Heat, DamageClass.Burn},
{DamageType.Shock, DamageClass.Burn},
{DamageType.Cold, DamageClass.Burn},
{DamageType.Poison, DamageClass.Toxin},
{DamageType.Radiation, DamageClass.Toxin},
{DamageType.Asphyxiation, DamageClass.Airloss},
{DamageType.Bloodloss, DamageClass.Airloss},
{DamageType.Cellular, DamageClass.Genetic}
}.ToImmutableDictionary();
}
}
}

View File

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.Serialization;
namespace Content.Shared.Damage
{
[Serializable, NetSerializable]
public enum DamageType
{
Blunt,
Slash,
Piercing,
Heat,
Shock,
Cold,
Poison,
Radiation,
Asphyxiation,
Bloodloss,
Cellular
}
public static class DamageTypeExtensions
{
public static DamageClass ToClass(this DamageType type)
{
return DamageSystem.TypeToClass[type];
}
public static Dictionary<DamageType, T> ToNewDictionary<T>() where T : struct
{
return Enum.GetValues(typeof(DamageType))
.Cast<DamageType>()
.ToDictionary(type => type, _ => default(T));
}
public static Dictionary<DamageType, int> ToNewDictionary()
{
return ToNewDictionary<int>();
}
public static Dictionary<DamageClass, int> ToClassDictionary(this IReadOnlyDictionary<DamageType, int> types)
{
var classes = DamageClassExtensions.ToNewDictionary();
foreach (var @class in classes.Keys.ToList())
{
foreach (var type in @class.ToTypes())
{
if (!types.TryGetValue(type, out var damage))
{
continue;
}
classes[@class] += damage;
}
}
return classes;
}
}
}

View File

@@ -1,18 +0,0 @@
using System;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Shared.Damage
{
/// <summary>
/// A single damage type. These types are grouped together in <see cref="DamageGroupPrototype"/>s.
/// </summary>
[Prototype("damageType")]
[Serializable, NetSerializable]
public class DamageTypePrototype : IPrototype
{
[DataField("id", required: true)]
public string ID { get; } = default!;
}
}

View File

@@ -1,86 +0,0 @@
#nullable enable
using System;
using System.Collections.Generic;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
namespace Content.Shared.Damage.ResistanceSet
{
/// <summary>
/// Set of resistances used by damageable objects.
/// Each <see cref="DamageTypePrototype"/> has a multiplier and flat damage
/// reduction value.
/// </summary>
[NetSerializable]
[Serializable]
public class ResistanceSet : ISerializationHooks
{
[ViewVariables]
private Dictionary<DamageTypePrototype, ResistanceSetSettings> _resistances = new();
public ResistanceSet()
{
}
public void AfterDeserialization()
{
var _prototypeManager = IoCManager.Resolve<IPrototypeManager>();
foreach (var damageType in _prototypeManager.EnumeratePrototypes<DamageTypePrototype>())
{
_resistances.Add(damageType, new ResistanceSetSettings(1f, 0));
}
}
public ResistanceSet(ResistanceSetPrototype data)
{
ID = data.ID;
_resistances = data.Resistances;
}
public string ID { get; } = string.Empty;
/// <summary>
/// Adjusts input damage with the resistance set values.
/// Only applies reduction if the amount is damage (positive), not
/// healing (negative).
/// </summary>
/// <param name="damageType">Type of damage.</param>
/// <param name="amount">Incoming amount of damage.</param>
public int CalculateDamage(DamageTypePrototype damageType, int amount)
{
if (amount > 0) // Only apply reduction if it's healing, not damage.
{
amount -= _resistances[damageType].FlatReduction;
if (amount <= 0)
{
return 0;
}
}
amount = (int) Math.Ceiling(amount * _resistances[damageType].Coefficient);
return amount;
}
}
/// <summary>
/// Settings for a specific damage type in a resistance set. Flat reduction is applied before the coefficient.
/// </summary>
[Serializable, NetSerializable]
public struct ResistanceSetSettings
{
[ViewVariables] public float Coefficient { get; private set; }
[ViewVariables] public int FlatReduction { get; private set; }
public ResistanceSetSettings(float coefficient, int flatReduction)
{
Coefficient = coefficient;
FlatReduction = flatReduction;
}
}
}

View File

@@ -1,63 +0,0 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Net;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Shared.Damage.ResistanceSet
{
/// <summary>
/// Prototype for the BodyPart class.
/// </summary>
[Prototype("resistanceSet")]
[Serializable, NetSerializable]
public class ResistanceSetPrototype : IPrototype, ISerializationHooks
{
[Dependency]
private readonly IPrototypeManager _prototypeManager = default!;
[ViewVariables]
[field: DataField("coefficients")]
public Dictionary<string, float> Coefficients { get; } = new();
[ViewVariables]
[field: DataField("flatReductions")]
public Dictionary<string, int> FlatReductions { get; } = new();
[ViewVariables]
public Dictionary<DamageTypePrototype, float> Resistances { get; private set; } = new();
[ViewVariables]
public Dictionary<DamageTypePrototype, int> FlatResistances { get; private set; } = new();
[ViewVariables]
[DataField("id", required: true)]
public string ID { get; } = default!;
void ISerializationHooks.AfterDeserialization()
{
Resistances = new Dictionary<DamageTypePrototype, float>();
FlatResistances = new Dictionary<DamageTypePrototype, int>();
foreach (var KeyValuePair in Coefficients)
{
var resolvedDamageType = _prototypeManager.Index<DamageTypePrototype>(KeyValuePair.Key);
Resistances.Add(resolvedDamageType,KeyValuePair.Value);
}
foreach (var KeyValuePair in FlatReductions)
{
var resolvedDamageType = _prototypeManager.Index<DamageTypePrototype>(KeyValuePair.Key);
Resistances.Add(resolvedDamageType,KeyValuePair.Value);
}
foreach (var damageType in _prototypeManager.EnumeratePrototypes<DamageTypePrototype>())
{
// Resistances.Add(damageType, new ResistanceSetSettings(Coefficients[damageType], FlatReductions[damageType]));
}
}
}
}

View File

@@ -1,7 +1,5 @@
using System;
using System;
using System.Collections.Generic;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
@@ -9,31 +7,18 @@ namespace Content.Shared.Damage.Resistances
{
/// <summary>
/// Set of resistances used by damageable objects.
/// Each <see cref="DamageTypePrototype"/> has a multiplier and flat damage
/// Each <see cref="DamageType"/> has a multiplier and flat damage
/// reduction value.
/// </summary>
[Serializable, NetSerializable]
public class ResistanceSet
{
[ViewVariables]
public string? ID { get; } = string.Empty;
[ViewVariables]
public Dictionary<DamageTypePrototype, ResistanceSetSettings> Resistances { get; } = new();
public ResistanceSet()
{
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
foreach (var damageType in (DamageType[]) Enum.GetValues(typeof(DamageType)))
{
Resistances.Add(damageType, new ResistanceSetSettings(1f, 0));
}
=======
>>>>>>> Merge fixes
=======
>>>>>>> refactor-damageablecomponent
}
public ResistanceSet(ResistanceSetPrototype data)
@@ -42,6 +27,12 @@ namespace Content.Shared.Damage.Resistances
Resistances = data.Resistances;
}
[ViewVariables]
public string ID { get; } = string.Empty;
[ViewVariables]
public Dictionary<DamageType, ResistanceSetSettings> Resistances { get; } = new();
/// <summary>
/// Adjusts input damage with the resistance set values.
/// Only applies reduction if the amount is damage (positive), not
@@ -49,18 +40,11 @@ namespace Content.Shared.Damage.Resistances
/// </summary>
/// <param name="damageType">Type of damage.</param>
/// <param name="amount">Incoming amount of damage.</param>
public int CalculateDamage(DamageTypePrototype damageType, int amount)
public int CalculateDamage(DamageType damageType, int amount)
{
// Do nothing if the damage type is not specified in resistance set.
if (!Resistances.TryGetValue(damageType, out var resistance))
{
return amount;
}
if (amount > 0) // Only apply reduction if it's healing, not damage.
{
amount -= resistance.FlatReduction;
amount -= Resistances[damageType].FlatReduction;
if (amount <= 0)
{
@@ -68,9 +52,25 @@ namespace Content.Shared.Damage.Resistances
}
}
amount = (int) Math.Ceiling(amount * resistance.Coefficient);
amount = (int) Math.Ceiling(amount * Resistances[damageType].Coefficient);
return amount;
}
}
/// <summary>
/// Settings for a specific damage type in a resistance set. Flat reduction is applied before the coefficient.
/// </summary>
[Serializable, NetSerializable]
public readonly struct ResistanceSetSettings
{
[ViewVariables] public readonly float Coefficient;
[ViewVariables] public readonly int FlatReduction;
public ResistanceSetSettings(float coefficient, int flatReduction)
{
Coefficient = coefficient;
FlatReduction = flatReduction;
}
}
}

View File

@@ -1,27 +1,5 @@
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
<<<<<<< refs/remotes/origin/master
using System;
=======
#nullable enable
using System;
using System.CodeDom;
>>>>>>> update damagecomponent across shared and server
=======
using System;
using System.CodeDom;
>>>>>>> Refactor damageablecomponent update (#4406)
using System.Collections.Generic;
<<<<<<< refs/remotes/origin/master
=======
using Robust.Shared.IoC;
>>>>>>> Merge fixes
=======
using System;
using System.CodeDom;
using System.Collections.Generic;
using Robust.Shared.IoC;
>>>>>>> refactor-damageablecomponent
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
@@ -37,90 +15,28 @@ namespace Content.Shared.Damage.Resistances
public class ResistanceSetPrototype : IPrototype, ISerializationHooks
{
[ViewVariables]
<<<<<<< HEAD
<<<<<<< refs/remotes/origin/master
[DataField("coefficients")]
<<<<<<< refs/remotes/origin/master
public Dictionary<DamageType, float> Coefficients { get; } = new();
=======
[DataField("id", required: true)]
public string ID { get; } = default!;
>>>>>>> refactor-damageablecomponent
[ViewVariables]
[DataField("coefficients", required: true)]
private Dictionary<string, float> coefficients { get; } = new();
[DataField("flatReductions")]
public Dictionary<DamageType, int> FlatReductions { get; } = new();
[ViewVariables]
<<<<<<< HEAD
public Dictionary<DamageType, ResistanceSetSettings> Resistances { get; private set; } = new();
=======
public Dictionary<string, float> Coefficients { get; } = new();
=======
[ViewVariables]
[DataField("id", required: true)]
public string ID { get; } = default!;
>>>>>>> update damagecomponent across shared and server
[ViewVariables]
[DataField("coefficients", required: true)]
private Dictionary<string, float> coefficients { get; } = new();
[ViewVariables]
[DataField("flatReductions", required: true)]
private Dictionary<string, int> flatReductions { get; } = new();
[ViewVariables]
<<<<<<< refs/remotes/origin/master
public Dictionary<DamageTypePrototype, int> FlatResistances { get; private set; } = new();
>>>>>>> Merge fixes
=======
[DataField("flatReductions", required: true)]
private Dictionary<string, int> flatReductions { get; } = new();
>>>>>>> refactor-damageablecomponent
[ViewVariables]
public Dictionary<DamageTypePrototype, ResistanceSetSettings> Resistances { get; private set; } = new();
void ISerializationHooks.AfterDeserialization()
{
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
foreach (var damageTypeID in coefficients.Keys)
Resistances = new Dictionary<DamageType, ResistanceSetSettings>();
foreach (var damageType in (DamageType[]) Enum.GetValues(typeof(DamageType)))
{
var resolvedDamageType = prototypeManager.Index<DamageTypePrototype>(damageTypeID);
Resistances.Add(resolvedDamageType, new ResistanceSetSettings(coefficients[damageTypeID], flatReductions[damageTypeID]));
}
=======
public Dictionary<DamageTypePrototype, ResistanceSetSettings> Resistances { get; private set; } = new();
void ISerializationHooks.AfterDeserialization()
{
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
foreach (var damageTypeID in coefficients.Keys)
{
var resolvedDamageType = prototypeManager.Index<DamageTypePrototype>(damageTypeID);
Resistances.Add(resolvedDamageType, new ResistanceSetSettings(coefficients[damageTypeID], flatReductions[damageTypeID]));
Resistances.Add(damageType,
new ResistanceSetSettings(Coefficients[damageType], FlatReductions[damageType]));
}
}
}
/// <summary>
/// Resistance Settings for a specific DamageType. Flat reduction should always be applied before the coefficient.
/// </summary>
[Serializable, NetSerializable]
public readonly struct ResistanceSetSettings
{
[ViewVariables] public readonly float Coefficient;
[ViewVariables] public readonly int FlatReduction;
public ResistanceSetSettings(float coefficient, int flatReduction)
{
Coefficient = coefficient;
FlatReduction = flatReduction;
<<<<<<< HEAD
>>>>>>> update damagecomponent across shared and server
=======
>>>>>>> refactor-damageablecomponent
}
}
}