BatBrain -- a central nervous system for consult scripts

I have problems making BatBrain work for when BatBrain thinks a monster should be dead, but it still has HP due to ML variance. I'd like to be able to tell it to assume maximum variance for a monster, or to tell it to increase current monster HP by X.

Also, it would be helpful if I could access damage information without it being capped by current monster HP. This limit keeps me from easily being able to work around that on my own.

Are there ways to do this, or would this require a new BatBrain feature?
 
I have to ask, how do you add new items to batfactors.txt? There's no listing for the Rain-doh indigo cup or the the blue balls so I tried adding my own but it doesn't seem to use them. I'm not sure it I have them coded right for it:
Code:
item	5560	Rain-doh blue balls	{10,15,20}	cold	once, stun 2
item	5561	Rain-doh indigo cup	0	physical	once, hp .2*maxhp
And I'm not entirely sure which function would use them, act() or try_custom()
 
Last edited:
Act() never uses anything, it just parses your option and makes them available for the other batbrain-functions. That said the only place in SmartStasis that does stuns is try_custom() so it would be used in conjunction with any items or similar that SS thinks it needs to stun first in order to use safely.
The only other stunning being done is at the end of SS where it tests if entangling noodles is profitable or not, that would need to be edited in order to work with blue balls.

The cup I think would only be used as a stasis-item and I have no idea how that calculation works.

However, the coding looks ok to me at least :)
 
Needs spading:
March 01 - Mosquitoes, like your mom, now bite a little harder and a little more often.
So, batfactors will need an update on that whenever we actually know what that means. :)
 
News flash for BatBrain scripters! I have probably broken your script!

I have been increasingly dissatisfied with a few aspects of BatBrain's information. First, HP is a single integer, but player resistances should apply to all incoming elemental damage, not just from the monster. Second, the method of entering spreads into batfactors is too limiting. If something does an unequal amount of physical and hot damage, there has been no way of specifying this in batfactors.

Fixing these has been on my list for a long time, but I finally buckled down and did it. I have entirely reworked a) the way spreads are loaded from batfactors, and 2) the way BatBrain handles HP.

A. All-new Spread Notation

Spreads are now written in batfactors in a single string (rather than the previous two fields) like so:

expression[ types]|expression[ types]|expression[ types] [...]

Any number of expressions and associated types may be entered, separated by pipe characters. The final result will be summed.

  • expression: the formula to evaluate. This was previously the entire dmg field.
  • types: the type(s) of damage dealt, separated by commas with no spaces (e.g. "hot,cold"). This was previously the dmgtypes field. The result of expression will be equally divided among the types entered. If a type is entered multiple times, that type will get multiple shares of the damage. If types is omitted, the damage is assumed to be entirely physical.


Also, another change from before: the names now correspond exactly with mafia's elements, so use "none" instead of "physical".

I believe this is a highly flexible system which should allow us to have much more accurate information in batfactors for all current and future damage-dealers.

2. HP Reworked

This has been a significant overhaul of BatBrain with very minor actual functional change, but I believe the greater accuracy will be worth it in the long run.

In short, HP is now loaded as a spread rather than a float and treated as player damage ("pdmg" for short) rather than HP. This has the following repercussions:

  • In place of the previous dmgtypes field, batfactors now has a pdmg field for player damage, which is a spread (same format as just described above).
  • Since it now has its own field, HP information is no longer contained in the "special" field in batfactors.
  • Important: pdmg is negative for healing, positive for damage to the player -- the opposite of the previous "hp" keyword.
  • advevents no longer have an "hp" field.
  • advevents now contain a "pdmg" field, which is a spread.
  • A new function, dmg_taken(), reduces a given pdmg spread by the appropriate player resistances.


III. What This Means For You

Several important functions have changed. The declarations for to_event() and to_spread() are different, for one. Any reference to the hp field of an advevent will no longer work. Since I feel that this update will likely break most of the scripts currently using BatBrain, I've decided to post this update here first, along with the reformatted batfactors. I'll leave it here for a week before updating in the first post, to give scripters using BatBrain time to prepare for when I officially update the script.

Also, during the overhaul I may have missed something -- a plus which should be a minus or somesuch -- so if you find anything like this I would appreciate your mentioning it here so those transitional bugs may all be squashed before the update goes "public". Enjoy the improved accuracy!

ETA: It has now been a week. BB removed from this post and updated in the first post.
 
Last edited:
Having disabled all MP/HP-restoring parts of WHAM (they weren't working anyway so...) I get a script that seems to be working but generates a lot of:
Code:
Evaluator syntax error: unexpected end of expr

WIth verbosity at 9:
Code:
Encounter: The Naughty Sorceress (2)
Round 0: Winterbay loses initiative!
You lose 68 hit points
Running ZLib version: r34 (current)
Running Character Info Toolbox version: 0.6.2.2
Running ZLib version: r34 (current)
1 HP costs 5.333μ. ( 184 / 371 )
1 MP costs 8μ. ( 95 / 115 )
Running BatBrain version: 1.16 (current)
Running SmartStasis version: 3.11 (current)
Running WHAM version: 1.5 (current)
We currently think that the round number is: 0
Value of stat gain: 544.53μ
Value of stat gain: 544.53μ
ATT: 205 (94% × -77.78, death in 3)
DEF: 185 (95.45% × 84.8, win in 6050000)
HP: 600, Value: 544.53 μ
Parsed round number: 1
Building options...
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Options built! (36 actions)
We currently think that the round number is: 1
WHAM: You are fighting a The Naughty Sorceress (2). Mafia considers that this monster has an attack of 205 or 205 when given a monster name.
WHAM: Mafia further considers that this monster has a defense value of 185 or 185 when given a monster name.
WHAM: Mafia further further considers that this monster has a HP value of 600 or 600 when given a monster name.
WHAM: Your current ML-adjustment is: 0.
WHAM: Setting up variables via BatBrain
WHAM: Monster HP is 600.0.
WHAM: Running SmartStasis
SmartStasis starting.
Profit per round: ActionProfitDamageOtherbase (0μ)0μ--
Building custom actions...
Custom actions built! (0 actions)
This monster is not your huckleberry.
Queued: skill 11003
Building options...
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Options built! (35 actions)
Executing macro: scrollwhendone; sub batround; if haseffect 8 || haseffect 264 || haseffect 282 || haseffect 283 || haseffect 284; abort "BatBrain abort: poisoned"; endif; endsub; skill 11003; call batround; 
Round 1: Winterbay executes a macro!
Round 1: Winterbay casts BROADSIDE!
Happened: skill 11003
Parsed round number: 2
Building options...
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Options built! (35 actions)
WHAM: We estimate that the monster is stunned for 2.0 more turns and correct this with -1 for the turn the stun started on.
SmartStasis complete.
WHAM: Running SmartStasis took 2.218 seconds.
We currently think that the round number is: 2
WHAM: Starting evaluation and performing of attack
We currently think that the round number is: 2
WHAM: You will kill the monster in 8 rounds with your basic attack.
WHAM: The monster will take 4.0 rounds to kill you.
rounds_to_kill: 8, round_limit: 10, maxround: 50, die_rounds(): 5, stuncorrect: -1.0, hitchance("attack"): 0.95454544
WHAM: Intimidating your foes was a very Borisy thing to do.
Queued: skill 11011
Building options...
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Options built! (34 actions)
Executing macro: scrollwhendone; sub batround; if haseffect 8 || haseffect 264 || haseffect 282 || haseffect 283 || haseffect 284; abort "BatBrain abort: poisoned"; endif; endsub; skill 11011; call batround; 
Round 2: Winterbay executes a macro!
Round 2: Winterbay casts INTIMIDATING BELLOW!
Happened: skill 11011
Parsed round number: 3
Building options...
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Evaluator syntax error: unexpected end of expr
Options built! (34 actions)
WHAM: Evaluating the attack but not performing it took 0.016 seconds.
WHAM: These are the numbers of the kill counts.
Oneshot: 0, Twoshot: 0, Threeshot: 0, Fourshot: 0, Fiveshot: 0
Round 3: Winterbay executes a macro!
KoLmafia thinks it is round 4 but KoL thinks it is round 3
WHAM: Unable to determine a valid combat strategy. For your benefit here are the numbers for you combat skills.
WHAM: Heroic Belch 60.0 potential damage.
WHAM: Cleave 95.412 potential damage.
WHAM: Mighty Axing 42.401997 potential damage.
WHAM: Basic attack 80.949265 potential damage with a hitchance of 95.454544%.
WHAM: You now have the knowledge needed to go forward and be victorious
You're on your own, partner.

Any idea what's that about?
 
Fairly certain that's due to empty strings being passed to modifier_eval(), but I'm not sure yet where they're coming from. Exceedingly ugly but functionally harmless.
 
Just downloaded batbrain, smartstasis, and batfactors from 587... Getting an error on the second line here, due to the first... Lines 216 and 217:
Code:
      case "stats": string[int] sts = split_string(bittles.group(2),"\\|"); break;
         foreach n,st in sts res.stats[to_class((n+1)*2).primestat] = eval(st,fvars); break;
Note that the first one always breaks, which makes the second one never trigger. Anyways, this is the visible error:
WARNING: Unreachable code (BatBrain.ash, line 217)

Also odd...
Run SmartStasis! (239 profit to stasis with Intimidating Bellow -- good enough)
One cast, good. 5 more rounds of seal tooth and taking ~30 damage per round, not so good.
 
Last edited:
Cool! I like the update that made this break. That was a break which I put in when I had the second line temporarily commented out. It shouldn't be there anymore.

Updated post 587 with the fix.

As to your second issue... the line you reported is not from any of my scripts but it looks okay... where's the line that lists the estimated profit from using the seal tooth?

This might be a SS issue regarding stuns. When the monster is stunned, stasis actions may seem profitable and be submitted with no repeat conditions for when the monster is no longer stunned. I'll check out that theory.

EDIT: Also fixed all the evaluator syntax errors -- rather than figure out where all the empty strings are coming from, BB just checks that the string is not empty before eval()'ing it. :)
 
Last edited:
DAM displays what the estimated profit is from SS before it lets it run. It runs this:
Code:
	advevent stasis = stasis_action();
	int profit = to_profit(stasis);
	vprint("Run SmartStasis! ("+profit+" profit to stasis with "+translate_id(stasis.id)+" -- "+(profit >= to_float(vars["BatMan_profitforstasis"])? "good enough)": "low)"), "blue", 3);
	SmartStasis();
So it checks it, but then it just runs the SmartStasis...

Anyways, here's a log of combat on a taco cat, up until the point where DAM takes over to kill it:
Encounter: Taco Cat
Strategy: C:\Program Files (x86)\KoLMafia\ccs\default.ccs [default]
Round 0: Theraze wins initiative!
ATT: 139 (94% × -49.78, death in 6)
DEF: 132 (95.45% × 57.67, win in 1500000)
HP: 145, Value: 460.97 μ
Run SmartStasis! (146 profit to stasis with Intimidating Bellow -- good enough)
Profit per round: Action Profit Damage Other base (0μ) 0μ --
Round 1: Theraze executes a macro!
Round 1: Theraze casts INTIMIDATING BELLOW!
Round 2: taco cat drops 20 attack power.
Round 2: taco cat drops 20 defense.
You lose 32 hit points
Round 2: Theraze executes a macro!
Round 2: Theraze uses the seal tooth!
Round 3: taco cat takes 1 damage.
You lose 31 hit points
Round 3: Theraze executes a macro!
Round 3: Theraze uses the seal tooth!
Round 4: taco cat takes 1 damage.
You lose 31 hit points
Round 4: Theraze executes a macro!
Round 4: Theraze uses the seal tooth!
Round 5: taco cat takes 1 damage.
Round 5: Theraze uses the seal tooth!
Round 6: taco cat takes 1 damage.
You lose 31 hit points
Round 6: Theraze executes a macro!
Round 6: Theraze uses the seal tooth!
Round 7: taco cat takes 1 damage.
You lose 29 hit points
Round 7: Theraze executes a macro!
Round 7: Theraze uses the seal tooth!
Round 8: taco cat takes 1 damage.
You lose 30 hit points
DestroyAllMonsters starts now! (0mp option Mighty Axing -- killrounds: 2, dierounds: 3)
 
Last edited:
That seems to verify Zarqon's theory, and also fits nicely with what I experienced yesterday when poking at things.
 
Well, the monster wasn't stunned though, just delevelled... and it's done it both with straight seal tooth as well as (more commonly) with bellows. The bigger question is, why would Clancy and Boris be considered good for stasising? Actively delevelling, sure. If I can't one-hit the mob and avoid losing health that way. But using the seal tooth as a 'useful' thing? Nah...
 
Found it -- it was, as I'd mentioned might be likely, a negative which should have been a positive. I had a hard time initially deciding whether the field would be HP (positive for healing, negative for damage) or pdmg (positive for damage, negative for healing). In the end I went with the latter since it was an easy parallel with the dmg field, but I forgot to reverse one important negative back to a positive: monster damage in m_regular(). Thus, the more damage the monster did to you, the more profit the new BB thought you were making! Haha, oops. Anyway, that's fixed and I haven't seen any more stasising with seal teeth in Boraxecore.
 
Yay! Laptop got unplugged, so I haven't gotten to run adventures today, but I'll try it again in another hour or two. Looking forwards to it, and thanks for the speedy fixings! :)
 
Is there any way of getting Batbrain to recognize that a monster can have a disparate amount of HP? The Mountain Man (who is not really added to Mafia yet) has a HP of around 300 and a ML of around 100. This leads to problems when using unknown_ml as it sets the HP to 100 and will subsequently fail in finding a good way to kill it.

Also, since reset_queue() is called when you execute a macro (fair enough, we don't need the queue any more) multistuns and other things tracked by batbrain but not by Mafia gets wiped. Is there a specific reason for this?
 
To answer your first question: Yes; add the monster to mafia. The unknown_ml thing should only be necessary for new monsters for a short time before they are spaded and their stats added to mafia, ideally. And since I'm an idealist, I want to believe this ideal is possible. I'm not interested in coding solutions for people to temporarily work around mafia's temporary ignorance.

As to your second, the reason is that I wanted to implement reset_queue() ASAP, despite having no solution for stun tracking yet. :) That's on my list. However, other things tracked by BatBrain are not wiped, to my knowledge -- that's all in happenings. What "other things" are you talking about?
 
Well, for monsters that are not in Mafia's database yet (such as the aforementioned Mountain Man and the swarms of whelps in the cyrpt and any other monster with at least one stat at 0) any damage done to the monster in one call to macro() gets wiped as reset_queue() resets the HP and other stats for the monster back to the ones based on unknown_ml. This means that in a script like WHAM or DAM where smartstasis is incorporated into the call any damage and delevelling done by SS is lost after the macro generated by SS is submitted and control is handled back to the initiating script.

While we're on the subject of happenings: Any chance that the round the action was performed could be recorded as well? Not that I can come up with a good idea as to why, but I know I had one earlier today...

Also. I just looked at my happenings_winterbay.txt-file and it looks slightly odd. Or am I just imagining things?
Code:
attack	319	0	1
skill 11000	394	0	1
skill 11003	1466	0	1
skill 11011	380	0	1
use 2	1298	0	2
use 2563	277	0	2
use 820	364	0	1
use 821	364	0	1
use 824	364	0	1
use 825	364	0	1

It feels a bit odd that the turn-field is so varying...
 
I think you are possibly misunderstanding the purpose of "adj". It does not track actual stats; it tracks the current adjustment to those stats -- the difference between mafia's current knowledge of those stats and the estimated stats at the end of the actions in the queue. When a macro is submitted, there is no longer any difference between the end of the empty queue and the current situation, so they are wiped.

Or are you saying that mafia doesn't track deleveling and damage done to monsters of unknown stats?

Your happenings file looks fine. The turn number simply shows the most recent turn where you performed that specific action. So it looks like SS decided to ID a handful of bang potions for you on turn 364, and attack hasn't been useful for you since turn 319, as your combat script seems to be preferring Boris skills. This could possibly be interesting or useful information. I like to look at my happenings file from time to time, anyway.
 
Back
Top