# DungeonBot3000: Stats, Combat, and Items

871 views

I have to admit to an ulterior motive or two when it comes to this Challenge entry. My other project, Goblinson Crusoe, will certainly benefit from some of the iteration on stats, combat and item design that I am doing. In fact, it has already benefited. For one thing, I've polished the way I handle combat stats.

In a previous entry I talked about a system I had built to implement combat stats in GC. While the system had some good ideas, the implementation was clunky as hell, and the data file format was painfully verbose and awkward. To sum up, I built a system of stat containers, or sets, that held stats and managed the various linkages between them. Dependencies could be specified in JSON files, using specialized description formats. Stats could depend upon other stats in various ways; for example, the MaximumLife stat could depend upon Level (the character's level), IncreasedMaximumLife boosts, and so forth. The engineering challenge was to come up with a way to manage having stats and stat modifiers coming from various sources: equipment, base character stats, buffs/debuffs, and so forth.

If you read that previous entry, you can see that the first iteration of the system was ugly and the specifiers for stat dependencies were convoluted and extremely limited. The code backing that shit up was even worse, I assure you. In revisiting the idea for this challenge entry, though, I decided to clean up and simplify the way I build the stat sets. The first example from that previous entry now would look like this:

{
"MajorStatPerLevel: [["Flat", "5"]],
"MinorStatPerLevel": [["Flat", "2"]],

"Arrogance": [["Flat", "3"], ["Flat", "Level*MinorStatPerLevel"]],
"Cunning": [["Flat", "3"], ["Flat", "Level*MinorStatPerLevel"]]
}

Gone are the various "StatFlat", "CalcLinear", "Scale", etc... specifiers. In their place is a simple expression parsing system. A stat modifier is specified as a Type (can be one of Flat, Multiplier, Scale, Min or Max), and an expression string that is parsed to provide the dependency linkages. Stat values are calculated by summing the Flat contributions, multiplying them by the sum of the the Multiplier contributions + 1.0, multiplying that result by the product of the Scale contributions, and capping them by the values of the Min and Max contributions, if specified.

StatValue = SumOfFlat * (1.0 + SumOfMultiplier) * (Scale*Scale*Scale...)

Additionally, I have expanded the system to implement things like global or local mods, and mods from various sources. An action, be it an attack or other combat-related activity, requests from the combatant the relevant set of stat sets as a StatSetCollection. If it wants to use the local mods for the weapon equipped in the left hand, it requests those. If it wants to use the stats for a certain skill, it requests those. This collection is used to evaluate the final values for the stats required for an action.

A simple example. In the game currently, DB3000 can perform a spin attack. The spin attack uses the damage values specified by the equipped blades (the item system is still in development, so those are hard-coded for the moment), as well as the character's base stats and a set of damage values specified by the spin attack spell itself, in order to calculate the final damage values for the attack. Say that DB3000 has a Steel Blade equipped:

"Steel Blade": {
"MinLevel": 8,
"Random": ["PhysicalDamageLocalTiers", "LifeRegenTiers", "EnergyGenTiers"]}
},

This item structure specifies the fixed implicit (local) mods for a Steel Blade, as well as the set of mod tiers that can be randomly rolled on a Steel Blade. The SteelBladeImplicit mod StatSet looks like:

"SteelBladeImplicit":["Implicit", "Damage: 20 to 50", {
"PhysicalLow": [["Flat", "20"]],
"PhysicalHigh": [["Flat", "50"]]
}],

So a basic Steel Blade deals physical damage in the range of 20 to 50. The Spin Attack skill itself also provides a StatSet:

{
"SpinAttack": {
"PhysicalLow": [["Flat", "5+SpinAttackLevel*5 + PhysicalDamageToSpinAttackLow"]],
"PhysicalHigh": [["Flat", "10+SpinAttackLevel*8 + PhysicalDamageToSpinAttackHigh"]],
},
}

This means that using Spin Attack will add physical damage to the physical damage the blades provide, based on the skill level of the Spin Attack skill. It will also add damage based on any PhysicalDamageToSpinAttack bonuses provided by equipment or buffs or other sources, if any. When the skill is used, all of these various StatSets are concatenated into a single set (conceptually, at least) then the final value for PhysicalLow and PhyiscalHigh are determined, and a damage roll is made. A Level 1 Spin Attack would do 30 to 68 damage with a Steel Blade with no random mods.

Items can also roll a list of randomized mods. One such mod that a Steel Blade can roll comes from the PhysicalDamageLocalTiers set, which provide local (meaning, they apply only to skills using the equipped blade) physical damage modifiers:

"PhysicalDamageLocalTiers": {
"Weighting": 2,
"Tables": [
{"Level": 1, "Mods": ["Cruel"]},
{"Level": 5, "Mods": ["Barbarous", "Cruel"]},
{"Level": 10, "Mods": ["Brutal", "Barbarous", "Cruel"]},
]
},

From this tier list you can see that the physical damage mods come in 3 tiers. A Steel Blade can start to drop on Dungeon Level 8 and up, so if one drops on L8 it can only roll from the set including  "Cruel", or from the second set including "Barbarous" and "Cruel", which are specified as:

"Cruel":["Local", "Increase physical damage by 10 to 15.", {
"PhysicalLow": [["Flat", "10"]],
"PhysicalHigh": [["Flat", "15"]]
}],

"Barbarous":["Local", "Increase physical damage by 20 to 35.", {
"PhysicalLow": [["Flat", "20"]],
"PhysicalHigh": [["Flat", "35"]]
}],

If the blade drops with the Barbarous mod, then that will provide an additional flat 20 to 35 damage to the Spin Attack. These stats exist as StatSets local to the item, so they are collected only if the item is equipped and, since it is a local mod, only if the skill is using the blade, which Spin Attack does. So, once the various StatSets (from blade and from the Spin Attack skill) are collected, you end up with:

"PhysicalLow": [["Flat", "20"], ["Flat", "20"], ["Flat", "5+SpinAttackLevel*5 + PhysicalDamageToSpinAttackLow"]],
"PhysicalHigh": [["Flat", "35"], ["Flat", "50"], ["Flat", "10+SpinAttackLevel*8 + PhysicalDamageToSpinAttackHigh"]],

for the final physical damage calculation of the Spin Attack. At Level 1, that means it does 50 to 103 physical damage per hit.

I know this has been a bit long-winded. A lot of this is second- or even third-generation stuff derived from what Goblinson Crusoe already has, with many much-needed fixes, so when I'm done working on this challenge I'll be able to fold a lot of this back into GC. It should be fun.

Looking good!

can't wait to see the final boss.

Thanks, guys.

@Awoken: The final boss is gonna be spectacular. I'm pretty sure I'm friends with @khawk on facebook, so I could probably hit his profile to model the boss based on what he looks like for accuracy, but I'm gonna go with what I imagine him to look like instead. Probably around 6 foot 5, 300 lbs of raw muscle and a big-ass ban-hammer to swing around. And plenty mad, on account of being in cryo-sleep for 650 years and waking up to all his shit smashed. That ban hammer will swing freely, my friends, and wide.

11 hours ago, JTippetts said:

Probably around 6 foot 5, 300 lbs of raw muscle and a big-ass ban-hammer to swing around.

The accuracy is startling.

13 hours ago, JTippetts said:

Probably around 6 foot 5, 300 lbs of raw muscle and a big-ass ban-hammer to swing around. And plenty mad, on account of being in cryo-sleep for 650 years and waking up to all his shit smashed. That ban hammer will swing freely, my friends, and wide.﻿

lol

## Create an account

Register a new account

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.