Godot Version
4.3
Question
I’m currently making a Rougelike with complex damage system…So far I haven’t written a single function on damage, since I’m worrying too much on the future need.
Let’s say I have an attacker A, and a defenser B.
The most basic damage calculation would be simple,
B.hp -= A.attack - B.defence
Sums up the whole interaction.
Now.
What if my character has a swappable weapon, and it would increase an attack, and the defender also has a shield?
B.hp -= (A.attack + A.weapon.attack) - (B.defence + B.weapon.defense)
It’s already becoming a mess. What if I have multiple weapons?
var damage: int = 0
damage += A.attack
for weapon in A.weapons:
damage += weapon.attack
damage -= B.defence
for weapon in B.weapons:
damage -= weapon.defence
B.hp -= damage
Perfect, now I have no worry stacking up weapons.
Now. What if I want a magic weapon, that has low base stat, but bypass defence check?
...
var bypass_defence: bool = false
for weapon in A.weapons:
if weapon.is_magic:
bypass_defence = true
...
if !bypass_defence:
damage -= B.defense
Cool, but what if B has damage reduction on magic attack specifically, but the basic attack stat from A still deals full damage?
Oh wait, I also want an item that makes you deal damage base on opponent’s attack, an area buff that add 30% to fire damage, a passive effect that heals 10% of the damage you done…
==================================
I think I’ve illustrate my point enough.
I can’t just expand the damage calculation script forever.
I’ll have to make it modular somehow, and that’s where I’m stuck for the past few days.
The closest thing I have for now, is just stacking up effect after effect in an array, and ask for the defender to do calculation.
class_name DamageModifier extends Resource
var raw: int = 0
var multiplier: float = 1.0
var priority: int = 0
var trait: Array[StringName]
var modifiers: Array[DamageModifier]
modifiers.append(A.basic_attack)
modifiers.append(B.basic_defence)
for modifier_stacks in [A.weapons, A.items, B.weapons, B.items]:
for modifier in modifier_stacks:
modifiers.append[modifier]
B.take_damage(modifiers)
func take_damage(modifiers: Array[DamageModifiers])
modifiers.sort_custom(func(a, b): return a.get("priority") <= b.get("priority"))
for modifier in modifiers:
## Calculation logic here, probably
And then I look at this, go:
What if I want to heal on attack? The damage goes one way, A wouldn’t know how much it dealt…
What if the weapon does damage base on specific item effect? I’ll have to make it be aware data on other modifiers in the array…
======================================
The questions themselves don’t actually matter,
My point is, I’m always worrying about imaginary problem that doesn’t exist yet.
Once the imaginary problem got solved, I just move the goalpost and worrying more. This also can’t go on forever.
So, I’m making this post to ask, how is this typically done?
This is a solved problem right? How to construct and build an interface for complex damage calculation, is there some kind of demonstration?
Or does everyone actually just build simple system, and build hack upon hack until refactor is necessary, I’m actually fine and should just move on?
I’ve been stuck in my own head for half a week now, any opinion is welcomed.
Thanks for reading.