CounterChecker: Wormwood, Semi-rares, Dance Cards and more

viable Options:
timely
true, always
false, never

Optionally there can be a number appended at the end to indicate maximum number of counters lest another cookie be eaten.

By appended, do you mean "timely 1" or "timely1"?
 
Excellent!

For appending, I was planning to use contains_text() so the space won't matter. Less opportunity for user error.
 
get_counters("Fortune Cookie",0,200) will produce a tab delimited list. So, count the number of tabs? Hmmm... I guess something like this:

PHP:
if(get_counters("Fortune Cookie",0,200) == "" || count(split_string( get_counters("Fortune Cookie",0,200), "\t")) != 1) 
   eatsilent(1, $item[fortune cookie]);
It worked perfectly. Thanks!
 
This is what I have now (untested):

PHP:
boolean cookiecheck() {
   if (my_fullness() == fullness_limit()) return true;
   matcher cooks = create_matcher("([a-z]*) {0,1}([1-3]{0,1})",vars["auto_semirare"]);
   if (!cooks.find()) return vprint("Warning: your auto_semirare setting is not an accepted value: timely|always|never (maximumcounters)",-5);
   switch (cooks.group(1)) {
      case "timely": if (get_counters("Fortune Cookie",0,200) != "" || get_counters("Semirare window begin",1,200) != "")
         return vprint("BBB: No need to eat a cookie given the present counters.","#F87217",8);
         if (my_location() != to_location(get_property("semirareLocation")) && $locations[Purple Light District, Haunted Billiards Room,
             Menagerie 2, Outskirts of The Knob, Limerick Dungeon, Sleazy Back Alley, Haunted Pantry, Harem] contains my_location())
           return vprint("BBB: "+my_location()+" contains a nice semi-rare; not auto-eating cookie.  Eat one manually if you want your counterScript to handle it.","#F87217",5);
      case "always": case "true":
         while (get_counters("Fortune Cookie",0,200) == "" ||
                (to_int(cooks.group(2)) > 0 && count(split_string(get_counters("Fortune Cookie",0,200),"\t")) > to_int(cooks.group(2)))) {
            if (my_fullness() == fullness_limit()) return true;
            if (!eatsilent(1,$item[fortune cookie])) return false;
         }
   }
   return true;
}

I would like to point out that I have realized the truth of these immortal words: "Fear leads to anger. Anger leads to hate. Hate leads to suffering." Therefore, I have faced my fears and included my first ever regex. If I did something suboptimally, please let me know.

This will be in the upcoming BBB update, just as soon as I figure out how to update the auto-turtle-taming given recent changes. Blasted TPTB, I really can't keep up with all their changes these days.
 
{0,1} is usually written as ?
You also probably want [a-z]+ instead of [a-z]*, so that it doesn't match empty strings.
That makes
Code:
matcher cooks = create_matcher("([a-z]+) ?([1-3]?)",vars["auto_semirare"]);

Of course, since you only have three valid values for the first group anyway, you might want to actually ensure that ... (your version doesn't catch this condition anywhere, not even in the switch):

Code:
matcher cooks = create_matcher("(timely|always|never) ?([1-3]?)",vars["auto_semirare"]);
 
Last edited:
Oh yeah, I'd changed that * to a + locally but I guess I'd pasted it here before changing that.

Excellent about the ?, I hadn't come across that in the tutorial I read.

And there are more than three valid values, but only three of them matter to the code (and that doesn't include "never" since all non-matches are treated as "never"). So I'll either include all possible values in the group in the manner you suggest or just keep matching on any word.
 
I would probably just keep the pattern matching anything, then add a catch-all default: in the switch to display the error message (and put that message somewhere else, so that you don't have to fix two occurences of the same string when you change the valid values). Just so I wouldn't have to *triplicate* the list of valid values (once in the switch, once in the error message, once in the regex).

ETA: or, if you want to treat all non-matches as "never", you might want to write a comment to that effect (the several-years-down-the-timeline-you will than the now-you for that practice) and possibly modify the warning?
 
Last edited:
Ended up going with "(timely|always|true|never|false) ?([1-3]?)". Thanks for your help.

@Bale: new BBB will be rolled out within a day or two. Feel free to snatch any of the posted code for eating/parsing the preference to make our scripts play wonderfully together.

Also -- would you prefer "auto_semirare" or "bbb_auto_semirare"? The former follows my ideals for shared names, but several users seem to prefer that every setting be prefixed with an owning script even when multiple scripts reference it. I'll leave that call up to you (and whoever else chimes in here).
 
Last edited:
Would it make sense for multi_auto_semirare, multiple_auto_semirare, or shared_auto_semirare? Something that's obviously shared, but splits it off as well.
 
@Bale: new BBB will be rolled out within a day or two. Feel free to snatch any of the posted code for eating/parsing the preference to make our scripts play wonderfully together.

I've been busy with other things. I'll try to get to this soon.

Basically, I just need to skip eating cookies when the value of vars["auto_semirare"] is timely, never or false. (Or if numerical, eat another cookie when I have more than that number of cookie counters.) Right?
 
Basically, yes. Your script should react as follows to the "auto_semirare" setting:

"always (n)" or "true": definitely eat enough cookies to guarantee no more than n Fortune Cookie counters (or any counters if not specified). Some of the above code is probably directly stealable for this. You could adjust the matcher to "(always|true) ?([1-3]?)" and if no matches are found, skip eating cookies.
anything else: skip eating cookies.
 
When you don't have a semi-rare window set, Mafia doesn't always discard numbers that are too high. This should only be a problem for the first Semi-rare of a run though. Maybe this should be taken into account before eating 2 cookies to discard a number that should have been discarded but wasn't?
 
Using a reasonable maximum number in get_counters() should obviate that problem.

Bale: this is not pressure, just information. Take your time. BBB will work fine without CC being updated. It will just work better after the CC update. Script synergy ftw.
 
So, what do you think of this?

PHP:
int count_counters() {
	string counters = get_counters("Fortune Cookie", 0, 200);
	if(counters == "") return 0;
	return count(split_string(counters, "/t"));
}

boolean toEat() {
	if(vars contains "auto_semirare") {
		matcher cooks = create_matcher("(timely|always|true|never|false) ?([1-3]?)", vars["auto_semirare"]);
		if(cooks.find())
			switch(cooks.group(1)) {
			case "false":
			case "never":
			case "timely": return false;
			case "always":
			case "true": return count_counters() < cooks.group(2).to_int();
			}
	}
	return count_counters() < 1;
}


void eat_cookie() {
	if(get_property("semirareCounter").to_int() != last) {
		// semi-rare acquired, let's do it again
		if(my_fullness() == fullness_limit())
			print("If I ate even a fortune cookie I'd burst! Remember to eat a fortune cookie when the tummy is emptier.", "red");
		else while(toEat())
			eatsilent(1, $item[fortune cookie]);
	} else
		print("Oops, that wasn't the right number!", "red");
}
 
Last edited:
I love the integration between the two scripts. One request: for aftercore farming, is there any way that I can specify whether to use milk of magnesium before eating the cookie? Thanks so much!
 
The milk will add exactly one adventure, so you'd just have to compare the price of the milk to valueOfAdventure to see if it would be worth it.
 
The milk will add exactly one adventure, so you'd just have to compare the price of the milk to valueOfAdventure to see if it would be worth it.

I agree that makes sense. However, if I added the feature I think a simple "true" or "false" to using milk would be best since otherwise I'd get complaints.
 
You'll get complaints no matter what, so that's not particularly relevant. :)

I like comparing it to valueOfAdventure, particularly if you may be about to eat multiple cookies and thereby gain multiple adventures (for example, if someone specified "always 1"). Depending on prices, that may mean the difference between profit and loss.

Seems to me like calculating the odds of getting X valid counters from Y cookies is necessary -- solving for Y (as a float). That number would be multiplied by valueOfAdventure to determine the gross profit of eating milk. But that's what I might call overkill.

EDIT: This problem interested me so I came up with this:

PHP:
int valid_sr_count() {
   if (get_counters("Fortune Cookie",0,200) != "") 
      return count(split_string(get_counters("Fortune Cookie",0,200),"\t"));
   int counter_num(string whichcounter) {  // returns the first matching counter, or -1 if not found
      if (get_counters(whichcounter,0,2000) == "") return -1;
      for i from 0 to 2000 if (get_counters(whichcounter,i,i) != "")) return i; return -1;
   }
   int sr_start() {
      return max(0,max(counter_num("Semirare window begin"),70 - my_turncount()));
   }
   int sr_stop() {
      if (get_counters("Semirare window end",1,200) != "") return counter_num("Semirare window end");
      if (my_turncount() < 82) return 81 - my_turncount();
      return 200 - (to_int(in_hardcore() && !can_drink() && !can_eat()))*80;
   }
   return sr_stop() - sr_start();
}

// chance that a random lucky number will be valid
valid_sr_count()/300

// chance that a random lucky number will be discarded
1 - (valid_sr_count())/300)

// counters after eating one cookie
1 + 2*(valid_sr_count()/300)

It may be useful. Or maybe not.
 
Last edited:
I have a quick question on usage. I've got this script set up and working properly to trigger counters, but I'm curious how to use it to help me do a specific thing.

I have an arbitrarily large supply of absinthe, but all I want to get is three not-a-pipes a day (generally a bounty with sniffing takes about this long). If I set a mood to reapply absinthe-minded I have to fiddle around by adventuring until I get two pipes, clearing the trigger, and getting the last pipe; otherwise, since conditions aren't checked until the last "real" adventure, not the counter interrupt, I end up swigging an extra bottle.

Is there some way to go about this other than simple effect triggers and mood setting, preferably one that requires less day-to-day intervention on my part, even if it's more complex to set up?
 
Back
Top