BatBrain -- a central nervous system for consult scripts

Aha, thanks for the heads up. A couple days ago I tried to add all the familiars I could to batfactors, and looks like I forgot that BatBrain parses familiars differently than it parses other events. I've just uploaded a new batfactors with rate 1, before the existing comment which I believe ought to solve that issue.
 
Line 1267 in batbrain.ash
Code:
   boolean are_attracting() { foreach s in $strings[gallapagosMonster, nosyNoseMonster, olfactedMonster, longConMonster, makeFriendsMonster] 
      if (to_monster(get_property(s)) == m) return true; return false; }

gallapagosMonster should be _gallapagosMonster
Otherwise it spams the mating call skill every adventure a zone it wants to attract a specific monster which burns a lot of MP unnecessarily.

Also

Code:
Changing "Invader" to "the invader" would get rid of this message. (BatBrain.ash, line 1093)

Also also, if you have Gallapagosian Mating Call and Transcendent Olfaction, it'll only ever cast the first one. I've not tested with the Nosy Nose as my test account doesn't have one but it will also be similarly ignored as the code pasted above returns true for the first match from left to right.
 
Last edited:
Finally got around to posting a fix to those little bugs. r129.

BatBrain's attraction logic only uses one of your available attraction actions at the moment, pending superior logic for determining when to use multiple attraction skills, which is unfortunately non-trivial.
 
r19887

Latest version of all scripts according to svn update.

Code:
Cannot store advevent in res[] of type float [element]     (BatBrain.ash, line 149)
Consult script     'wham.ash' not found.
You're on your own,     partner.
Click     here to continue in the relay browser.

CCS is wham.

Reporting here because the offending line was identified as being in Batbrain.

Probably related to varargs work.
 
I'm on it.

Code:
typedef float[element] spread;

record advevent {          // record of changes due to an event
   spread dmg;             // raw dmg dealt, before resists/vulns
};

spread copy(spread source) {
   spread res;
   foreach el,v in source res[el] = v;
   return res;
}

advevent copy(advevent source) {
   advevent res;
   res.dmg = copy(source.dmg);
   return res;
}

advevent base;             // happens every round for the rest of combat

// **** TEST
advevent test = copy( base );
yields

Code:
[color=green]> bbtest[/color]

[color=red]Cannot store advevent in res[] of type float [element] (bbtest.ash, line 15)[/color]
 
Last edited:
Still getting
Unexpected error, debug log printed.
Consult script 'wham.ash' not found.
You're on your own, partner.


Even though it is there and nothing about my CSS has changed
 
r132 adds basic Plumber support. Besides blacklisting "attack", each Plumber skill should also now contain the proper results for its current tier, which should also be set correctly in BatBrain. I'm just starting my first run so this is mostly untested. I am aware of two problems already:

1) I had to guess what the possible costume names were for the costume property when setting the tier. If any of my guesses were wrong, you won't be able to reach tier 3 according to BatBrain.
b) Happenings tracking is wrong because mafia defaults to the Passive version of the skill when to_skill()-ing the message from the session log. This also confuses/renders useless the "submit previous fight again" macro button in BatMan RE.

The first is easily enough fixed if someone tells me what the canonical values are, or I figure them all out myself eventually (EDIT: Just got a costume; looks like they're all stat names? Convenient). The latter is less easily fixed and would probably require a feature request -- either to use [1234]this sort of name in the session logs, or adding a version of to_skill() to ASH where you can specify a preference for lower-number matches.
 
Last edited:
The first is easily enough fixed if someone tells me what the canonical values are, or I figure them all out myself eventually.

Quickly checking the code (mafia and yours), it seems your first guess wasn't right. Carpenter is "muscle", gardener is "mysticality", ballerina is "moxie" otherwise "none".
 
I could prefix an [id] easily enough to skills in the session log, but perhaps some might find that overly chatty? Seems fine to me though.
 
II think I'd prefer something like

skill to_combat_skill( string )

SkillDatabase.getCombatSkill( String ) will do it.

Or even

skill to_skill( string, type )

Internal types, which can be used to filter skills in SkillDatabase.getSkillsByType:

CASTABLE
COMBAT
REMEDY
PASSIVE

(each of which combines multiple subtypes) or

SUMMON
SELF_ONLY
BUFF
SONG
EXPRESSION
WALK
COMBAT_NONCOMBAT_REMEDY
 
Last edited:
I just (r19905) added something that I've wanted for ages that would pave the way for a workaround for issues like this. cli_execute_output will give you the results of a cli_execute as a string, which I've seen lots of people asking about before. It's not foolproof of course, because you might trigger some output to the RequestLogger that isn't directly related to your command, but it can be useful.

Here you could have then done

Code:
cli_execute_output(`test skillids {skillName}`);

then parse the output and loop through the ids for the one you wanted. Of course, Veracity's solution in this particular case would be a lot better.
 
I will also point out that you can easily create your own list of just combat skills.

Code:
typedef skill [string] skill_name_map;

skill_name_map buff;
skill_name_map combat;
skill_name_map expression;
skill_name_map passive;
skill_name_map song;
skill_name_map summon;
skill_name_map walk;

foreach sk in $skills[] {
    if ( sk.buff )
	buff[sk.name] = sk;
    if ( sk.combat )
	combat[sk.name] = sk;
    if ( sk.expression )
	expression[sk.name] = sk;
    if ( sk.passive )
	passive[sk.name] = sk;
    if ( sk.song )
	song[sk.name] = sk;
    if ( sk.summon )
	summon[sk.name] = sk;
    if ( sk.walk )
	walk[sk.name] = sk;
}

print( `There are {count(buff)} buffs` );
print( `There are {count(combat)} combat skills` );
print( `There are {count(expression)} expressions` );
print( `There are {count(passive)} passive skills` );
print( `There are {count(song)} songs` );
print( `There are {count(summon)} summoning skills` );
print( `There are {count(walk)} walk skills` );
yields

Code:
[color=green]> skills_by_type[/color]

There are 47 buffs
There are 504 combat skills
There are 16 expressions
There are 403 passive skills
There are 11 songs
There are 57 summoning skills
There are 3 walk skills
You can use the "combat" map to take a skill name from the session log and get the skill object.
 
Last edited:
I will also point out that you can easily create your own list of just combat skills.

This is quite true. What makes me hesitant to do it this way is that foreaching $skills[] and a handful of map lookups every round of every combat is a good bit more expensive in terms of processing time. "It's too slow" is probably the biggest drawback/criticism of BatBrain, and I've been over the script repeatedly with the profiler to try to make it faster, using static variables where I can, caching parsed information to avoid parsing it every time, etc. and it still is noticeably slower than most other methods of combat automation. I can do what you're suggesting but I'd really prefer a solution that didn't add quite so much to the runtime, if possible.

I think I'd prefer something like

skill to_combat_skill( string )

SkillDatabase.getCombatSkill( String ) will do it.

That would be excellent.

@gausie: I missed your adding cli_execute_output(). I think that's been brought up over the years numerous times; cheers on implementing it! Your solution provides a nice lateral-thinking hack if a pure data approach is unavailable or too sluggish. :)
 
Last edited:
This is quite true. What makes me hesitant to do it this way is that foreaching $skills[] and a handful of map lookups every round of every combat is a good bit more expensive in terms of processing time.
No. Make those maps static and initialize them in a static block. They will be initialized the first time the script is run. You can access them forevermore with no additional overhead.

That said, KoLmafia has those maps built in, so perhaps the "to_skill( name, type )" solution would be best.
 
Back
Top