remaining resistance balance issues

Discussion among members of the development team.

Moderator: Forum Moderators

Darth Fool
Retired Developer
Posts: 2633
Joined: March 22nd, 2004, 11:22 pm
Location: An Earl's Roadstead

Post by Darth Fool »

ott wrote:Getting back to the topic at hand, anyone have ideas for what to do about the huge day/night swings that remain?


Based on the huge amount of changes and balancing since 0.7.1 I think it's too late to go back to multiplicative modifiers before 1.0. We are stuck with additive calculations for the moment.

The only way to restore sanity to out-of-whack additive calculations is to
  • * reduce resistances to more reasonable values, as was done with undeadspirit (60% down to 40%),
a possibility

* to make the relevant units neutral, or
I don't know that I like this, as chaos/neutrality/order to me is an expression of what environment the unit thrives in.
* to change the affected attack from a few damaging swings to more swings each doing less damage but retaining the same overall damage potential.[/list] and of course to then counterbalance these changes.
I really don't like this. Restricting non-neutral units to not have a small number of big hits is a bad idea.
Darth Fool
Retired Developer
Posts: 2633
Joined: March 22nd, 2004, 11:22 pm
Location: An Earl's Roadstead

Post by Darth Fool »

Ok, here is another possibility, which would require a little coding. All these effects are essentially

Code: Select all

1: a*(1+-b)
where a is the attack and b is the absolute value of the boni/bogi. The problem is that with multiple boni

Code: Select all

2: a*(1+-b1)(1+-b2)(1+-b3)...
rapidly gets large, so we currently use

Code: Select all

3: a*(1+-b1+-b2+-b3)
The problem with this is that if the b's are bogi, then this gets small quick. Well what if we try to get the best of both worlds and use

Code: Select all

4:a*(1+B1+B2+B3... - C1*C2*C3...)
where Bs are only boni and the Cs are bogi. Thus, boni would be additive, bogi would be multiplicative. The only other real alternative I can see would be to apply only the maximum boni and maximum bogi , but this has the undesirable effect that abilities would sometimes not make a difference for reasons that are not at first obvious.
scott
Posts: 5243
Joined: May 12th, 2004, 12:35 am
Location: San Pedro, CA

Post by scott »

Darth Fool wrote:

Code: Select all

4:a*(1+B1+B2+B3... - C1*C2*C3...)
What are some sample calculations with this one?
Hope springs eternal.
Wesnoth acronym guide.
User avatar
Elvish_Pillager
Posts: 8137
Joined: May 28th, 2004, 10:21 am
Location: Everywhere you think, nowhere you can possibly imagine.
Contact:

Post by Elvish_Pillager »

How about a Thief backstabbing a Heavy Infantry during day?
a*(1+(1)-(0.5*0.75))
0.5*0.75=0.375, thus
a*(1+(1)-(0.375))
which multiplies the attack by 1.625. Clearly not correct. You probably meant this:
a*((1+B1+B2+B3...)*(C1*C2*C3...))

which yields
a*((1+1)*(0.5*0.75))
which multiplies the attack by .75, not a bad amount. Now let us examine the Ghost being attacked during an oppoing alignment to its opponent...
a*(1*.4*.74)
=a*.3, not bad at all.
Now for the bonuses, a Konrad-led holy watered Thief backstabbing a Chocobone at Night...
a*(1+1+1+.5+.25)
*3.75, 'not excessive' given the situation Switching the alignment,
a*((1+1+1+.5)*.75)
*2.625, which is not an excessive change.

The only problem I can see with it is complexity.
It's all fun and games until someone loses a lawsuit. Oh, and by the way, sending me private messages won't work. :/ If you must contact me, there's an e-mail address listed on the website in my profile.
ott
Inactive Developer
Posts: 838
Joined: September 28th, 2004, 10:20 am

Post by ott »

Darth Fool wrote:Ok, here is another possibility, which would require a little coding. All these effects are essentially

Code: Select all

1: a*(1+-b)
where a is the attack and b is the absolute value of the boni/bogi. The problem is that with multiple boni

Code: Select all

2: a*(1+-b1)(1+-b2)(1+-b3)...
rapidly gets large, so we currently use

Code: Select all

3: a*(1+-b1+-b2+-b3)
The problem with this is that if the b's are bogi, then this gets small quick. Well what if we try to get the best of both worlds and use

Code: Select all

4:a*(1+B1+B2+B3... - C1*C2*C3...)
where Bs are only boni and the Cs are bogi. Thus, boni would be additive, bogi would be multiplicative.
OK, I've implemented a modified version of this in dr (version 1.5 attached). Run the script with the -a flag to see the
new calculations.

I've included the full output both with classic (dr.out) and new calculations (dr-alt.out) for comparison, for those who don't have perl installed. In short, the new calculations never yield a day/night swing of more than 2, which seems reasonable, but don't much affect the overall damage tables. The main effect is to increase damage during adverse time of day from 1 to 2 in many cases.

The code is fairly simple:

Code: Select all

$diff = 0; $factor = 1.0;
if ( $percent > 100 ) { # 120 -> 20
        $diff = $percent - 100;
} elsif ( $percent < 100 ) { # 80 -> 0.8
        $factor = $percent/100.0;
} # else do nothing
if ( $special =~ /backstab|charge/ ) {
        $diff *= 2;
} elsif ( $special =~ /steadfast/ ) {
        $factor *= .5;
}
if ( $_ > 0 ) {
        $diff += 25*$_;
} elsif ( $_ < 0 ) {
        $factor *= (1.0 + $_/4.0);
} # else do nothing
$finaldam = int( (1.00 + $diff/100.0) * $factor
        * $damage + 0.499999 );
$finaldam = 1 if $finaldam < 1;
against the old code of

Code: Select all

$percent += 25*$_ - 100;
$percent = 100 + 2*$percent if $special =~ /backstab|charge/;
$percent = $percent/2.0 - 50 if $special =~ /steadfast/;
$is_neg = ($percent < 0) ? -1 : 1;
$diff = $is_neg * int( ($is_neg*$percent*$damage + 49)/100 );
$finaldam = ($damage + $diff < 1) ? 1 : ($damage + $diff);
and the new effects are illustrated for example with
the Elvish Fighter

Code: Select all

blade 5-4: Elvish Rider,Huntsman,Elvish
Fighter,Drake Clasher,Huntsman-Peasant

against        -25   0  25  50  75 100
--------------------------------------
armoredfoot      2   2   3   4   4   5 <-   1.50
deepsea          3   4   5   6   7   8 <-   1.67
drakefly         3   4   6   7   8   9 <-   2.00
drakefoot        3   4   5   6   7   8 <-   1.67
dwarvishfoot     3   3   4   5   6   7 <-   1.33
elusivefoot      5   6   8   9  10  11 <-   1.60
float            4   5   6   7   9  10 <-   1.50
fly              4   5   6   7   9  10 <-   1.50
largefoot        3   4   5   6   7   8 <-   1.67
lizard           4   5   6   7   9  10 <-   1.50
mountainfoot     4   5   6   7   9  10 <-   1.50
mounted          3   4   5   6   7   8 <-   1.67
naga             4   5   6   7   9  10 <-   1.50
none             3   4   5   6   7   8 <-   1.67
orcishfoot       4   5   6   7   9  10 <-   1.50
scuttlefoot      3   4   6   7   8   9 <-   2.00
smallfoot        4   5   6   7   9  10 <-   1.50
spirit           1   2   2   3   3   4 <-   2.00
swimmer          4   5   6   7   9  10 <-   1.50
treefolk         4   5   6   7   9  10 <-   1.50
undeadfly        4   5   6   7   9  10 <-   1.50
undeadfoot       3   4   6   7   8   9 <-   2.00
undeadspirit     1   2   2   3   3   4 <-   2.00
woodland         4   5   6   7   9  10 <-   1.50
woodlandfloat    4   5   6   7   9  10 <-   1.50
against the existing calculations

Code: Select all

blade 5-4: Elvish Rider,Huntsman,Huntsman-Peasant,Drake Clasher,Elvish Fighter

against        -25   0  25  50  75 100
--------------------------------------
armoredfoot      1   3   4   5   6   7 <-   4.00
deepsea          3   4   5   6   8   9
drakefly         3   5   6   7   8   9
drakefoot        3   4   5   6   8   9
dwarvishfoot     2   4   5   6   7   8
elusivefoot      5   6   8   9  10  11
float            4   5   6   7   9  10
fly              4   5   6   7   9  10
largefoot        3   4   5   6   8   9
lizard           4   5   6   7   9  10
mountainfoot     4   5   6   7   9  10
mounted          3   4   5   6   8   9
naga             4   5   6   7   9  10
none             3   4   5   6   8   9
orcishfoot       4   5   6   7   9  10
scuttlefoot      3   5   6   7   8   9
smallfoot        4   5   6   7   9  10
spirit           1   2   3   5   6   7
swimmer          4   5   6   7   9  10
treefolk         4   5   6   7   9  10
undeadfly        4   5   6   7   9  10
undeadfoot       3   5   6   7   8   9
undeadspirit     1   2   3   5   6   7
woodland         4   5   6   7   9  10
woodlandfloat    4   5   6   7   9  10
.

What are the feelings about this? Please also look at Knights and other units before drawing conclusions. There are some significant differences even for bonuses, where the penalties from resistances seem to pull the really high damage values back a little. My subjective feeling is that these calculations slightly squish the range of damage values, which is a good thing in my book. A lv-3 Highwayman from Liberty now does

Code: Select all

undeadfly        8  11  14  16  19  22 <-   1.75
against the 0.8.8 Ghost, against

Code: Select all

undeadspirit     2   4   7  10  13  15 <-   3.50
with the classic damage calculations. I think this would allow the defense reduction in CVS for undeadspirit to be reversed.

Before making any game code changes, could someone please also do some checking that my perl rendering of the existing code is a faithful rendering, by comparing with in-game damage. Looks good to me, but I'm not infallible.
The only other real alternative I can see would be to apply only the maximum boni and maximum bogi , but this has the undesirable effect that abilities would sometimes not make a difference for reasons that are not at first
I don't like this.
User avatar
Elvish_Pillager
Posts: 8137
Joined: May 28th, 2004, 10:21 am
Location: Everywhere you think, nowhere you can possibly imagine.
Contact:

Post by Elvish_Pillager »

ott wrote:I think this would allow the defense reduction in CVS for undeadspirit to be reversed.
webcvs.wesnoth.org wrote: [resistance]
blade=40
pierce=40
impact=40
fire=100
cold=30
holy=150
[/resistance]
There has been no such change. If you are referring to the Wraith/Spectre change, it was necessary. The Wraiths didn't need invincibility in order to be overpowered; removing the invinvibility would only remove half the problem.
It's all fun and games until someone loses a lawsuit. Oh, and by the way, sending me private messages won't work. :/ If you must contact me, there's an e-mail address listed on the website in my profile.
Invisible Philosopher
Posts: 873
Joined: July 4th, 2004, 9:14 pm
Location: My imagination
Contact:

Post by Invisible Philosopher »

ott wrote:

Code: Select all

if ( $special =~ /backstab|charge/ ) {
        $diff *= 2;
Why are you multiplying the "boni"? Especially when you add to it both before and after. Shouldn't charge and backstab add 100% to it because they increase the damage rather than decreasing it?
Play a Silver Mage in the Wesvoid campaign.
ott
Inactive Developer
Posts: 838
Joined: September 28th, 2004, 10:20 am

Post by ott »

Invisible Philosopher wrote:
ott wrote:

Code: Select all

if ( $special =~ /backstab|charge/ ) {
        $diff *= 2;
Why are you multiplying the "boni"? Especially when you add to it both before and after. Shouldn't charge and backstab add 100% to it because they increase the damage rather than decreasing it?
You are right, this causes the charge bonus to disappear when the resistance modifier is 100 (ie. no special resistance or vulnerability, very common).

I think this should be

Code: Select all

if ( $special =~ /backstab|charge/ ) {
    $diff = 2*$diff + 100;
}
just like the old code. However, I'll also need to reshuffle the ordering, since the day/night bonus is not doubled either.

I'll try to post a new version of dr and the damage tables as soon as possible. Since Friday I'm having to use lynx as the forum server is unreachable from my ISP, and this version of lynx doesn't allow file uploads.
User avatar
Elvish_Pillager
Posts: 8137
Joined: May 28th, 2004, 10:21 am
Location: Everywhere you think, nowhere you can possibly imagine.
Contact:

Post by Elvish_Pillager »

ott wrote:I think this should be

Code: Select all

if ( $special =~ /backstab|charge/ ) {
    $diff = 2*$diff + 100;
}
just like the old code. However, I'll also need to reshuffle the ordering, since the day/night bonus is not doubled either.
No, you don't understand. That mechanism is still 'multiplying the boni'; it should just add 100 without doubling.
It's all fun and games until someone loses a lawsuit. Oh, and by the way, sending me private messages won't work. :/ If you must contact me, there's an e-mail address listed on the website in my profile.
Darth Fool
Retired Developer
Posts: 2633
Joined: March 22nd, 2004, 11:22 pm
Location: An Earl's Roadstead

Post by Darth Fool »

Elvish Pillager wrote:How about a Thief backstabbing a Heavy Infantry during day?
a*(1+(1)-(0.5*0.75))
0.5*0.75=0.375, thus
a*(1+(1)-(0.375))
which multiplies the attack by 1.625. Clearly not correct. You probably meant this:
a*((1+B1+B2+B3...)*(C1*C2*C3...))
I'm not sure I meant that, but I should have as that does seem more reasonable.
ott
Inactive Developer
Posts: 838
Joined: September 28th, 2004, 10:20 am

Post by ott »

Elvish Pillager wrote:No, you don't understand. That mechanism is still 'multiplying the boni'; it should just add 100 without doubling.
The resistance modifier does need to be doubled somehow -- against a -20% resistant enemy one can't just add 10 onto damage for a unit doing 10 baseline damage, that would lead to charge adding the same amount of damage whether the unit was resistant or not. The current code does this, and I think we need to retain this behaviour.

Currently: -20% resistance (resistance modifier 120) against charging unit, becomes (100+(120-100))*2 = 240 (ie. 240% of baseline damage total) plus two times any daytime and leadership modifiers. We'd need to achieve similar values, which at 100 + 20*2 + 100 = 240 my suggestion matches exactly. The bonuses are not multiplied, simply the effect of bonuses is doubled. Adverse time of day (unled) modifies this to 2.4*0.75 = 180% instead of the current (100+(120-100-25))*2 = 190%. Favourable time of day (unled) would be 290% both old and new.

Resistance modifier 80 (resistance 20%) against charging unit currently becomes (100+(80-100))*2 = 160 ie. 160% total. The above suggestion is an attempt to translate Darth Fool's suggestion into something workable (with bonuses added, then penalties multiplied), in this case (1.00+100/100.0)*0.8 ie. 160%, again matching existing calculations. The difference is that adverse time of day (unled) modifies this to 2*0.8*0.75 so 120% instead of (100+(80-100-25))*2 = 110 so 110% total currently. Favourable time, unled would be 200% new, versus 210% currently.

This all seems innocuous. The big change happens with larger resistances, which currently are seriously messed up.

So for an unled charging or backstabbing unit doing 10 baseline damage, its adverse/neutral/favourable time of day damage, against

Code: Select all

-20% resistance: 19 24 29
20% resistance: 11 16 21
60% resistance: 3 8 13
becomes with my version of Darth Fool's suggestion

Code: Select all

-20% resistance: 18 24 29
20% resistance: 12 16 20
60% resistance: 6 8 10
For 60% resistance, 1.67 day/night factor instead of the current 4.3, making high resistance units feasible again. Best of all, the expected damage values stay almost the same.
Invisible Philosopher
Posts: 873
Joined: July 4th, 2004, 9:14 pm
Location: My imagination
Contact:

Post by Invisible Philosopher »

ott wrote:The resistance modifier does need to be doubled somehow -- against a -20% resistant enemy one can't just add 10 onto damage for a unit doing 10 baseline damage, that would lead to charge adding the same amount of damage whether the unit was resistant or not. The current code does this, and I think we need to retain this behaviour.
Yeah, don't you understand how the system works? You're adding into the bonus, not the whole thing. Here are calculations using the correct scheme, with only +100% to bonus for charge.

Damage multiplier = (100% + Bonus1 + ...) * (Penalty1 * ...)

Charge, no other modifiers:
Damage multiplier = (100% + 100%) * (no penalty) = 200%

Charge, 50% resistance:
Damage multiplier = (100% + 100%) * (50%) = * 200% * 50% = 100%

See, it does work appropriately with only +100% to bonus with charge, not multiplying the bonus itself.

Mathematically, distributing the bonus:
Damage multiplier = (100% * (Penalty1 * ...)) + (100%[from charge] * (Penalty1 * ...))

Every bonus is effectively multiplied by the penalties, so the penalties are fully effective. Multiple penalties don't reduce the damage in a ridiculous way (multiplying by below 0%, stopped only by minimum damage of 1, was caused by adding together penalties), and avoiding multiplying together the bonuses makes damages not become too huge. It is a very good scheme, IMO. Just try to understand how the formula really works and hopefully you'll understand...
Play a Silver Mage in the Wesvoid campaign.
dms
Posts: 56
Joined: August 11th, 2004, 9:08 pm
Location: New Zealand

Post by dms »

So, bonuses and penalties should be separated and handled differently?

meaning the damage increase for -20% resistance may be quite different from the damage decrease from 20% resistance?
ott
Inactive Developer
Posts: 838
Joined: September 28th, 2004, 10:20 am

Post by ott »

Invisible Philosopher wrote:Yeah, don't you understand how the system works? You're adding into the bonus, not the whole thing. Here are calculations using the correct scheme, with only +100% to bonus for charge.
I'm clearly failing to communicate my meaning, perhaps I can blame my poor phrasing on having to type into lynx via a high latency link.

A lawful charging unit currently does 250% damage during the day, not 225% as you seem to be suggesting. We should not change the current damage values too much, to avoid having to rebalance all the campaigns. I am proposing using Darth Fool's separation of bonuses and penalties, making bonuses additive and penalties multiplicative. However, we need to tweak this by ensuring bonuses are doubled for charging/backstabbing units, otherwise the current damage would be reduced. Are you suggesting that led charging units currently do too much damage?

This is a perl version of the kind of code I'm proposing (after corrections and more useful variable names):

Code: Select all

$bonus = 100; $penalty = 1.0;
if ( $percent > 100 ) { $bonus = $percent } elsif ( $percent < 100 ) { $penalty = $percent/100.0 }
if ( $_ > 0 ) { $bonus += 25*$_ } elsif ( $_ < 0 ) { $penalty *= (1.0 + $_/4.0) }
if ( $special =~ /backstab|charge/ ) { $bonus *= 2 } elsif ( $special =~ /steadfast/ ) { $penalty *= 0.5 }
$finaldam = int( ($bonus/100.0) * $penalty * $damage + 0.49999 );
$finaldam = 1 if $finaldam < 1;
which gives

Code: Select all

blade 10-3 backstab: Nightgaunt

against        -25   0  25  50  75 100
--------------------------------------
armoredfoot      7  10  12  15  17  20 <-   1.71
deepsea         12  16  20  24  28  32 <-   1.67
drakefly        13  18  22  27  31  36 <-   1.69
drakefoot       12  16  20  24  28  32 <-   1.67
dummy0          30  40  45  50  55  60 <-   1.50
dummy1           1   1   1   1   1   1 <-   1.00
dwarvishfoot    10  14  17  21  24  28 <-   1.70
elusivefoot     19  26  31  36  41  46 <-   1.63
float           15  20  25  30  35  40 <-   1.67
fly             15  20  25  30  35  40 <-   1.67
largefoot       12  16  20  24  28  32 <-   1.67
lizard          15  20  25  30  35  40 <-   1.67
mountainfoot    15  20  25  30  35  40 <-   1.67
mounted         12  16  20  24  28  32 <-   1.67
naga            15  20  25  30  35  40 <-   1.67
none            12  16  20  24  28  32 <-   1.67
orcishfoot      15  20  25  30  35  40 <-   1.67
scuttlefoot     13  18  22  27  31  36 <-   1.69
smallfoot       15  20  25  30  35  40 <-   1.67
spirit           6   8  10  12  14  16 <-   1.67
swimmer         15  20  25  30  35  40 <-   1.67
treefolk        15  20  25  30  35  40 <-   1.67
undeadfly       15  20  25  30  35  40 <-   1.67
undeadfoot      13  18  22  27  31  36 <-   1.69
undeadspirit     6   8  10  12  14  16 <-   1.67
woodland        15  20  25  30  35  40 <-   1.67
woodlandfloat   15  20  25  30  35  40 <-   1.67
against the current

Code: Select all

blade 10-3 backstab: Nightgaunt

against        -25   0  25  50  75 100
--------------------------------------
armoredfoot      5  10  15  20  25  30 <-   3.00
deepsea         11  16  21  26  31  36 <-   1.91
drakefly        13  18  23  28  33  38 <-   1.77
drakefoot       11  16  21  26  31  36 <-   1.91
dummy0          35  40  45  50  55  60 <-   1.29
dummy1           1   1   5  10  15  20 <-   5.00
dwarvishfoot     9  14  19  24  29  34 <-   2.11
elusivefoot     21  26  31  36  41  46 <-   1.48
float           15  20  25  30  35  40 <-   1.67
fly             15  20  25  30  35  40 <-   1.67
largefoot       11  16  21  26  31  36 <-   1.91
lizard          15  20  25  30  35  40 <-   1.67
mountainfoot    15  20  25  30  35  40 <-   1.67
mounted         11  16  21  26  31  36 <-   1.91
naga            15  20  25  30  35  40 <-   1.67
none            11  16  21  26  31  36 <-   1.91
orcishfoot      15  20  25  30  35  40 <-   1.67
scuttlefoot     13  18  23  28  33  38 <-   1.77
smallfoot       15  20  25  30  35  40 <-   1.67
spirit           3   8  13  18  23  28 <-   4.33
swimmer         15  20  25  30  35  40 <-   1.67
treefolk        15  20  25  30  35  40 <-   1.67
undeadfly       15  20  25  30  35  40 <-   1.67
undeadfoot      13  18  23  28  33  38 <-   1.77
undeadspirit     3   8  13  18  23  28 <-   4.33
woodland        15  20  25  30  35  40 <-   1.67
woodlandfloat   15  20  25  30  35  40 <-   1.67
which I think is a sensible change, with most damage quite similar if not the same, but against high defense the damage is definitely more sane.

I've added movetypes dummy0 and dummy1 representing 200 and 0 defense modifiers, respectively 0% and 100% defense, to show that the modified DF scheme gives sensible results even in these cases, whereas the current scheme results in large damage during the unit's favourable time of day, even against a unit with 100% defense against that attack.

I don't think the current pure additive scheme in 0.8.8 makes sense with high defense values, and I think it would be sad if all the high defense values in the game had to be removed because of a weakness of the damage algorithm that is easily fixed.

Could IP, EP or DF work out how your respective variations on DF's mixed additive/multiplicative proposal actually fare in this example? Nightgaunt is nice and easy to calculate with 10 damage per swing and backstab acting just like charge.
Invisible Philosopher
Posts: 873
Joined: July 4th, 2004, 9:14 pm
Location: My imagination
Contact:

Post by Invisible Philosopher »

ott wrote:A lawful charging unit currently does 250% damage during the day, not 225% as you seem to be suggesting. We should not change the current damage values too much, to avoid having to rebalance all the campaigns.
You are correct about the current effects (for situations in which there are no penalties, at least), but who cares? That has only been true for a few versions, since we made charge and backstab multiplicative (0.8.4). The campaigns haven't even had time to be balanced with that, or if they had time, they weren't, mostly. Besides, this proposal is a somewhat big change, let's not leave hacky details in it that run counter to the goal of the idea. And 250% isn't so different from 225% that it would throw off balancing very much, assuming the campaign wasn't played with only horsemen.
ott wrote:Are you suggesting that led charging units currently do too much damage?
Yes, that is the entire reason we made damage additive in the first place: units with too many bonuses did too much damage. If we don't care about them doing high amounts of damage, why aren't we just using multiplicative damage calculations for everything?
ott wrote:I am proposing using Darth Fool's separation of bonuses and penalties, making bonuses additive and penalties multiplicative. However, we need to tweak this by ensuring bonuses are doubled for charging/backstabbing units, otherwise the current damage would be reduced.
Contradictory. Either we use the scheme or we don't. Tweaks like that make the beautifully balanced scheme be wrecked and ruined beyond almost all use they had originally, sending them into a quagmire of complexity.
Play a Silver Mage in the Wesvoid campaign.
Post Reply