I don’t have any specific tutorials on this. I was basing this off of your own descriptoin of what you’re looking for (Physical damage and then “Lightening” damage).
Many games have multiple damage types attached to a given weapon. The Physical damage is blocked by conventional means (your defense score), while elemental damage is mitigated by resistance to that element.
In my setup, DamageType is an Enum
public enum DamageType
{
Earth,
Air,
Fire,
Water,
Lightning,
Light,
Dark
}
WeaponConfigs have direct conventional damage. They also have a List of Damages which correspond to elemental damages.
Armor can have stats that reduce that damage.
I created a parallel system for elemental damage alongside the IModifierProvider system, to make it easier to match up damages and resistances.
using System.Collections.Generic;
namespace RPG.Stats
{
[System.Serializable]
public struct ElementalDamage
{
public DamageType damageType;
public float amount;
}
public enum DamageType
{
Earth,
Air,
Fire,
Water,
Lightning,
Light,
Dark
}
public interface IElementalResistanceProvider
{
public IEnumerable<float> GetElementalResistance(DamageType damageType);
}
public interface IElementalDamageProvider
{
public IEnumerable<float> GetElementalDamageBoost(DamageType damageType);
}
}
With these helper classes/enums in place, then I add a few tidbits to StatsEquipableItem, adding IElementalDamageProvider and IElementalResistanceProfider to the interfaces.
[SerializeField] private ElementalDamage[] elementDamages;
[SerializeField] private ElementalDamage[] elementResistances;
public IEnumerable<float> GetElementalDamageBoost(DamageType damageType)
{
foreach (ElementalDamage damage in elementDamages)
{
if (damage.damageType == damageType) yield return damage.amount;
}
}
public IEnumerable<float> GetElementalResistance(DamageType damageType)
{
foreach (ElementalDamage damage in elementResistances)
{
if (damage.damageType == damageType) yield return damage.amount;
}
}
Similarly, in StatsEquipment, I add the providers
public IEnumerable<float> GetElementalResistance(DamageType damageType)
{
foreach (var slot in GetAllPopulatedSlots())
{
var item = GetItemInSlot(slot) as IElementalResistanceProvider;
if (item == null) continue;
foreach (float modifier in item.GetElementalResistance(damageType))
{
yield return modifier;
}
}
}
public IEnumerable<float> GetElementalDamageBoost(DamageType damageType)
{
foreach (var slot in GetAllPopulatedSlots())
{
var item = GetItemInSlot(slot) as IElementalDamageProvider;
if (item == null) continue;
foreach (float modifier in item.GetElementalDamageBoost(damageType))
{
yield return modifier;
}
});
}
In WeaponConfig, I add
[SerializeField] ElementalDamage[] elementalDamages;
public IEnumerable<ElementalDamage> GetElementalDamages()
{
foreach (ElementalDamage elementalDamage in elementalDamages)
{
yield return elementalDamage;
}
}
And finally in Fighter.cs, in the Hit() method, after doing the standard damage, we need to add the elemental damages:
else
{
target.TakeDamage(gameObject, damage);
foreach (ElementalDamage elementalDamage in currentWeaponConfig.GetElementalDamages())
{
damage = elementalDamage.amount;
float boosts = 0;
foreach (IElementalDamageProvider provider in GetComponents<IElementalDamageProvider>())
{
foreach (float amount in provider.GetElementalDamageBoost(elementalDamage.damageType))
{
boosts += amount;
}
}
boosts /= 100f;
float resistances = 0;
foreach (IElementalResistanceProvider provider in target.GetComponents<IElementalResistanceProvider>())
{
foreach (float amount in provider.GetElementalResistance(elementalDamage.damageType))
{
resistances += amount;
}
}
resistances /= 100f;
damage += damage * boosts;
damage -= damage * resistances;
if (damage <= 0) continue;
target.TakeDamage(gameObject, damage);
}
}
What this does is crawl through each set of damages in the WeaponConfig. It then gets any boosts from the ElementalDamagerBoostProviders (put in boosts as it it was xx%, so a 10% boost is 10, not .1. The method scales it back down to fractional values before applying the damage.
Then it crawls through the target’s ElementalResistanceProviders to get the resistances. You might, for enemies, for example, give them elemental resistances in a separate class.
The damage gets the added damage boosts (damage += damage*boosts;) and then gets the resistances removed (damage -= damage * resistances), and finally the damage is applied to the enemy if there is any damage left to deliver.