top of page
Writer's pictureNostalgiq

RPG Builder Mod: Additional Effect Bonus Damage through Multiple Stats

Updated: Feb 7


Intro

This enhancement idea came from Zed, over on the RPGB Discord, where he suggested if Effects could scale with more than one stat it would allow for more dynamic gameplay design. I agree with that idea, and think it would be quite useful to add, so let's do that in this post. Thomas mentioned this is a feature that should be coming in a future version of RPGB, but if you want it now, you can use the code below.

 

What will the final product look like?

Instead of only being able to add a single Stat for Effect bonus damage, you can add them in a List, which looks like this:

The bonus damage calculation for the screenshot above would work like this:

  • If player has 50 Strength -> Bonus Damage = 50*.25 = 12.5

  • If player has 25 Dexterity -> Bonus Damage = 25*.15 = 2.25

  • If player has 100 Agility-> Bonus Damage = 100*.05 = 5

  • Total Bonus Damage = 12.5 + 2.25 + 5 = 19.75

What scripts do we need to touch?

Go ahead and open up the following RPGB scripts:

  • RPGEffect.cs

  • RPGBuilderEditorFields.cs

  • RPGBuilderEditorEffectModule.cs

  • CombatCalculations.cs

 

There is no guarantee or future support offered regarding these changes. I tested them out at the time I wrote them, and they worked within the scope of my needs. However, I am not the author of RPGB and therefore am not the authoritative source on whether these mods are complete. Use at your own risk, and always backup your projects.


Modded RPGB v2.0.7.1. New code additions are always highlighted in green, whilst RPGB code is always highlighted in blue.


The start and end of mods will have // Delora Start and // Delora End at the top and bottom.


!! Back up or version control your code before making modifications !!


Mod RPGEffect.cs

The first thing we'll want to modify is the Effect class itself. This class has all of the variables that allow Effects to work. We'll need to add a new variable type, in particular one that includes both the Stat ID and the Stat Damage Modifier. This will allow us to couple the two together and maintain their relationship through a serialized list. I defined it below, and put it near the top of the class as follows:

...
public enum DISPEL_TYPE
{
    EffectType,
    EffectTag,
    Effect
}

// Delora Start
[System.Serializable]
public class STAT_BONUS_DAMAGE
{
    public int DamageStatID = -1;
    public float DamageStatModifier = 0.0f;
}
// Delora End

[Serializable]
public class RPGEffectRankData
{
    public bool ShowedInEditor;
...

Create an empty list of these further down in the class itself:

...
public float requiredEffectDamageModifier;

// Delora Start
[RPGDataList] public List<STAT_BONUS_DAMAGE> StatBonusDamageEntries = new List<STAT_BONUS_DAMAGE>();
// Delora End

[StatID] public int damageStatID = -1;
public float damageStatModifier;
...

Once that's complete you'll need to manage the actual saving of the data. This happens way down near the bottom of the file, and can be done by adding the following:

...
original.requiredEffectID = copied.requiredEffectID;
original.requiredEffectDamageModifier = copied.requiredEffectDamageModifier;

// Delora Start
original.StatBonusDamageEntries = new List<STAT_BONUS_DAMAGE>();
for (var index = 0; index < copied.StatBonusDamageEntries.Count; index++)
{
    STAT_BONUS_DAMAGE newRef = new STAT_BONUS_DAMAGE();
    newRef.DamageStatID = copied.StatBonusDamageEntries[index].DamageStatID;
    newRef.DamageStatModifier = copied.StatBonusDamageEntries[index].DamageStatModifier;
    original.StatBonusDamageEntries.Add(newRef);
}
// Delora End

original.damageStatID = copied.damageStatID;
original.damageStatModifier = copied.damageStatModifier;
...

Mod RPGBuilderEditorFields.cs

This script modification is what helps draw the GUI whenever we click the Add Bonus Damage Stat button and create a new record. It's a big chunk of code you can add basically anywhere in the file:

...   RPGBuilderEditorUtility.EndHorizontalMargin(RPGBuilderEditor.Instance.LongHorizontalMargin, true);
    GUILayout.Space(10);
    return visualEffects;
}

// Delora Start
public static List<RPGEffect.STAT_BONUS_DAMAGE> DrawStatDamageList(List<RPGEffect.STAT_BONUS_DAMAGE> statStructs)
{
    if (DrawHorizontalAddButton("Add Stat Damage Bonus", true))
    {
        statStructs.Add(new RPGEffect.STAT_BONUS_DAMAGE());
    }
    
    for (var a = 0; a < statStructs.Count; a++)
    {
        GUILayout.Space(10);

        if (DrawSmallRemoveButton())
        {
            statStructs.RemoveAt(a);
            return statStructs;
        }
        
        statStructs[a].DamageStatID = DrawDatabaseEntryField(statStructs[a].DamageStatID, "Stat", "Stat Damage", "");
        
        if (statStructs[a].DamageStatID != -1)
        {
            statStructs[a].DamageStatModifier = DrawHorizontalFloatField(
                "Stat Damage Modifier (%" +
                "1)",
                "The percentage of this stat added as damage",
                RPGBuilderEditor.Instance.FieldHeight, 
                statStructs[a].DamageStatModifier
                );
        }
        
        GUILayout.Space(10);
    }
    GUILayout.Space(10);
    
    return statStructs; 
}
// Delora End

public static List<SoundEntry> DrawSoundsList(List<SoundEntry> sounds)
{
    if (DrawHorizontalAddButton("Add Sound", true))
...

Mod RPGBuilderEditorEffectModule.cs

Next we need to touch the bit of code that manages displaying the Stat Bonus Damage List in the RPGB Editor.


First find the bit of code that matches this:

currentEntry.ranks[i].damageStatID =
    RPGBuilderEditorFields.DrawDatabaseEntryField(currentEntry.ranks[i].damageStatID,
        "Stat", "Stat Damage", "");

if (currentEntry.ranks[i].damageStatID != -1)
{
    currentEntry.ranks[i].damageStatModifier =
        RPGBuilderEditorFields.DrawHorizontalFloatField("Stat Damage Modifier",
            "The percentage of this stat added as damage",
            RPGBuilderEditor.Instance.FieldHeight,
            currentEntry.ranks[i].damageStatModifier);
}

currentEntry.ranks[i].skillModifierID =
    RPGBuilderEditorFields.DrawDatabaseEntryField(currentEntry.ranks[i].skillModifierID,
        "Skill", "Skill", "");

if (currentEntry.ranks[i].skillModifierID != -1)
{
    currentEntry.ranks[i].skillModifier =
        RPGBuilderEditorFields.DrawHorizontalFloatField(
            "Skill Damage", "How much damage is added by skill level",
            RPGBuilderEditor.Instance.FieldHeight, currentEntry.ranks[i].skillModifier);
}

We're going to replace the code in yellow with code that uses the lists, and we're going to move the part in orange up so that it's above the Add Stat Bonus Damage button. In the end it looks like this:

currentEntry.ranks[i].skillModifierID =
    RPGBuilderEditorFields.DrawDatabaseEntryField(currentEntry.ranks[i].skillModifierID,
        "Skill", "Skill", "");

if (currentEntry.ranks[i].skillModifierID != -1)
{
    currentEntry.ranks[i].skillModifier =
        RPGBuilderEditorFields.DrawHorizontalFloatField(
            "Skill Damage", "How much damage is added by skill level",
            RPGBuilderEditor.Instance.FieldHeight, currentEntry.ranks[i].skillModifier);
}

// Delora Start
GUILayout.Space(20);
currentEntry.ranks[i].StatBonusDamageEntries = RPGBuilderEditorFields.DrawStatDamageList(currentEntry.ranks[i].StatBonusDamageEntries);
GUILayout.Space(5);
// Delora End

Mod CombatCalculations.cs

Finally we need to change the way we calculate the bonus damage. RPGB will now iterate through the list instead of using just one pair of variables for the calculation. Both Damage and Healing use the method AddRequiredEffectBonus to calculate the bonus, and since we aren't modifying Healing in this post, I'm going to create a new method for the Bonus Damage calculation to use called AddStatBonusDamage as follows:

...
private static float AddStatBonusBonus(CombatEntity casterEntity, RPGEffect.RPGEffectRankData effectRank, float damage)
{
    if (casterEntity == null) return damage;
    damage += CombatUtilities.GetCurrentStatValue(casterEntity, effectRank.damageStatID) * (effectRank.damageStatModifier / 100);
    return damage;
}

// Delora Start
private static float AddStatBonusDamage(CombatEntity casterEntity, RPGEffect.STAT_BONUS_DAMAGE bonusDamage, float damage)
{
    if (casterEntity == null) return damage;
    damage += CombatUtilities.GetCurrentStatValue(casterEntity, bonusDamage.DamageStatID) * (bonusDamage.DamageStatModifier / 100);
    return damage;
}
// Delora End

private static float AddBaseDamage(CombatEntity casterEntity, RPGEffect.RPGEffectRankData effectRank, float damage)
{
    if (casterEntity == null) return damage;
    foreach (var t in casterEntity.GetStats())
    {
        foreach (var t1 in t.Value.stat.statBonuses.Where(t1 => t1.statType == RPGStat.STAT_TYPE.BASE_DAMAGE_TYPE))
        {
            if (effectRank.mainDamageType != t1.MainDamageType) continue;
            damage += t.Value.currentValue * t1.modifyValue;
        }
    }

    return damage;
}
...

The damage calculation itself happens in the same script, in a method named DamageCalculation. You'll want to delete or comment out this line:

if (effectRank.damageStatID != -1 && effectRank.damageStatModifier > 0) result.DamageAmount = AddStatBonusBonus(casterEntity, effectRank, result.DamageAmount);

and replace it with this one:

// Delora Start
if (effectRank.StatBonusDamageEntries.Count > 0)
{
    float bonusDamage = 0;
    Debug.Log("bonus damage: " + bonusDamage);
    foreach (RPGEffect.STAT_BONUS_DAMAGE bonus in effectRank.StatBonusDamageEntries)
    {
        if (bonus.DamageStatID != -1 && bonus.DamageStatModifier > 0) bonusDamage += AddStatBonusDamage(casterEntity, bonus, result.DamageAmount);
        Debug.Log("bonus damage: " + bonusDamage);
    }
    result.DamageAmount = bonusDamage;
    Debug.Log("Final Bonus Damage from stats: " + bonusDamage);
}
// Delora End

Final Steps

If you already have data stored into each one of the Bonus Damage slots RPGB comes with, you can load them into the new list created for each effect by putting this code into RPGBEditorEffectModule.cs, opening each Effect in RPGB, and clicking Save. Once that's done you can delete the code in yellow.

...
// Delora Start
GUILayout.Space(20);
currentEntry.ranks[i].StatBonusDamageEntries = RPGBuilderEditorFields.DrawStatDamageList(currentEntry.ranks[i].StatBonusDamageEntries);
GUILayout.Space(5);
// Delora End

if (currentEntry.ranks[i].damageStatID != -1)
{
    if (currentEntry.ranks[i].StatBonusDamageEntries.Count == 0)
    {
        currentEntry.ranks[i].StatBonusDamageEntries.Add(new RPGEffect.STAT_BONUS_DAMAGE());
    }
    currentEntry.ranks[i].StatBonusDamageEntries[0].DamageStatID = currentEntry.ranks[i].damageStatID;
    currentEntry.ranks[i].StatBonusDamageEntries[0].DamageStatModifier = currentEntry.ranks[i].damageStatModifier;
}
...

The End

Next steps could be to include similar changes to Healing so it can also depend on more than one stat. With this guide you should be able to implement that yourself if you so desire. Enjoy!





Comments


Commenting has been turned off.
bottom of page