My personal Meat farming script

I often run VMF right after I finish a run. Since I am slow, many of my runs are five days or more. My skeleton garden, which was unharvested during run because it is out of style, has a Skulldozer. VMF does not fight the Skulldozer. At least twice, due to my repeated inattention, I have not had any adventures left after running VMF to fight it. Would you consider something that might save me from myself? Fighting the dozer is an obvious possibility or just stopping the script if the dozer is there is another. I can think of circumstances where someone else would not want either of those choices so I defer to your wisdom in this matter. Thank you.
 
That would be in Veracity Garden Harvester. That should or could be configurable to ignore it. It would need code to fight it. I’ll take a look.
 
I've been working on visiting Madame Zatara and collecting the three daily items. CheeseFax is configured to respond appropriately, if you are in Bonus Adventures to Hell. How hard could it be? It was trickier than I anticipated, but after consulting with cheesecookie about how CheeseFax operates, I have it working. I might do some tweaking, but I'll release this now so others can try it out.

Here are the configuration options:

Code:
// Which fortune teller buff to request
//
// susie (familiar)		A Girl Named Sue (Familiar Weight: +5, Experience (familiar): +5, Familiar Damage: +10)
// hagnk (items)		There's No N in Love (Item Drop: +50, Food Drop: +50, Booze Drop: +50)
// meatsmith (meat)		Meet the Meat (Meat Drop: +100, Gear Drop: +50)
// gunther (muscle)		Gunther Than Thou (Experience (Muscle): +5, Muscle Percent: +100, Maximum HP Percent: +50)
// gorgonzola (mysticality)	Everybody Calls Him Gorgon (Experience (Mysticality): +5, Mysticality Percent: +100, Maximum MP Percent: +50)
// shifty (moxie)		They Call Him Shifty Because... (Experience (Moxie): +5, Moxie Percent: +100, Initiative: +50)
// none

string fortune_teller_npc = define_property( "VMF.FortuneTellerNPC", "string", "meat" );

// Go to Bonus Adventures From Hell and consult with CheeseFax
// 
// send: pizza, batman, thick
// receive: beer, robin, thin

boolean consult_with_cheesefax = define_property( "VMF.ConsultWithCheeseFax", "boolean", "false" ).to_boolean();
Like other Clan Lounge things, VMF will look in your own clan for furnishings. So, if you want a buff - such as "meat" or "items" or whatever - specified via VMF.FortuneTellerNPC, you need the fortune teller in your own clan.

That is not the same for consulting with CheeseFax, though. You need the following:

- a VIP lounge key
- a whitelist to Bonus Adventures From Hell
- not being the clan leader, since if you are, you cannot leave the clan. :)

Given those, do this:

set VMF.ConsultWithCheeseFax=true

and VMF will get you some stuff each day. Here's gCLI output of today's test:

Code:
[color=green]> ash import <VeracityMeatFarm.ash>; consult_with_madame_zatara()[/color]

[color=green]Now pledging your allegiance to Bonus Adventures from Hell.[/color]

You are currently a member of Bonus Adventures from Hell
Visiting Hot Dog Stand in clan VIP lounge
Visiting Speakeasy in clan VIP lounge
Visiting Floundry in clan VIP lounge
Visiting Fortune Teller in clan VIP lounge
You enter your answers and wait for 3038166
Waiting for 3038166 to respond...
Visiting Fortune Teller in clan VIP lounge
You enter your answers and wait for 3038166
Waiting for 3038166 to respond...
Visiting Fortune Teller in clan VIP lounge
You enter your answers and wait for 3038166
Waiting for 3038166 to respond...
Visiting Fortune Teller in clan VIP lounge
[color=green]Now pledging your allegiance to Hardcore Oxygenation.[/color]

You are currently a member of Hardcore Oxygenation
Updating inventory...
Returned: void
02/04/20 11:02:29 AM - New message received from CheeseFax.
02/04/20 11:02:40 AM - New message received from CheeseFax.
02/04/20 11:02:51 AM - New message received from CheeseFax.
(The New Message lines did not appear until I opened the Relay Browser)

This is tricky, since you are interacting with a different KoL player.

Requesting a fax: sent a chat message, wait for a chat message in response. We have built-in support in KoLmafia to recognize the chat response and built in ASH functions to handle the whole transaction.
Asking for a buff from a buffbot: send an IM or kmail, receive a response. You can tell when it finishes by looking at active effects.
Madame Zatara: make a request to ask for a reading. Eventually, the other player responds and you get kmail.

We have the "fortune" command to make requests of Madame Zatara - "fortune CheeseFax pizza batman thick" will initiate the request, but not wait for the response. Looking at the request/response interactions with Madame Zatara, I see no way to probe her and see if you have an outstanding request, other than trying to make another request and being told you are waiting; you can't just visit her and learn that.

And once you know the request is complete, you can't see the results without looking at kmail.

I initially worked on setting up ASH access to KoLmafia's internal kmail functionality - no longer active; we used to have an "Ice Penguin" (play on "Firefox") GUI, but hola removed that a long time ago - but that turned into a whole lot of too much work. So I took inspiration from cc_ascend's interface to Madame Zatari (helpfully provided by cheesecookie) and rolled it into a simple version that suits this script's needs: As you can see from the above output, it works.

I am disappointed I could not use the built-in "fortune" CLI command for this. Perhaps I could add ASH functionality. But, visit_url, for now.

Here's the function I wrote, for amusement:

Code:
void consult_with_madame_zatara()
{
    if ( !have_lounge_key || !consult_with_cheesefax ) {
	return;
    }

    // Check how many times you've consulted with a clanmate.
    // You are allowed three per day.
    if ( get_property( "_clanFortuneConsultUses" ).to_int() >= 3 ) {
	return;
    }

    try {
	// We start out in home_clan
	if ( home_clan != BAFH ) {
	    cli_execute( "/whitelist " + BAFH );
	}

	if ( BAFH != get_clan_name() ) {
	    print( "You are not whitelisted in " + BAFH + ". Fix that and try again.", "red" );
	    return;
	}

	// CheeseFax
	int player = 3038166;
	string name = get_player_name( player );

	int retries = 12;
	while ( true ) {
	    string page = visit_url( "clan_viplounge.php?preaction=lovetester", false );
	    page = visit_url( "choice.php?pwd=&whichchoice=1278&option=1&which=1&whichid=" + name + "&q1=pizza&q2=batman&q3=thick" );
	    if ( page.contains_text( "You can't consult Madame Zatara about your relationship with anyone else today." ) ) {
		return;
	    }
	    if ( page.contains_text( "You enter your answers and wait for " + name + " to answer, so you can get your results!" ) ||
		 page.contains_text( "You're already waiting on your results with " + name + "." ) ) {
		print( "Waiting for " + name + " to respond..." );
	    }
	    else if ( page.contains_text( "You can only consult Madame Zatara about someone in your clan.") ) {
		print( name + " is not in the clan. Waiting...", "blue" );
	    } else {
		print( "Waiting for " + name + " to respond..." );
	    }
	    if ( --retries < 0 ) {
		print( name + " seems to be lost. Giving up.", "red" );
		return;
	    }
	    waitq( 10 );
	}
    } finally {
	if ( home_clan != get_clan_name() ) {
	    cli_execute( "/whitelist " + home_clan );
	}

	// New items arrive in kmail
	cli_execute( "refresh inventory" );
    }
}
Switching clans via "/whitelist" is easy, but weird. It submits a chat request, whose response has a JavaScript redirect to the appropriate clan recruiter page, which we submit.
And the output looks prettier if you have CheeseFax in your contact list - although it is not necessary.

Revision 224.
 
Collecting those automatically is really a pain. Easyfax will come visit your clan, assuming it hasn't been trapped as clan leader, which has been happening often since the once a week check was changed to daily.
 
I didn't know EasyFax would do that too - and in your own clan. Will it linger, waiting for all three Madame Zatara requests?
I could make this configurable to use either CheeseFax or EasyFax; the only difference would the clan switching - and doing whatever is needed to summon EasyFax.
And I am sure that Frono will comment that his "doesn't have chat access" multi can't use "/whitelist" to switch clans. :)

(I've noticed a lot of errors, right after rollover, from EasyFax saying "that monster is not available. Look at this file to see what is available" - and I look there and the monster is there. As expected, since we wouldn't have sent you a request if we didn't see it in the config file. Is that message the equivalent of "Help, I'm stuck in a clan and can't get out to go get that monster"?)
 
And I have what is, essentially, an "inventory difference" function that I could use to extract what you got without having to look at kmail by comparing your inventory before consulting Madame Zatara with what it is afterwards (having refreshed inventory, which will account for the items that came in kmail).

I'll try that tomorrow.
 
That would be in Veracity Garden Harvester. That should or could be configurable to ignore it. It would need code to fight it. I’ll take a look.
I just planted a Bone Garden. I've had Tall Grass ever since it came out; it is the only Standard-compatible Garden, and I've pulled 4 Mu familiars out of it, which have more than paid for it.
But I'm done with Standard for the year (6 Normal and 6 Hardcore ascensions) until the next challenge path, so I have time to try this out.
Stay tuned.
 
*snicker*

The chatless multi exists in that state to keep KoLMafia accessible to all. So I should be fine if a script requires chat :-)

Thanks for the clan switching discussion. It explains some faxbot issues I have seen but not reported.
 
Revision 225 soups up the Zatara consultations a few ways:

KoLmafia has some existing properties, used by the "fortune" command and the ClanFortuneRequest:

// clanFortuneWord1 default = pizza
// clanFortuneWord2 default = batman
// clanFortuneWord3 default = thick

VMF now uses those values for word1, word2, and word3.

Those are all "compatible" requests to CheeseFax's responses. If you want "incompatible" prizes from any question, change the appropriate word.

I also save your inventory before doing the Zatara queries and, when you are done, after refreshing inventory, get the current inventory.
I You can get other items in kmail and can lose items to PVP, so I filter on valid Zatara prizes and tell you what you got.

None of the above has actually been tested in the wild. I will see for myself after rollover and fix any issues. Not that I expect any.

New function:

Code:
void consult_with_madame_zatara()
{
    if ( !have_lounge_key || !consult_with_cheesefax ) {
	return;
    }

    // Check how many times you've consulted with a clanmate.
    // You are allowed three per day.
    if ( get_property( "_clanFortuneConsultUses" ).to_int() >= 3 ) {
	return;
    }

    string word1 = get_property( "clanFortuneWord1" );
    boolean compatible1 = word1 ≈ "pizza";
    string word2 = get_property( "clanFortuneWord2" );
    boolean compatible2 = word2 ≈ "batman";
    string word3 = get_property( "clanFortuneWord3" );
    boolean compatible3 = word3 ≈ "thick";

    print( "Consulting with CheeseFax seeking {" +
	   ( compatible1 ? "compatible" : "incompatible" ) + ", " +
	   ( compatible2 ? "compatible" : "incompatible" ) + ", " +
	   ( compatible3 ? "compatible" : "incompatible" ) +
	   "} prizes." );

    // CheeseFax
    int player = 3038166;

    // Unless CheeseFax is on your contact list, this will return the player ID.
    // Which works, even though responses from Madame Zatara will use the name
    string name = get_player_name( player );

    string consultURL =
	"choice.php?pwd=&whichchoice=1278&option=1&which=1" +
	"&whichid=" + name +
	"&q1=" + word1 +
	"&q2=" + word2 +
	"&q3=" + word3;

    // Save current inventory
    item_to_int_map initial_inventory = get_inventory();

    try {
	// We start out in home_clan
	if ( home_clan != BAFH ) {
	    cli_execute( "/whitelist " + BAFH );
	}

	if ( BAFH != get_clan_name() ) {
	    print( "You are not whitelisted in " + BAFH + ". Fix that and try again.", "red" );
	    return;
	}

	int retries = 12;
	while ( true ) {
	    string page = visit_url( "clan_viplounge.php?preaction=lovetester", false );
	    page = visit_url( consultURL );
	    if ( page.contains_text( "You can't consult Madame Zatara about your relationship with anyone else today." ) ) {
		return;
	    }
	    if ( page.contains_text( "You enter your answers and wait for " + name + " to answer, so you can get your results!" ) ||
		 page.contains_text( "You're already waiting on your results with " + name + "." ) ) {
		print( "Waiting for " + name + " to respond..." );
	    }
	    else if ( page.contains_text( "You can only consult Madame Zatara about someone in your clan.") ) {
		print( name + " is not in the clan. Waiting...", "blue" );
	    } else {
		print( "Waiting for " + name + " to respond..." );
	    }
	    if ( --retries < 0 ) {
		print( name + " seems to be lost. Giving up.", "red" );
		return;
	    }
	    waitq( 10 );
	}
    } finally {
	if ( home_clan != get_clan_name() ) {
	    cli_execute( "/whitelist " + home_clan );
	}

	// New items arrive in kmail
	cli_execute( "refresh inventory" );

	item_to_int_map inventory_diff = item_map_difference( initial_inventory, get_inventory() );

	// You can gain other items in kmail or lose things by PVP.
	// Make a map containing only Zatara's prizes
	item_to_int_map prizes;
	foreach it, count in inventory_diff {
	    if ( ZATARA_PRIZES contains it && count == 1 ) {
		prizes[ it ] = count;
	    }
	}

	if ( count( prizes ) > 0 ) {
	    print( "The following iteme arrived from " + name + ":" );
	    foreach it, count in zatara_prizes {
		print( "    " + it );
	    }
	}
    }
}
 
Revision 227 adds support for the Boxing Daycare

boolean boxing_daycare = define_property( "VMF.UseBoxingDaycare", "boolean", "true" ).to_boolean();

It's optional, but defaults to true.

Having a Boxing Daydream can be done once a day to receive an item. There is no reason to defer doing that, so we'll always do that.

// Boxing Daycare Spa - get a buff once per day
//
// Muddled (muscle) Muscle Percent: +200, Monster Level: +15
// Ten out of Ten (moxie) Moxie Percent: +200, Initiative: +50
// Uncucumbered (mysticality) Mysticality Percent: +200, Item Drop: +25
// Flagrantly Fragrant (regen) Maximum HP: +100, Maximum MP: +50, Damage Reduction: 25, MP Regen Min: 5, MP Regen Max: 10, HP Regen Min: 10, HP Regen Max: 20

string boxing_daycare_buff = define_property( "VMF.BoxingDaycareBuff", "string", "mysticality" );

You can get a buff once a day. You can specify it either by buff name or by keyword. The default is "mysticality" - "Uncucumbered" - which gives you an item drop bonus

// Number of times to scavenge for equipment. 1st is free, so that's the default
int boxing_daycare_scavenge = define_property( "VMF.BoxingDaycareScavenge", "int", "1" ).to_int();

// Number of times to recruit toddlers. Cost increases geometrically: 100, 1000, 10,000, ...
int boxing_daycare_recruit = define_property( "VMF.BoxingDaycareRecruit", "int", "0" ).to_int();

// Sparring takes a turn. It gives you a small amount of stats. The first time also gives PVP fights.
// If you want fights, it is reasonable to spar once. Otherwise, don't spar
boolean boxing_daycare_spar = define_property( "VMF.BoxingDaycareSpar", "boolean", "false" ).to_boolean();

Scavenging for equipment is free, the first time each day, so we'll do that by default.

Recruiting toddlers costs an increasing amount of Meat each time. If you want to improve the effectiveness of Sparring, you want more toddlers. But, because it costs Meat, we don't do it by default.

Hiring instructors does ... something ... but costs variable amount of random items. Do that by hand, if you want to.

Sparring costs an adventure and gives PVP fights (and some stats) the first time each day. Only you can decide if you want/need PVP fights, so only you can decide if spending a turn to get some is worth it.
 
Revision 228 fixes a typo in my code that reports on which items you got from CheeseFax.

And here's a fun little alias:

alias zatara => ashq import <VeracityMeatFarm.ash>; consult_with_madame_zatara()
 
Revision 230 saves the items we received from Madame Zatara in _zataraPrizes, so you can look at it later, if you are not running the function by itself.

I noticed that CheeseFax was out of the clan for two whole minutes after I requested the relationship test with him. He came back later and answered, but the function had timed out by then.
I reran it and it picked up where it left off and got all three prizes.

Makes me think that I need a longer timeout.
 
Revision 231 fixes a bug:

If you have a fax monster but neither rain-doh nor spooky putty, we'd still try to set up copying with both of those.

My only multi who didn't have a VIP key and is not a clan leader bought a VIP key, so I could have a character whose clan had nothing but a fax machine in its VIP lounge to test stuff. This character went to BAFH just fine for Madame Zatara, but when I set a Fax Monster (Knob Goblin Embezzler), EasyFax sent it over but the script failed attempting to use a Rain-doh black box.

I'm astonished that nobody reported this before. Apparently, everybody who has a VIP key and a fax machine in their clan also had a copying item?

Maybe this character will make me consider whitelisting over to BAFH (and back) in order to use clan lounge items.
 
I'm astonished that nobody reported this before. Apparently, everybody who has a VIP key and a fax machine in their clan also had a copying item?

I run the script. It works as expected so I have nothing to report. The issue is probably my expectations.

I have no recollection of ever seeing it fax so there may be a combination of settings that kept it from trying or it may be that I have no expectation of it copying anything so I don't notice the absence. I'm sure I can't provide an accurate list of copiers but I don't think I have any of the ones I know about. Character does not clan hop and Madame Z is done entirely within the clan.

Is there anything I should check/watch for before I run tomorrow?
 
I have no recollection of ever seeing it fax so there may be a combination of settings that kept it from trying or it may be that I have no expectation of it copying anything so I don't notice the absence.

Here are the settings:

monster fax_monster = define_property( "VMF.FaxMonster", "monster", "" ).to_monster();
boolean use_rain_doh = define_property( "VMF.UseRainDoh", "boolean", "true" ).to_boolean();
boolean use_spooky_putty = define_property( "VMF.UseSpookyPutty", "boolean", "true" ).to_boolean();

If you don't set VMF.FaxMonster, it will not fax.
If you do set it, VMF.UseRainDoh and VMF.UseSpookyPutty will let you make additional copies of your faxed monster.

I had two characters with VIP keys. They both also have at least one copier. They faxed and copied monsters.
I now have a third character with a VIP key - and no copiers. That didn't work - until I fixed it.
Today, that charaacter faxed in a monster and fought it with no problem. I.e., without trying to use a copier she did not own.
 
Revision 232 removes Gingerbread City from being automatically installed - and, in fact, imported into the script at runtime. Instead, this script treats it like any of the other External Scripts that it can invoke: if you configured VMF to use the script and have the appropriate IOTM, it will be invoked via "call", rather than by calling an internal function.

The only required External scripts which ARE automatically installed - and imported at compile time - are vprops, vcon, and Garden Harvester.

This revision also changes the timeout for consulting 3 times with Madame Zatara to be 5 minutes, waiting 5 seconds at a time. The normal case, when CheeseFax is at home in BAFH, will finish in 20 seconds, but if he is out distributing faxes some of the time, we won't give up for 5 minutes, which should be plenty, even right after rollover. I hope.

Here's the comment I put in about external scripts:

Code:
// ***************************
// *     External Scripts    *
// ***************************

// Required scripts which are are installed automatically
//
// vprops			Veracity's property management library
//				https://kolmafia.us/showthread.php?21593
//				veracity0-vprops
// vcon				Veracity's consumable library
//				https://kolmafia.us/showthread.php?23145
//				veracity0-vcon
// Garden Harvester		Veracity's Garden Harvester
//				https://kolmafia.us/showthread.php?21651
//				veracity0-garden
//
// The following scripts are optional. If they are installed and this
// script is configured to use them, they will be invoked as needed
//
// Here are the script name (as seen in the Script Manager), the forum
// thread describing it, and the repo in your "svn" directory
//
// Veracity Scripts:
//
// Beach Comb			Veracity's BeachComber
//				https://kolmafia.us/showthread.php?23993
//				veracity0-beach
// Spacegate			Veracity's Spacegate
//				https://kolmafia.us/showthread.php?23335
//				veracity0-spacegate
// Gingerbread City		Veracity's Gingerbread City
//				https://kolmafia.us/showthread.php?21609
//				veracity0-gingerbread
//
// Ezandora scripts:
//
// Detective School		Detective Solver
//				https://kolmafia.us/showthread.php?20406
//				Ezandora-Detective-Solver-branches-Release
// TimeSpinner			Far Future
//				https://kolmafia.us/showthread.php?20575
//				Ezandora-Far-Future-branches-Release
// (soon)
// Kremlin's Greatest Briefcase	KGBriefcase
//				https://kolmafia.us/showthread.php?21892
//				Ezandora-Briefcase-branches-Release
// Bastille Battalion		Bastille
//				https://kolmafia.us/showthread.php?22957
//				Ezandora-Bastille-branches-Release
Note that I tell you what the optional scripts are named in the Script Manager - so you can find them to install - as well as the kolmafia.us forum thread pertaining to the script. Also, mostly for my own reference, the directory in KoLmafia's "svn" directory where that script is installed.

Some those scripts have VMF configuration and if you enable the script, at validation, we require them to be installed.
Some have no configuration needed (Detective Solver, for example) and we don't check if they are installed at validation time.

Some options:

1) List all optional scripts as svn dependencies, which will install them all, whether or not you have the prerequisites (IOTM) to use them.
2) Or for all external scripts, provide a configuration property to say whether they should be used, and fail validation if they are not installed.
3) Or for all external scripts for which you have the prereqs (IOTM), if you have not installed (and configured) them, give a warning (suggestion) to install and configure the script.

Not that you will see validation warnings, unless you watch the validation phase of the script - which is the very first stage of execution.

Thoughts?

(By the way, I'll be releasing an Arrrbor Day script, which VMF will require - and therefore install - but not import. Considering I won't be able to test it for anoth 86 days, I haven't started writing it yet. :) )
 
Thank you. I set VMF.FaxMonster and got a fax but not any further copying which is what I expect. I note the undesirable visual clutter of a chat window that remains open but if it REALLY bothers me, I can close it manually. I will run with the chatless character eventually just to see what happens but I don't expect any changes to be made. It would have been nice if VMF "suggested" a fax monster but I understand why there isn't a default. Knob Goblin Embezzler or is there something better? Given its role as a "don't forget" script I can imagine a FR for it to pick a fax monster based upon lack of Manuel information but I can also see that being a whole lot of work for you compared to me just making sure I do that before I run VMF and knowing the fax opportunity wasn't wasted if I forget.

Thank you again.
 
Thank you. I set VMF.FaxMonster and got a fax but not any further copying which is what I expect. I note the undesirable visual clutter of a chat window that remains open but if it REALLY bothers me, I can close it manually. I will run with the chatless character eventually just to see what happens but I don't expect any changes to be made.
Well, yes. KoLmafia's built-in support for faxbots in tied to chat: it sends a chat message and recognizes the specific chat message that comes in response to it, which requires chat to be open.

I would not be surprised if there was a scripting way to do without that: perhaps by receiving chat messages directly, somehow, and processing them. A little chat bot, of sorts. But I didn't want to include that in my script. Perhaps I will poke around in cc_ascend, or something, and see what others do.

In any case, I am sure that a character who is not chat literate will be unable to interact with a faxbot at all.

It would have been nice if VMF "suggested" a fax monster but I understand why there isn't a default. Knob Goblin Embezzler or is there something better?
Knob Goblin Embezzler is a good choice. Two of my characters with Fax access do that. The third does a Black Crayon Penguin (with a Robortender) in order to collect fish heads - an ingredient for the drive-by shooting, which doubles the Meat Drop of the Robortender. That's a free fight and the fish head is worth more than what the Embezzler drops

Given its role as a "don't forget" script I can imagine a FR for it to pick a fax monster based upon lack of Manuel information but I can also see that being a whole lot of work for you compared to me just making sure I do that before I run VMF and knowing the fax opportunity wasn't wasted if I forget.
I could see somebody (not me) writing a script to pick a Fax Monster based on needed Manuel factoids. I say "not me" because only my main has Manuel, and I have all factoids.

I might make the Knob Goblin Embezzler the default Fax Monster. If you have a VIP key and access to a fax machine, that's a perfectly reasonable way to spend a turn.
 
Thank you. I will confirm illiterate inability to interact with faxbot.

Code:
faxtoid	checkmanuel; ash monster fax_mon() { foreach mm in $monsters[] if (can_faxbot(mm) && monster_factoids_available(mm,true)<3) return mm; return $monster[none];} faxbot(fax_mon());

Above is the alias I use. I decided maybe VMF integration might not be a good thing if there were copies made of the fax. Someone might only need one factoid and have a better idea for how to use the copies.

I can either run the alias manually or have it select a target and update VMF.FaxMonster.

Or for all external scripts for which you have the prereqs (IOTM), if you have not installed (and configured) them, give a warning (suggestion) to install and configure the script.

I prefer that option, at least until there is a relay script that allows the setting of VMF parameters.
 
Back
Top