Bug expected_damage() can be very wrong in some cases

Malibu Stacey

Active member
Running this before adventuring

Code:
	boolean[monster] monsters = get_location_monsters(location);
	foreach enemy in monsters {
		auto_log_info(`expected damage({enemy}): {expected_damage(enemy)}`);
	}

Output the following for the Lair of the Ninja Snowmen

Code:
[INFO] - expected damage(Ninja Snowman (Mask)): 46
[INFO] - expected damage(Ninja Snowman (Hilt)): 46
[INFO] - expected damage(Ninja Snowman (Chopsticks)): 62
[INFO] - expected damage(Ninja Snowman Janitor): 58
[INFO] - expected damage(Ninja Snowman Weaponmaster): 65
[B][INFO] - expected damage(ninja snowman assassin): 77[/B]
[INFO] - expected damage(Frozen Solid Snake): 82

Code:
[261] Lair of the Ninja Snowmen
Preference lastEncounter changed from Ninja Snowman Weaponmaster to ninja snowman assassin
Encounter: ninja snowman assassin
Preference _lastCombatStarted changed from 20200712064509 to 20200712064609
Round 0: Player Two loses initiative!
Round 1: You lose 7 hit points
[B]Round 1: You lose 122 hit points[/B]
This combat did not cost a turn
Preference _edDefeats changed from 0 to 1
Preference lastEncounter changed from ninja snowman assassin to Like a Bat Into Hell
Encounter: Like a Bat Into Hell

Output the following for the Defiled Alcove

Code:
[INFO] - expected damage(grave rober zmobie): 30
[INFO] - expected damage(corpulent zobmie): 28
[INFO] - expected damage(conjoined zmombie): 37
[B][INFO] - expected damage(modern zmobie): 31[/B]


Code:
[275] The Defiled Alcove
Preference lastEncounter changed from Turn Your Head and Coffin to modern zmobie
Encounter: modern zmobie
Preference _lastCombatStarted changed from 20200712071345 to 20200712071848
Round 0: Player Two loses initiative!
Round 1: You lose 1 hit point
[B]Round 1: You lose 40 hit points[/B]
This combat did not cost a turn
Preference _edDefeats changed from 0 to 1
Preference lastEncounter changed from modern zmobie to Like a Bat Into Hell
Encounter: Like a Bat Into Hell

I've noticed it with these 2 as they have very high Initiative so getting the jump is unlikely hence knowing whether they will instagib or not is useful. There may be other monsters with similar issues but I haven't ran into those as yet.

Thanks.
 

fronobulax

Developer
Staff member
Since expected damage is an estimate based upon probabilities and distributions, the differences could easily be explained by random number generator hatred. I spot checked the code and the code seems to match the wiki in terms of formulas.

I suppose there could be data errors associated with those specific monsters or there could be "something" that is exerting an effect that mafia does not know about and this does not include in the calculation, but I'm not really sure where I would start looking. That said the assassin's numbers look "interesting".
 

zarqon

Well-known member
There are lots of monsters that have custom damage formulae, which I'm fairly sure mafia wouldn't be accounting for in this function. A quick search of batfactors for the "dmgformula" keyword reveals:

Code:
monster	-85	The Unkillable Skeleton (Hard Mode)	2.5 prismatic	0	noitems, noskills, dmgformula maxhp*0.09
monster	210	Your Shadow	0	0	nostun, autohit, noskills, dmgformula 95+maxhp/6
monster	917	The Landscaper	5 prismatic	0	autohit, dmgformula maxhp*0.49
monster	953	Vanya's Creature	0	0	dmgformula maxhp*0.125
monster	1185	ninja snowman assassin	0	0	autohit, dmgformula max(0,monsterattack-buffedmox)+110 cold
monster	1210	blazing bat	5 none,hot,spooky,stench,sleaze	0	autohit, dodge 1.0, dmgformula max(0,monsterattack-buffedmox)+500 hot
monster	1379	Dad Sea Monkee	0	0	nostagger, noitems, nostun, damagecap 301, maxround 12, dmgformula maxhp*0.11, variable
monster	1706	wall of meat	0	0	autohit, dmgformula maxhp*0.15
monster	1899	drunk cowpoke	0	0	dmgformula maxhp*0.1*lttdifficulty
monster	1903	hired gun	0	0	dmgformula maxhp*0.15*lttdifficulty
monster	2110	Sylvia Belgrande	0	0	autohit, dmgformula maxhp*0.3
monster	2115	Your Lack of Reflection	0	0	nostagger, nostun, autohit, dmgformula maxhp*0.1
monster	2136	skeleton astronaut	1 spooky	0	damagecap 10, capexp 0, autohit, dmgformula maxhp*0.125
monster	2138	Invader	0	0	nostagger, nostun, damagecap 100*daycount, capexp 0, dmgformula 5*max(150,maxhp*(1.1-0.1*daycount)) prismatic
monster	2162	drippy tree	5 prismatic	0	onlyhurtby drippy, nostagger, nostun, autohit, dmgformula maxhp*0.3
monster	2163	drippy bat	5 prismatic	0	onlyhurtby drippy, nostagger, nostun, autohit, dmgformula maxhp*0.3
monster	2176	drippy reveler	5 prismatic	0	onlyhurtby drippy, nostagger, nostun, autohit, dmgformula maxhp*0.3

Also included in there is every single Batfellow monster. Then, BatBrain also has these monsters' damage formulae hardcoded:

PHP:
      case $monster[Mammon the Elephant]: return to_spread(2**(round - 1));
      case $monster[wall of bones]: return to_spread(my_maxhp()*(0.1 + 0.2*(round - 1)));
      case $monster[pufferfish]: return to_spread(2 + 2**round);
      case $monster[Great Wolf of the Air (Hard Mode)]: if (round % 2 == 1) return to_spread(my_maxhp() + 50 - max(0,numeric_modifier("Damage Reduction") - mdata.drpen)); break;

All told, that's about 50 monsters with unique damage formulae. Should mafia support all of those for its estimated_damage() function? Sorry Malibu, but I think that's a very high work:functionality ratio.

...especially given that a script for that already exists! You could take advantage of the work I've already put in to BatBrain for the same result but including all the various custom damage formulae:

import <BatBrain.ash>
set_monster(whatever monster);
m_regular()
--> returns a spread containing the monster's expected damage
 

fronobulax

Developer
Staff member
I was iterating through $monsters and right after Burly Sidekick I got
Expression syntax errors for 'modifier_eval()':
Can't understand batheatresistance)/100
Expected ), found (zlib.ash, line 195)
at eval (zlib.ash:195)
at to_spread (BatBrain.ash:251)
at to_spread (BatBrain.ash:257)
at m_regular (BatBrain.ash:759)
at wrapup (BatBrain.ash:1744)
at set_monster (BatBrain.ash:2120)

I presume the solution is to edit batbrain but if it isn't I'm open to ideas>

Also is there a to_string(spread)? Since I'm just interested in comparing numbers with expected_damage() to_html() just introduces clutter I will parse out. I could write my own but...

Thanks.
 

zarqon

Well-known member
There's dmg_taken(spread), which sums the actual damage you will take from a given spread given your current resistances.

dmg_taken(m_regular()) would probably be what you want.

As for the error, BatBrain attempts to save precious ms by only loading the fvars you'll need. Unless you're Batfellow you won't face any Batfellow monsters, so I'm tempted to just say "don't do that" for all the Batfellow monsters. There may be another way but I'd need to consider what it would be.

You could foreach locations instead, and only calculate damage for get_monsters in CanAdvable locations?
 

fronobulax

Developer
Staff member
The above was not a satisfactory answer. I should be able to iterate over all monsters.

The attached script does so. I just set a fvar for each of the "constants" that weren't defined in my (not even logged in) environment and the mechanics worked. I printed the monster name, BatBrain's damage_taken and KoLmafia's expected damage using an asterisk as a delimiter. That is so much easier for me than worrying about what characters might be in a monster name :)

View attachment BatDamage.ash

Doing some filtering on cases where data might be lacking or special handling might be needed I see the following monsters where BatBrain's estimate is significantly larger:

blazing bat
flock of every birds
ninja snowman assassin
Pharaoh Amoon-Ra Cowtep
quadfaerie
Tasmanian Dervish

There are monsters where mafia's estimate is higher, and the difference is at least 10 and greater than 15%.

the invader
Your Shadow
pufferfish
drippy tree
drippy bat
drippy reveler.

I don't need another project so I'm just putting this out there for someone with more curiosity than I have.

But since the ninja snowman assassin started the discussion, I too would wonder if mafia's data is correct. Several of the others could be due to me running my script when not logged in :)
 
Top