BatBrain -- a central nervous system for consult scripts

@Theraze: Just change the "fumble" to a "" and you'll be accounting for fumbles again. I'll try to get an update done in the next hour before work starts, but I'm also in the middle of trying to fix some Ubuntu issues that sometimes make the computer unusable. We'll see.

I tried the "" and it went back to 480 thousand rounds, so... I'll leave it commented out for now. :)
 
I tried the "" and it went back to 480 thousand rounds, so... I'll leave it commented out for now. :)

Replace fumble() with this:

PHP:
advevent fumble() {
   if (string_modifier("Outfit") == "Clockwork Apparatus")
      return to_event("",to_spread(15*0.25,"physical"),"stun 0.25, hp 12.5*0.25, mp 12.5*0.25, att -1, def -1");
   int wpnpwr = get_power(equipped_item($slot[weapon]));
   if (have_skill($skill[double-fisted skull smashing]) && item_type(equipped_item($slot[offhand])) != "shield")
      wpnpwr += get_power(equipped_item($slot[offhand]));
   return to_event("",to_spread(0,"physical"),"hp -"+max(1.0,to_float(wpnpwr)*0.05));
}

I changed "fumble" to "" twice in that function and it fixed the problem.
 
Last edited:
Hrm. It seems that BatBrain does not understand the damaging power of pufferfish! Is this a known bug?

Code:
Visit to The Sea: Madness Reef in progress...

[288534] Madness Reef
Encounter: pufferfish
Strategy: C:\My Dropbox\KolMafia\ccs\default.ccs [default]
Round 0: character wins initiative!
1 MP costs 3.7037036μ.
1 HP costs 0.025478048μ.
pufferfish spine (5.0 @ +148.87482): 7000μ * 12.44374% = 871.06177
rough fish scale (4.0 @ +148.87482): 2500μ * 9.954992% = 248.8748
seaweed (5.0 @ +148.87482): 4100μ * 12.44374% = 510.19333
Value of stat gain: 1397.5μ
Factoring in plastic pumpkin bucket: 9.19 damage,
pufferfish spine (5.0 @ +148.87482): 7000μ * 12.44374% = 871.06177
rough fish scale (4.0 @ +148.87482): 2500μ * 9.954992% = 248.8748
seaweed (5.0 @ +148.87482): 4100μ * 12.44374% = 510.19333
Value of stat gain: 1397.5μ
Monster: Pufferfish, ATT: 410, DEF: 459, HP: 760, Value: 3277.63
Profit per round: ActionProfitDamageOtherbase; plastic pumpkin bucket; Grouper Groupie (0μ)0μ9.19 (0 μ/dmg)
Building options...
Options built! (78 actions)
You will die in 1335 rounds.
Your attack will kill the monster in 1 rounds.
Building custom actions...
Custom actions built! (0 actions)
pufferfish spine (5.0 @ +148.87482): 7000μ * 12.44374% = 871.06177
pufferfish spine (6.0 @ +148.87482): 7000μ * 14.932489% = 1045.2742
rough fish scale (4.0 @ +148.87482): 2500μ * 9.954992% = 248.8748
rough fish scale (4.8 @ +148.87482): 2500μ * 11.9459915% = 298.64978
seaweed (5.0 @ +148.87482): 4100μ * 12.44374% = 510.19333
seaweed (6.0 @ +148.87482): 4100μ * 14.932489% = 612.23206
pufferfish spine (5.0 @ +148.87482): 7000μ * 12.44374% = 871.06177
pufferfish spine (6.5 @ +148.87482): 7000μ * 16.176863% = 1132.3804
rough fish scale (4.0 @ +148.87482): 2500μ * 9.954992% = 248.8748
rough fish scale (5.2 @ +148.87482): 2500μ * 12.94149% = 323.53723
seaweed (5.0 @ +148.87482): 4100μ * 12.44374% = 510.19333
seaweed (6.5 @ +148.87482): 4100μ * 16.176863% = 663.2514
Executing macro: scrollwhendone; sub batround; if haseffect 8 || haseffect 264 || haseffect 282 || haseffect 283 || haseffect 284; abort "BatBrain abort: poisoned"; endif; endsub; skill 52; skill 51; skill 50; call batround; skill 5003; skill 5005; skill 5008; call batround; if hpbelow 28; abort "BatBrain abort: Danger, Will Robinson"; endif; skill 51; skill 50; skill 52; call batround; skill 5005; skill 5008; call batround; if hpbelow 27; abort "BatBrain abort: Danger, Will Robinson"; endif; 
Round 1: character executes a macro!
Round 1: character casts RUN LIKE THE WIND!
Round 2: pufferfish takes 7 damage.
You lose 4 hit points
You lose 8 hit points
Round 2: character casts POP AND LOCK IT!
Round 3: pufferfish takes 15 damage.
Round 3: Cuddles rolls the plastic pumpkin bucket at it. It promptly trips over it and falls, taking 33 damage.
Round 3: pufferfish takes 33 damage.
You lose 16 hit points
Round 3: character casts BREAK IT ON DOWN!
You acquire an effect: Rave Concentration (duration: 1 Adventure)
You lose 32 hit points
Round 4: character casts DISCO EYE-POKE!
Round 5: pufferfish takes 3 damage.
Round 5: pufferfish drops 3 attack power.
Round 5: pufferfish drops 3 defense.
You lose 64 hit points
You lose 56 hit points
Round 5: character casts DISCO DANCE OF DOOM!
Round 6: pufferfish takes 8 damage.
Round 6: pufferfish drops 5 attack power.
Round 6: pufferfish drops 5 defense.
You lose 128 hit points
Round 6: character casts DISCO DANCE II: ELECTRIC BOOGALOO!
Round 7: pufferfish takes 8 damage.
You acquire an effect: Disco Concentration (duration: 1 Adventure)
Round 7: pufferfish drops 7 attack power.
Round 7: pufferfish drops 7 defense.
Round 7: Cuddles rolls the plastic pumpkin bucket at it. It gets its foot caught in it and falls over, sustaining 26 damage.
Round 7: pufferfish takes 26 damage.
You lose 256 hit points
Round 7: character casts POP AND LOCK IT!
Round 8: pufferfish takes 9 damage.
Round 8: Cuddles rolls the plastic pumpkin bucket at it. It gets its foot caught in it and falls over, sustaining 31 damage.
Round 8: pufferfish takes 31 damage.
You lose 512 hit points
Round 8: character casts BREAK IT ON DOWN!
Round 9: pufferfish takes 10 damage.
You lose 1,024 hit points
Round 9: character casts RUN LIKE THE WIND!
Round 10: pufferfish takes 16 damage.
You acquire an effect: Rave Nirvana (duration: 1 Adventure)
You lose 2,048 hit points
Building options...
Options built! (78 actions)
SmartStasis complete.

Requests complete.
 
Most odd.
"Round 0: drkirre loses initiative!
Cannot apply operator contains to aggregate boolean [class] (boolean [class]) and s[] (string) (BatBrain.ash, line 784)
Consult script 'smartstasis.ash' not found.
You're on your own, partner.
Click here to continue in the relay browser."
I have smartstasis.ash and batbrain both in the scripts folder.. this is quite a conundrum.
 
@Bale: Yes, presently there is no support for anything ongoing unless it's a status effect. It's one of the tricky puzzles to solve on the todo list.
 
The last line in hitchance() does not work.

Code:
return min(critchance() + (1.0 - critchance())*(6.0 + attack - max(monster_stat("def"),0.0))/11.0,1.0)*through;

That goes negative every time your attack much is 7 lower than the monster's defense. Obviously you can never have a hitchance less than 0. Ooops. It should be:

Code:
return min(critchance() + (1.0 - critchance())*max(6.0 + attack - max(monster_stat("def"),0.0), 0.0)/11.0,1.0)*through;

I needed to fix this to make killrounds() be correct all the time, not just when I was fighting weak monsters. VERY important bugfix.
 
Last edited:
Is there any good way to mark the NSN as having 100 resistance to damage, since they generally heal 100 every round? If consult scripts were aware of this, it would help them not try to use low-damage skills to finish them off...
 
This is already done. It's included in res which is reflected in kill_rounds(). Simply check if kill_rounds(get_action()) is greater than 15 and you'll know that you've got a problem without the consult script needing to pay attention to the nurse.

PHP:
if((kill_rounds(get_action("attack")) >= die_rounds() || kill_rounds(get_action("attack")) > 15) && enqueueDanger(foe) == "fail")
	return macro("abort \"Unable to figure out combat strategy\"", "");

That code checks if attacking will kill the monster before it kills me. If so, then it checks if attacking will kill the monster in less than 15 rounds because I worry that something is bad after that many turns. If I cannot kill it in less than 15 rounds or before it kills me then I move on to finding an alternative means of execution.

This works for the Naughty Sorority Nurse also. You can bump the turn limit for killing up to 25 if you are less paranoid than I.
 
Last edited:
What I already had was this:
Code:
  int rounds_to_kill = kill_rounds(get_action("attack"));
  if(rounds_to_kill < 10 && die_rounds() > rounds_to_kill + 1 && hitchance(get_action("attack")) > 0.5)
It only tries to use attack if it decides that it can kill them in under 10 rounds of attacking, it has at least 2 rounds of safety, and over a 50% chance to hit. Not sure what your enqueueDanger function is, but it's not in my BatBrain...
 
enqueueDanger() is a function in my consult script.

Your method should ensure that you don't waste time attacking a Naughty Sorority Nurse. It looks like you already solved your problem. Was it attacking the nurse anyway?

I would suggest ignoring hitchance(). It is quite possible at low level for a critical or your familiar to kill a monster before it has any chance of killing you. Don't straightjacket your script by ensuring that you have a good chance to hit the monster. I've been amazed how often my consult script kills monsters by attacking when I would expect that to be crazy.

The awesome thing about BatBrain is that it is considering many possibilities that you are not considering. Don't limit it by caring about a small factor like hitchance(get_action("attack")) which is already included in rounds_to_kill.
 
Last edited:
Yep, burned through all 30 turns trying to outdamage it and failed.

I actually added the hitchance after it decided that if it ever succeeded in hitting a bee, it would easily kill it... Well, not after it decided... the first time... or the second... it was after it decided for the 5th time or so today. This is in my spamattack that should already consider all of my skills for what's cheapest for the kill. While using attack is cheapest if it works, it just needs to be guaranteed. 20 rounds of "hope it works" isn't reliable enough for me to be happy with it. Once a bee gets down to <10 health or so, it thinks that the critical chance of hitting is going to be good enough for 'guaranteed' success.
 
This is slightly related to a problem I recently encountered. I'm doing a 100% Hipster run, and due to the Hipster's infrequent but huge attack, at low-to-mid levels it thought all of my actions (including Suckerpunch) would kill the monster in one round.

Let's suppose my Hipster deals 300 damage at a 5% rate. That means that BatBrain presently would assume that any monster with 15 or less HP will die in a single round, even if my action does no damage. That is Bad Predicting.

The solution -- which will probably also solve Theraze's above issue -- is to cap damage at the monster's remaining HP, since if the monster has 5 HP, any amount equal to or greater than that has the same result: death.

Will have to be careful how I do this, since doing extra-big damage to mine crabs and hobos does not have the same result, and I need to leave space for splashback support, but I think this will help BatBrain's predictions considerably. I'll add this and the *sigh* hopefully last remaining fix to the hitchance formula and post an update soon.
 
Let's suppose my Hipster deals 300 damage at a 5% rate. That means that BatBrain presently would assume that any monster with 15 or less HP will die in a single round, even if my action does no damage. That is Bad Predicting.

BTW: does BatBrain consider that hipster will never attack in the first round? (it has that +stats thing going on as its first action)


ETA: another thing to consider is that you should not just cap the average damage. Consider:
action A does 10-40 damage (uncapped average = 25).
Monster has
a) 30 hp left - above average so you don't cap and say that it takes 30/25=1.2 rounds to kill
b) 20 hp left - you cap the average to 20 and say that it takes 20/20=1 rounds to kill
If you instead simply cap the spread, you get wrong results:
a) to 10-30, average 20, 30/20=1.5 rounds to kill
b) to 10-20, average 15, 20/15=1.3333 rounds to kill

Slightly closer to exact:
a) 10-40 spread with ceil of 30: (31 possible different rolls, presumable with the same probability of happening) 21/31 of the time (rolls 10-30), damage is equal to roll; remaining 10/31 of the time (rolls 31-40), damage is equal to cap;
average = 21/31*(average of rolls from 10-30) + 10/31*(30) = (20*21+10*30)/31 = 720/31 =~ 23.2258, making it 1.2917 rounds to kill
b) 10-40 spread with ceil of 20 ... average = 11/31*(average of rolls from 10-20) + 20/31*20 = (15*11 + 20*20)/31 = 455/31 =~ 14.6774 and 1.3626 rounds to kill

The above is still wrong, of course, because it doesn't adjust the ceil after the first round if that round doesn't kill the monster. That doesn't matter much for things that fire 100% of the time, but the interaction might be interesting.
But then we are getting into event trees that have "opponent has at least X hp and at most Y hp" and split events when the value of (X > 0) or the value of (Y > 0) changes (opponent *might* be dead, opponent *definitely is* dead).
 
Last edited:
Slight error in the datafile for Harpoon! the white space between physical and regular is a space rather than a tab... I've uploaded a fixed version.
 
Is there some problem with Stealth Mistletoe?

I failed to enqueue it, so I checked and found that it is not in batfactors. I added it to my local copy, but it still would not enqueue. Does it have some special handling that I cannot find which is keeping me from enqueueing it? Is there a reason it is not in batfactors?
 
@xKiv: It's even trickier than that. Damage needs to be capped before hitchance, but not all damages should be capped, due to splashback or hobo overkills. The script needs to have access to the uncapped number for these issues, so capping the formulas in the data file is not an option. Capping them in to_event would also have unwanted repercussions in non-action events. Additionally, the cap needs to be aware of monster resistances and vulnerabilities.

In short, adding an upper cap to predictions is an unexpectedly major issue, and I may opt not to fix this before releasing a fix for the hitchance issue.

@Bale: It's not in batfactors because it's not a normal action -- you can only cast it once and it doesn't have a mechanic expressible in a single formula. However, now that BatBrain tracks mistletoe, I can add the handling I'd intended for it -- during enqueueing, if a DB skill is enqueued and you have not mistletoed yet this combat and the action queued != stasis_action(), pop Mistletoe in first.

@Winterbay: thanks!
 
Back
Top