balanced_fight_mode patch

Discussion among members of the development team.

Moderator: Forum Moderators

ignatius
Posts: 35
Joined: December 3rd, 2004, 11:59 am

balanced_fight_mode patch

Post by ignatius »

First of all, I want to thank Dave and the others for this great game, which go me hooked to the computer for the last 2 weeks. I did HttT on medium and sometimes found myself resorting to the save/load cheat. My next project will be to play a campaign w/o save/loading mid-scenario, but as I'm not too frustration tolerant, I decided that in the default version, the fight results were a bit too random for my taste. That's how I came up with the following patch:

balanced_fight_mode patch
-------------------------

- Goals

The aim of this patch is to modify the way fight results are
calculated to suppress extreme outcomes with as few changes
to the current game mechanics as possible. In the ideal case,
the player would not notice its presence during play, except
for the fact that he will find himself to having to do fewer
save-loads due to rotten (vs. the ususal bad) luck.

- What the patch does

For each attack with more than one try, the patch supresses
the least likely outcome, which is either all-hits (if the
hit probability is <50%) or all-misses (if the hit probability
is >50%) and balances this by increasing/reducing the hit
probability in the opposite case such that the EV is constant.
The patch is only active during the last round of fighting, so
tactical aspects like killing-before-getting-killed or abilities
like firststrike are not affected. Also, the patch has no effect
on weapons such as the pistol attack of Dwarvish Thunderer with
a single attempt.

Consider the following example:

Your mage has 3 tries to hit with a probability of 70%. Assuming
you have missed the first 2 tries, then you will always his on
the last try. OTOH, if you hit on your first 2 tries, then the
probability to also hit on the last strike is reduced from
70% to 65% (64.49% would be optimal, but wesnoth operates with
integer percentages). The EV for the inflicted damage remains
exactly the same as 2.7%, the chance to miss 3 times in a row,
results in an increased EV of 0.027 hits which is exactly balanced
by reducing the last hit probability by 5.51% after 2 hits
(probability 49%) which results in a decreased EV of
0.49*0.0551 = 0.027 hits.

The spectrum of possible outcomes thus changes from

0/1/2/3 hits: 2.7 / 18.9 / 44.1 / 34.3 %
to 0 / 21.6 / 46.8 / 31.6 %

As you can see, the changes should be small enough to go
unnoticed with units with 3 or more strikes. The most
visible change will be with units that only have 2 strikes:
A horseman on open terrain (hit probability 60%) will always
hit at least once, which should make combat with mounted troops
a bit less of a crapshoot.

- Download and Installation (Linux)

You can get the patch from

http://tph.tuwien.ac.at/~oemer/wesnoth/

The filename is

wesnoth-0.8.8-balanced_fight_mode.patch

and is only tested with wesnoth version 0.8.8.

After downloading the patch, change into the
wesnoth source directory and apply it with

patch -p1 < wesnoth-0.8.8-balanced_fight_mode.patch

After that, do the usual

./configure
make
make install

For compatibility reasons, the patch is disabled by default.
To activate the patch, edit your game.cfg file, usually in

/usr/local/share/wesnoth/data/game.cfg

and change the line

balanced_fight_mode=0

to

balanced_fight_mode=1

cu

Ignatius
Invisible Philosopher
Posts: 873
Joined: July 4th, 2004, 9:14 pm
Location: My imagination
Contact:

Post by Invisible Philosopher »

So units with two attacks will ALWAYS hit with exactly one of them, no matter what the chance to hit is?
Play a Silver Mage in the Wesvoid campaign.
User avatar
Elvish_Pillager
Posts: 8129
Joined: May 28th, 2004, 10:21 am
Location: Everywhere you think, nowhere you can possibly imagine.
Contact:

Post by Elvish_Pillager »

Invisible Philosopher wrote:So units with two attacks will ALWAYS hit with exactly one of them, no matter what the chance to hit is?
No; if their chance to hit is less than 50%, then only a double-hit is prevented, and if it's more, then only a double-miss is prevented. I don't know about exactly 50%.
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.
User avatar
Jetrel
Posts: 7242
Joined: February 23rd, 2004, 3:36 am
Location: Midwest US

Post by Jetrel »

:| wow. Quite some time ago I really had a problem with the same thing.

It's not really an issue in multi, since your troops can die and you don't care - you haven't spent 29+ hours nurturing them into being decent.

I avoided this massive frustration by just not playing single player - I've played single multiplayer battles almost exclusively for the last few months. The only exception to this was a short stint of HttT, played with unfortunately significant save-loading, and a run of TDH, which I didn't need to save-load on because the undead have a lot of cannon-fodder.

The problem is really caused by the existence of third and fourth-level troops, and the fact that it is not a linear progression of experience points needed to level them, but a quite sharp exponential rise. If all we had was level-2's, people wouldn't be foaming at the mouth when they see one fall - they'd just level another one. But to get a level-3 takes almost three times the experience, and the amount required for a level-4 is just sickening.

Something needs to be done to allow smart players to have a near-guarantee of having what they want to happen, happen, at least on "easy" mode. In easy mode, you should have to do something rather stupid to let you level-3 troops die. If this involves modifying the ai to not target and kill ones which have been unfairly weakened, sure.

Because the point of all this is, it's a fricken game. It's supposed to be FUN. We have gotten post after post after post from people complaining about how hard the game is in campaign mode. Something is wrong, and if we ever want wesnoth to be popular, we should fix it.

As much as we have buried our heads in the sand in the past, the single-player game isn't so much fun for a number of developers either.


I propose that we use this patch, but only for "easy" (and possibly medium) campaign mode - not for multi, and not for hard mode.
We can, and should explicitly explain on the difficulty screen just what the difficulty modes change.
MadMax
Posts: 1792
Joined: June 6th, 2004, 3:29 pm
Location: Weldyn, Wesnoth

Post by MadMax »

I am against this patch, because a Dwarvish Thunderer will always hit.
"ILLEGITIMIS NON CARBORUNDUM"

Father of Flight to Freedom
http://www.wesnoth.org/wiki/FlightToFreedom
Circon
Posts: 1200
Joined: November 17th, 2003, 4:26 am
Location: Right behind Gwiti, coding

Post by Circon »

MadMax wrote:I am against this patch, because a Dwarvish Thunderer will always hit.
Ignatius wrote:Also, the patch has no effect
on weapons such as the pistol attack of Dwarvish Thunderer with
a single attempt.
Read the post.
ignatius
Posts: 35
Joined: December 3rd, 2004, 11:59 am

Post by ignatius »

Elvish Pillager wrote:
Invisible Philosopher wrote:So units with two attacks will ALWAYS hit with exactly one of them, no matter what the chance to hit is?
No; if their chance to hit is less than 50%, then only a double-hit is prevented, and if it's more, then only a double-miss is prevented. I don't know about exactly 50%.
A unit with 2 strikes and against a terrain with a 50% chance to hit will indeed always hit exactly once. This is the case where the effect of the patch maximizes and the only case with a deterministic outcome.

Some numbers for different CtHs:

CtH 0 / 1 / 2 hits
70%: 0 / 60 / 40 instead of 9 / 42 / 49
60%: 0 / 80 / 20 instead of 16 / 48 / 36
50%: 0 / 100 / 0 instead of 25 / 50 / 25
40%: 20 / 80 / 0 instead of 36 /48 / 16
30%: 40 / 60 / 0 instead of 49 / 42 / 9

The whole point of this patch is that the average damage (i.e. its EV) does not change. This is also why there is no effect on units with a single strike b/c there's no way to balance the outcome of a single attempt w/o changing the average damage.

cu

Ignatius
Circon
Posts: 1200
Joined: November 17th, 2003, 4:26 am
Location: Right behind Gwiti, coding

Post by Circon »

My vote: Put this in on Easy level and STATE IT!
User avatar
Gafgarion
Posts: 607
Joined: February 26th, 2004, 10:48 pm

Post by Gafgarion »

Circon wrote:My vote: Put this in on Easy level and STATE IT!
Why not make a new difficulty level below easy? Some people might want an easier game, but not want special rules added to ensure hits and such.
-Gafgarion
Elvish Pillager wrote:Normal Trolls use clubs, not ostriches.
"Language is the source of misunderstandings." -Antoine de Saint-Exupéry
ignatius
Posts: 35
Joined: December 3rd, 2004, 11:59 am

Post by ignatius »

Gafgarion wrote:
Circon wrote:My vote: Put this in on Easy level and STATE IT!
Why not make a new difficulty level below easy? Some people might want an easier game, but not want special rules added to ensure hits and such.
If this patch is to be included into the mainline distrib (which would be great), then IMO, it should not be tied to difficulty levels at all, but become a separate option which is stored along the difficulty level in the save files. That way, players have the maximum choice. You might, however, switch it on by default on easy.

This way, it would also be easy to integrate further rule options. A "useful_traits" and a "leveled_units_survive" option come to mind, the latter allowing the player to get back his "wounded" (i.e. killed) leveled units in campaign mode, after a certain "recovery" time of one or two scenarios (and maybe some non-permanent penalty like double recall cost and/or the unit getting only 1/2 HPs and XP on recall).

The ultimate goal is to make save-loading unnecessary. An optional "only allow saves at the beginning of the turn" rule (maybe in combination with autosave) would also be nice, just to make it easier to resist the temptation ...
freim
Retired Terrain Art Director
Posts: 1113
Joined: November 29th, 2003, 11:40 pm
Location: Norway

Post by freim »

ignatius wrote: If this patch is to be included into the mainline distrib (which would be great), then IMO, it should not be tied to difficulty levels at all, but become a separate option which is stored along the difficulty level in the save files. That way, players have the maximum choice. You might, however, switch it on by default on easy.
I support this. More flexible than messing with the difficulty lvls.

Edit: just so it's clear, I would really like to see this implemented :)
silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Post by silene »

I won't participate in the philosophical discussion on whether and when such a behavior must be applied. This post only deals with coding issues in the patch. It mostly concerns the splice function.

First, you don't want to use ERR_NW, this output is used when synchronization errors occur during a network play, it doesn't have anything to do with cooking attack results.

Second, getting 0 in this function is not even an error in the first place!!! For example it will happen whenever somebody attacks a unit that stands like a sitting duck in the water. This situation is not uncommon.

Third, using integer divisions when floating-point multiplications can be used tends to annoy me, both on the efficiency side and the precision side.

Other than that, the patch looks good.
Woodwizzle
Posts: 719
Joined: December 9th, 2003, 9:31 pm
Contact:

Post by Woodwizzle »

Eeeeeeeh, i dunno about this. Seems kinda like a cheap hack. Luck is a big part of the game and I think it should stay that way. All hail the RNG. Also seems like a bit of a violation of KISS since a different RNG with a lower standard deviation could produce the same general effect of less erratic results.
ignatius
Posts: 35
Joined: December 3rd, 2004, 11:59 am

Post by ignatius »

silene wrote: First, you don't want to use ERR_NW, this output is used when synchronization errors occur during a network play, it doesn't have anything to do with cooking attack results.
Ooops, this is just a bit of debugging code I forgot to remove, as I used replays to test the patch, checking if it would trigger the sync-error (resulting from different fight results) at the right places. The other parts of the patch use LOG_NG.
silene wrote: Second, getting 0 in this function is not even an error in the first place!!! For example it will happen whenever somebody attacks a unit that stands like a sitting duck in the water. This situation is not uncommon.
This is defensive programming. The function is not supposed to be called for probabilities of less than 50% and can return mathematically meaningless values (probs>100%) in that case.

Note that the patch sets the least likely event to zero, so the function is only used to calulate the probability delta for the opposite case in which p is always >=50%.

Also, spice is only a helper function used for "cooking" the fight results and not even declared in actions.hpp, so it's not supposed to be called from other parts of the code.
silene wrote: Third, using integer divisions when floating-point multiplications can be used tends to annoy me, both on the efficiency side and the precision side.
I agree that FP arithmetic would be nicer, however since all probability calculations are done in integer arithmetic, I didn't want to taint the code. I assume that the reason for using integer arithmetic is reproducability in a multi-plattform enviroment, so potentially plattform dependent FP arithmetic in the replay/multiplayer code might be considered harmful.
silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Post by silene »

ignatius wrote:
silene wrote: Second, getting 0 in this function is not even an error in the first place!!! For example it will happen whenever somebody attacks a unit that stands like a sitting duck in the water. This situation is not uncommon.
This is defensive programming. The function is not supposed to be called for probabilities of less than 50% and can return mathematically meaningless values (probs>100%) in that case.

Note that the patch sets the least likely event to zero, so the function is only used to calulate the probability delta for the opposite case in which p is always >=50%.

Also, spice is only a helper function used for "cooking" the fight results and not even declared in actions.hpp, so it's not supposed to be called from other parts of the code.
You clearly didn't understand what I meant, did you even read it? The example I was giving was a real example of a situation that will happen in the game.

Let's suppose there is a Dwarvish Fighter stuck into water, the probability for him to be hit is 80%. So it's a lot more than your 50% hypothesis. Now let's suppose I use an Elvish Archer to slaughter him. The archer has 4 ranged attacks and the probability to hit is 80%. So it will often (51%) hit three times in a row.

Consequently, on the fourth attack, your cooking function will enter into play and will be called with the arguments 80 and 4. Now try again to convince me the result of the function won't be 0.

I suppose you were thinking the function would never return 0 because your algorithm was supposed to preserve EV...
Post Reply