FUN WITH FORMULAS

Posts

Red_Nova
Sir Redd of Novus: He who made Prayer of the Faithless that one time, and that was pretty dang rad! :D
9192
Put this in the script section:
class Game_Battler < Game_BattlerBase 

  def drain_half_damage(damage)
    change_hp(damage/2, false) 
    return damage #don't forget this line if you want this to deal damage 
  end 
  
end

Then call it by putting this in the damage formula:

a.drain_half_damage(/your damage formula here/)
The formula I'm using for Binding Wyrds for all the damaging effects is actually taken from the tabletop game I designed that it is based on. It's a pretty simple formula...if you have dice around, otherwise its a bit wonky to do in RPGMaker, so I have a sub-routine in Game_battler to do the dice rolls.

In essence, its damage_stat - defense_randomizer(reduction_stat * 2)

With defense randomizer rolling a dice (rand function) for each point of defense its given, and 1/3 of the time reducing damage by 1. Given my attack values and HP are fairly low comparatively, this leads to a rather stable set of values for defense that is pretty reliable, but not set in stone.

In example, attacker has 5 attack, defender has 3 defense. So it goes 5 - randomizer(6). Best case scenario, all 6 points reduce damage, so the attack does no damage. Worst case scenario, none of the points reduce damage, so the defender receives 5 damage. On average, the defender will receive 3 damage though (6/3 = 2).

This makes defense a very important stat, as high defense can nullify a full attack if you're lucky, but doesn't make high defense enemies completely invulnerable. It also lets me play with formulas, as some 'armor piercing' attacks only roll defense, not defense*2 for example, and any attack that does set damage without counting defense, such as poisons/burning/deals exactly 1 damage, are very valuable against high defense foes.

Then again, I'm a bit of a tabletop nerd, so I like dealing with balanced odds and such.
unity
You're magical to me.
12540
author=Red_Nova
Put this in the script section:
class Game_Battler < Game_BattlerBase 

  def drain_half_damage(damage)
    change_hp(damage/2, false) 
    return damage #don't forget this line if you want this to deal damage 
  end 
  
end


Then call it by putting this in the damage formula:

a.drain_half_damage(/your damage formula here/)


Wow! Super cool, thanks! :D
Is there any way to show the amount healed on the character like when you use a regular drain move?
Craze
why would i heal when i could equip a morningstar
15150
this is ace right? if you're using yanfly engine you should be able to use a popup method really easily. but i'm on mobile falling asleep soooo

answer: YES

can i help you in the next 8 hours: NO
@unity> should be: @log_window.add_text(sprintf("drained %d damage!", damage_drained))
add that somewhere before the return line
unity
You're magical to me.
12540
author=karins_soulkeeper
@unity> should be: @log_window.add_text(sprintf("drained %d damage!", damage_drained))
add that somewhere before the return line


For some reason, that just made the damage into NULL.

author=Craze
this is ace right? if you're using yanfly engine you should be able to use a popup method really easily. but i'm on mobile falling asleep soooo

answer: YES

can i help you in the next 8 hours: NO


Yeah, I'm using Yanfly's battle system in Ace, so it sounds like a popup method is exactly what I need. Looking at the battle engine script, would it be something to do with the user.create_popup command?

...And I think I just derailed the topic to solve a personal issue with my game. Sorry about that ^^;;;;;
Red_Nova
Sir Redd of Novus: He who made Prayer of the Faithless that one time, and that was pretty dang rad! :D
9192
author=unity
author=karins_soulkeeper
@unity> should be: @log_window.add_text(sprintf("drained %d damage!", damage_drained))
add that somewhere before the return line
For some reason, that just made the damage into NULL.


That wouldn't work. Log_window is in Scene_battle and the formula is in game_BattlerBase. I'm trying to figure out how to do it in ace...

Yeah, I'm using Yanfly's battle system in Ace, so it sounds like a popup method is exactly what I need. Looking at the battle engine script, would it be something to do with the user.create_popup command?

...And I think I just derailed the topic to solve a personal issue with my game. Sorry about that ^^;;;;;


Nah. If it's about formulas, then it's on topic.
Marrend
Guardian of the Description Thread
21781
This thread has me thinking about how Heroes of Might and Magic calculates damage. In that series, creatures have a damage range, an "attack power" and a "defense power". Damage range aside, each point of difference between the attacker's attack power and defender's defense power is translated into a 5% modifier to the base damage. So, for example, if a.atk = 25 and b.def = 14 (11 point difference), the modifier to the base damage would be 155%. Switching the numbers around, it would be 45% of the base damage. Obviously, a 0-point difference means a damage multiplier of 100%.

This system has built-in caps, of course. The lowest percentage might be 25% or 30% of the base damage (I'm inclined to think 30%), whereas highest percentage is 300% of the base damage.


*Edit: Also, the information regarding attack power, defense power, and damage range can be viewed with a left-click. The game doesn't approximate the potential damage that can be done by attacking DudeX with DudeY (at least to my knowledge), but, the basic information is accessible!
Craze
why would i heal when i could equip a morningstar
15150
unity try just putting


txt = [damage/2].floor
create_popup(txt.to_s, "HP_HEAL")


above the return and see if that works
unity
You're magical to me.
12540
That changes the damage to "Null"

The script now looks like this:



Marrend
Guardian of the Description Thread
21781
Shouldn't it be regular parenthesis surrounding "damage/2" rather than square brackets? I dunno. I'm afraid I'm not too familiar with this kind of thing!
unity
You're magical to me.
12540
THAT WORKS! THANKS CRAZE AND MARREND! :DDDDDDDDDDDDDD
Marrend
Guardian of the Description Thread
21781
Holy hell, that WORKED?


Er, I mean...


...Awesome!
While initially I was a big fan of (100 / (100 + DEF)) * ATK, further investigation makes me less satisfied.

At 100 ATK and 100 DEF you do 50 damage per hit. But at 200 ATK and 200 DEF you do only 67 damage per hit, not (as one might expect) 100 damage. In other words, DEF scales better than ATK. And you can't intuitively guess how raising attack and defense will impact the end result.

Thus balancing can become a problem. At a narrow range of values it isn't very apparent, but wide variations (from the beginning to the end of a game, for example) are problematic. At 100 ATK, 100 DEF, and 1000 HP, it takes 20 hits to kill the target. But at 500 ATK, 500 DEF, and 5000 HP, it takes 60 hits. The larger the numbers the more out of control this gets. The scaling doesn't make intuitive sense.

When the formula does make sense is when either ATK or DEF is held constant. So if you double ATK against constant DEF, you halve the hits to kill. If you increase DEF by a constant, hits to kill increase also by a constant. I think this is why the formula is so popular with PvP, since there you're often itemizing against a singular foe and that foe's specific stats. But in most JRPGs you're dealing with dozens of different monsters, making the fluctuations in damage just confusing.

To reiterate: the formula is wonderful when looking at changes in only ATK or only DEF, but breaks down with both are changing.


Below is my preferred damage formula:

ATK / (DEF / ATK + 1)

(for those mathematically inclined, the above formula is equivalent to (ATK ^ 2) / (ATK + DEF), which makes it easier to see how it scales)

This formula has a number of properties that I think make it intuitive in an RPG with tons of different monsters and large changes in overall statistics.

First, damage scales cleanly as the game progresses and both ATK and DEF increase. So at 100 ATK, 100 DEF, you do 50 damage. At 200 ATK, 200 DEF, you do 100 damage. So on and so forth.

"Hits to kill" scales normally too. At 100 ATK, 100 DEF it takes 20 hits to kill a 1000 health target. Multiply all the numbers by 10 and you still take 20 hits to kill the target.

The impact per point of defense scales off of ATK. So 10 DEF early game is worth a lot more than 10 DEF late game, as any normal player of your game would expect.

Damage will never be higher than ATK. And if you multiply the damage by two, the damage will be approximately equal to ATK at any given point in the game.

The new formula isn't perfect, of course, and there are trade-offs. For example, if DEF is held constant and you double your ATK, you more than double your damage. And there's no easy way to describe the exact effects of ATK or DEF to the player like there is with other formulas. (For example, with (100 / (100 + DEF)) * ATK, one can say every point of DEF increases your effective health by 1%, and doubling your ATK doubles your damage.) So while the overall scaling may make intuitive sense, it's difficult for the player to make any sort of mental calculation to know how a change in equipment will impact their damage.

Still, I find it really pleasant to work with. And some of the quirks can actually be used to your advantage. For instance, the fact that doubling your ATK more than doubles your damage means that there's value in characters that are specialized as opposed to having everyone a jack-of-all-trades. And if you really want straight percent damage increase, you can just code "this attack does 50% extra damage" rather than rely on your damage formula.

Either way, I'm just offering out another alternative for people if they're interested.

While I'm on the topic, I might as well add that if you want to use the (100 / (100 + DEF)) * ATK formula, it might be in your best interest too hold the DEF of the enemies relatively constant. Doing so makes the scaling from the player side very straightforward and balancing on the monster side not so much of a hassle. And if you really want to make it easy on yourself, keep the player DEF around the 100 value as well (like 50-300) and make all equipment give HP with some sort of standard armor-class based DEF value. So a late-game robe and late-game plate mail may have similar +HP but very different +DEF. Meanwhile, early game plate mail and late game plate mail may have similar +DEF but vastly different +HP. I hope that makes sense. It's just a nice way of giving more meaning to the differences in armor besides the standard "plate mail > robes at any given point in the game".
The issue isn't that defense varies, it's that you scaled HP up way too high at 5000. An increase of 4000 HP isn't even remotely equivalent to increasing defense by 400 with that formula, as they don't have a straight 1:10 relationship. To determine your HP scaling you reverse-engineer the formula, starting with how many hits you want an average character to take before they are knocked out. Then you do that again at a high level and smooth that curve. If a character at level 1 starts with 10 attack and defense and you want them to survive ten hits, then they have about 300 HP. A level 50 character with 100 attack and defense has 800 HP. The numbers you choose are equally important to the formula you're using.

I should clarify that this is actually with ATT * (100 / (25 + DEF)). Even in my quoted posting I note that you need to modify your denominator depending on how much you want to value a given statistic and its baseline effectiveness.
Marrend
Guardian of the Description Thread
21781
How is atk/(def/atk+1) equivalent to atk^2/(atk+def)? Like, if you plug in an atk of 5 and a def of 7, the first formula would (essentially) return 30/7 whereas the second returns 25/12 ?

Ugh. I'm spending waaaaay to much brainpower on this.
author=Red_Nova
author=unity
author=karins_soulkeeper
@unity> should be: @log_window.add_text(sprintf("drained %d damage!", damage_drained))
add that somewhere before the return line
For some reason, that just made the damage into NULL.
That wouldn't work. Log_window is in Scene_battle and the formula is in game_BattlerBase. I'm trying to figure out how to do it in ace...
Oh. Hehe, sorry bout that.

If my maths is right, it should be (atk^2 + atk) / def and not atk^2/(atk+def)
Yep, deffo that. It returns 30/7 as well.
author=Marrend
How is atk/(def/atk+1) equivalent to atk^2/(atk+def)? Like, if you plug in an atk of 5 and a def of 7, the first formula would (essentially) return 30/7 whereas the second returns 25/12 ?
My formulas are correct. You just need to remember the order of operations. So the first formula, using 5 and 7, becomes 5/(7/5+1). It's not 7/(5+1) on the bottom, but rather (7/5)+1, which is the same as (7/5)+(5/5), or 12/5. Thus it's 5/(12/5) or 25/12, which is the same as the 2nd formula.

author=Jude
The issue isn't that defense varies, it's that you scaled HP up way too high at 5000.... To determine your HP scaling you reverse-engineer the formula, starting with how many hits you want an average character to take before they are knocked out.... If a character at level 1 starts with 10 attack and defense and you want them to survive ten hits, then they have about 300 HP. A level 50 character with 100 attack and defense has 800 HP. The numbers you choose are equally important to the formula you're using.
The bolded part is exactly what I am trying to avoid. Unfortunately, having a formula like yours absolutely requires you to do the math. Consider the following example:

Using your formula, 20 ATK, 20 DEF, and 1000 HP takes 22.5 hits to kill.
400 ATK, 400 DEF requires around 2120 HP to retain 22.5 hits to kill.
4000 ATK, 4000 DEF requires only around 2240 HP to retain 22.5 hits to kill.

And no, that's not a typo. If ATK and DEF are increased by 3600, HP needs to increase only 120. That's nonsensical to the average person. It doesn't, by the way, get better if you make DEF proportionately smaller than ATK. The same scaling issue persists.

Now, as you said, you can reverse-engineer every number. But why take that time if you don't have to?

author=hedge1
The larger the numbers the more out of control this gets. The scaling doesn't make intuitive sense.
I said this for a reason. When you're dealing with a nice narrow range of numbers your formula works well. But if you're going to have large variations in stats, like from 400 to 4000, then you'll run into problems.

Just so I'm clear here, I'm not saying my formula is without problems. For example, if you double ATK using my formula you more than double damage. That means spell power is not intuitively comparable. Depending on the game this could be disastrous. But I'm dealing with JRPGs where such scaling is actually the norm, so I consider this drawback acceptable given the advantages elsewhere.

It's also worth noting that your formula, ATK * (100 / (25 + DEF)) is of the form ATK * (X / (Y + DEF)), with X = 100 and Y = 25. My formula simply takes X = ATK and Y = ATK. I could choose, if I wanted, X = LV of attacker, and Y = LV of defender. Whatever one picks for X and Y, though, really can influence what you can do (or can't do) with the numbers. And if your game is going to deal with a wide range of values, X and Y need to scale with them or else you get weird outcomes like the HP example I showed above.
If you use a formula of the form ATK * (X / (Y + DEF)) where X and Y is static, you're best of keeping enemy defense constant (enemy warriors and mages don't have to have the same defense, but a late game enemy warrior should have the same defense as an early game warrior) and increasing player defense slowly, if at all. You can also go the route of increasing enemy attack exponentially, but then you can't have confusion in your game.
unity
You're magical to me.
12540
Um, hate to bring this back up, but I found an error with the script snippet damage formula. It doesn't prevent decimals.



Any alteration to the script that could prevent this would be totally appreciated! ^_^