Veracity's Gingerbread City.ash

Veracity

Developer
Staff member
Here is my script to automate the Gingerbread City. It is fully configurable as documented by the following from the code:

Code:
// ****** Configuration ******

// If you want to advance the clock and spend 5 fewer turns in The
// Gingerbread City, you can do that.

boolean vgc_advance_clock = define_property( "VGC.AdvanceClock", "boolean", "false" ).to_boolean();

// The following are valid adventuring locations in the Gingerbread
// City. Specifying any other location results in an invalid plan
//
// Gingerbread Civic Center
// Gingerbread Industrial Zone
// Gingerbread Upscale Retail District
// Gingerbread Sewers
// Gingerbread Train Station
//
// If any of the following are "none", adventuring ceases in Gingerbread City at that phase

location vgc_morning = define_property( "VGC.Morning", "location", "none" ).to_location();
location vgc_afternoon = define_property( "VGC.Afternoon", "location", "none" ).to_location();
location vgc_night = define_property( "VGC.Night", "location", "none" ).to_location();

// You have a wide variety of options for Noon:
//
// "candy"				collect candy in Train Station 
// "lever"				enlarge alligators in sewers
// "schedule"				study the train schedule
// "fancy marzipan briefcase"		off-hand item that decreases combat frequency and lasts until rollover
// "column"				allows a fight with Judge Fudge at midnight
// "briefcase full of sprinkles"	turn in blackmail photos
// "creme brulee torch"			buy for 25 sprinkles; opens civic center midnight choice
// "candy crowbar"			buy for 50 sprinkles; opens unsupported train station midnight choice
// "candy screwdriver"			buy for 100 sprinkles; opens train station midnight choice
// "teethpick"				buy for 1000 sprinkles; opens train station midnight choice
// "robbery"				requires robbery outfit; activates vigilantes
// "gingerbread dog treat"		buy for 200 sprinkles; opens civic center midnight choice
// "pumpkin spice candle"		buy for 140 sprinkles; opens train station midnight choice
// "gingerbread spice latte"		buy for 50 sprinkles; +10 Familiar Weight potion
// "gingerbread trousers"		buy for 500 sprinkles; part of Gingerbread Best outfit
// "gingerbread waistcoat"		buy for 500 sprinkles; part of Gingerbread Best outfit
// "gingerbread tophat"			buy for 500 sprinkles; part of Gingerbread Best outfit
//
// An invalid choice will be treated as "candy"

string vgc_noon = define_property( "VGC.Noon", "string", "candy" );

// You have a wide variety of options for Midnight:
//
// "mainstat"				gain muscle, mysticality, or moxie, depending on your class
// "Judge Fudge"			fight Judge Fudge: activated by "column" at noon
// "Muscle"				gain muscle stats; eventually activates a train station midnight choice
// "Mysticality"			gain mysticality stats; eventually allows purchase of teethpick
// "Moxie"				gain moxie stats
// "broken chocolate pocketwatch"	part of Gingerbread Best outfit; requires "pumpkin spice candle" at noon
// "meat"				5,000 Meat; requires "candy crowbar" at noon
// "fat loot token"			requires "candy crowbar" at noon
// "sprinkles"				250 sprinkles; requires "candy crowbar" at noon
// "priceless diamond"			requires "candy crowbar" at noon
// "pristine fish scales"		5 pristine fish scales; requires "candy crowbar" at noon
// "dig"				gain items; requires teethpick in inventory; becomes unavailable after sugar raygun
// "counterfeit city"			buy for 300 sprinkles
// "gingerbread moneybag"		requires creme brulee torch in inventory
// "gingerbread cigarettes"		buy for 5 sprinkles
// "chocolate puppy"			requires gingerbread dog treat in inventory
// "gingerbread pistol"			buy for 300 sprinkles
// "ginger beer"			requires gingerbread mug in inventory
// "spare chocolate parts"		required to convert broken chocolate pocketwatch to chocolate pocketwatch
// "GNG-3-R"				fight GNG-3-R; requires (and consumes) gingerservo
// "tattoo"				buy for 100,000 sprinkles
// "fake cocktail"			potion: MP +50, MP Regen 20-30
// "high-end ginger wine"		requires Gingerbread Best outfit; EPIC booze
// "fancy chocolate sculpture"		buy for 300 sprinkles; chocolate
// "Pop Art: a Guide"			buy for 1,000 sprinkles; grants skill: Fifteen Minutes of Flame
// "No Hats as Art"			buy for 1,000 sprinkles; grants skill: Ceci N'Est Pas Un Chapeau
//
// An invalid choice will be treated as "mainstat"

string vgc_midnight = define_property( "VGC.Midnight", "string", "mainstat" );

// You can specify monsters to banish if you are looking for particular drops

boolean [monster] vgc_banish = define_property( "VGC.Banishes", "monster", "none" ).to_set_of_monster();

// The preconfigured outfit to wear while adventuring in The Gingerbread City

string vgc_outfit = define_property( "VGC.Outfit", "string", "Gingerbread City" );

// The familiar to take adventuring in The Gingerbread City

familiar vgc_familiar = define_property( "VGC.Familiar", "familiar", "Chocolate Lab" ).to_familiar();
Note that it assumes by default that you have a Chocolate Lab. If you don't have one, you must set VGC.Familiar to the familiar you want to use and equip it with the familiar item you want it to wear (unless you have a candy dog collar, which it will use in its place, since that gives +Sprinkle Drop).

Here is the current To Do list:

Code:
// ****** To Do **************
//
// Test setting clock ahead
// Implement VGC.Banishes
// Use tracking settings, as appropriate
//	gingerDigCount
//	gingerLawChoice
//	gingerMuscleChoice
//	gingerNegativesDropped
//	gingerSubwayLineUnlocked
// Configure remaining Noon options:
//      "bribery" : new GingerChoice( GINGERBREAD_CIVIC_CENTER, 1000, $item[ none ], 1202, 3 ),
//           Leads to another choice to buy a city upgrade
//      "photo counter" : new GingerChoice( GINGERBREAD_RETAIL_DISTRICT, 500, $item[ none ], 1208, 8 ),
//           Drop off negatives (one day) pick up photos (next day)
// Configure remaining Midnight options:
//      "fruit leather negatives" : new GingerChoice( GINGERBREAD_TRAIN_STATION, 0, $item[ none ], 1205, 4 ),
//           Once only, must be unlocked
// Make Mood configurable
I'll get to these, by and by. The "banish" list - which will use Licorice Leash, if possible - comes first. I expect I will eventually also use Gingerbread Mob Hit, but that will depend on me being able to get the skill book for a price I am willing to pay. Which, using Spelunky's model, will probably be a year from now.

Code:
svn checkout https://svn.code.sf.net/p/veracity0/code/gingerbread
 

Veracity

Developer
Staff member
Here is JSON to add it to the Script Registry:

Code:
{
  "repo": "https://svn.code.sf.net/p/veracity0/code/gingerbread/", 
  "author": "Veracity", 
  "name": "Veracity's Gingerbread City Script", 
  "forumThread": "http://kolmafia.us/showthread.php?21609", 
  "shortDesc": "Automate the Gingerbread City", 
  "category": "adventure", 
  "longDesc": "Highly configurable script to allow automation of turns in the Gingerbread City, specifying the morning, afternoon, and night adventuring locations and the noon and midnight non-combats."
 }
I am amused that I couldn't include that in the initial announcement since I could not give a link to the forum thread until I'd actually created the thread.

And, I could swear I saw somebody asking how to tell how many turns you spent in the Gingerbread City today - and I could certainly use something like that to determine whether it makes sense to run this script today. I may have to resort to an _ setting so you can only run it once...
 

Veracity

Developer
Staff member
Here is configureVGC.ash. It's a little utility for configuring a variety of gingerbread plans by name.
These may or may not be what you want. Heck, they may or may not be what _I_ want.
I'm thinking of including it in the Veracity's Gingerbread City script package.
If so, everybody can edit it to their taste.

Code:
import <Gingerbread City.ash>;

void main( string plan )
{
    void print()
    {
	print( "" );
    }

    void usage()
    {
	print( "Available plans:" );
	print();
	print( "alligators - bigger alligators, adventure in sewer" );
	print( "gingerbeard - adventure in retail district, banish tech bros" );
	print( "gingerservo - adventure in industrial zone, banish mutants" );
	print( "robbery - activate vigilantes" );
    }

    void log_property( string name )
    {
	print( name + "=" + get_property( name ) );
    }

    void log_set_property( string name, string value )
    {
	set_property( name, value );
	log_property( name );
    }

    switch ( plan ) {
    case "alligators":
	log_set_property( "VGC.AdvanceClock", "false" );
	log_set_property( "VGC.Morning", "Gingerbread Upscale Retail District" );
	log_set_property( "VGC.Noon", "lever" );
	log_set_property( "VGC.Afternoon", "Gingerbread Sewers" );
	log_set_property( "VGC.Midnight", "high-end ginger wine" );
	log_set_property( "VGC.Night", "Gingerbread Sewers" );
	log_set_property( "VGC.Banishes", "" );
	break;
    case "gingerbeard":
	log_set_property( "VGC.AdvanceClock", "false" );
	log_set_property( "VGC.Morning", "Gingerbread Upscale Retail District" );
	log_set_property( "VGC.Noon", "column" );
	log_set_property( "VGC.Afternoon", "Gingerbread Upscale Retail District" );
	log_set_property( "VGC.Midnight", "Judge Fudge" );
	log_set_property( "VGC.Night", "Gingerbread Upscale Retail District" );
	log_set_property( "VGC.Banishes", "gingerbread tech bro" );
	break;
    case "gingerservo":
	log_set_property( "VGC.AdvanceClock", "false" );
	log_set_property( "VGC.Morning", "Gingerbread Industrial District" );
	log_set_property( "VGC.Noon", "column" );
	log_set_property( "VGC.Afternoon", "Gingerbread Industrial District" );
	log_set_property( "VGC.Midnight", "Judge Fudge" );
	log_set_property( "VGC.Night", "Gingerbread Industrial District" );
	log_set_property( "VGC.Banishes", "gingerbread mutant" );
	break;
    case "robbery":
	log_set_property( "VGC.AdvanceClock", "false" );
	log_set_property( "VGC.Morning", "Gingerbread Upscale Retail District" );
	log_set_property( "VGC.Noon", "robbery" );
	log_set_property( "VGC.Afternoon", "Gingerbread Upscale Retail District" );
	log_set_property( "VGC.Midnight", "high-end ginger wine" );
	log_set_property( "VGC.Night", "Gingerbread Upscale Retail District" );
	log_set_property( "VGC.Banishes", "" );
	break;
    default:
	usage();
	print();
	log_property( "VGC.AdvanceClock" );
	log_property( "VGC.Morning" );
	log_property( "VGC.Noon" );
	log_property( "VGC.Afternoon" );
	log_property( "VGC.Midnight" );
	log_property( "VGC.Night" );
	log_property( "VGC.Banishes" );
	break;
    }

    log_set_property( "VGC.Outfit", "Gingerbread City" );
    log_set_property( "VGC.Familiar", "Chocolate Lab" );

    print();
    print( "Validating current plan:" );
    print();

    validate_gingerbread_plan();
}
These are plans for use after you have done all the one-time things. Obviously, you'd want sequences of plans that change each day, while you are still unlocking things.

If you have any suggested plans, I'd be interested in seeing them. I'm open to augmenting this script before publishing it as part of this package.

Edit: I updated this to always print out the current (or newly changed) value of all properties and to call the validate_gingerbread_plan() function so you can see how the script will handle them.
 
Last edited:

Veracity

Developer
Staff member
Revision 20 does this:

Provides configureVGC.ash, as above, with a few additional tweaks and fixes.
Lets you configure monsters to banish with Licorice Rope in VGC.Banishes
Lets you use "retail", "sewers", "turns" and "clock" as VGC.Noon options for buying city upgrades in the Civic Center
Looks at _gingerbreadCityTurns property to see whether you have already adventured in the Gingerbread City.
If you have, it punts, for now. Eventually, I'll make it able to continue with a plan after the already used adventures.

I haven't committed _gingerbreadCityTurns yet since it is not quite right; it says how many times we have entered the Gingerbread City, but it doesn't know that the choice options don't actually consume a turn. I may commit it and fix it tomorrow...
 

iule

New member
I think most people only care about the NC (or will once they get the tattoo), and use free run away to avoid the fights.
 

Veracity

Developer
Staff member
Who are "most people"?

Those who are selling gingerbeards for 600,000+ Meat or gingerservos for 300,000+ Meat want fights.
Those attempting to dominate the sprinkles leaderboards want fights.

In-run, I only care about candy at (time-advanced) noon.
In aftercore, I want sprinkles - until I get the Tattoo - and then probably don't want to spend turns here at all.

What NCs do "most people" want after they get the Tattoo?
 

Magus_Prime

Active member
What NCs do "most people" want after they get the Tattoo?

I have the tattoo but I'm still hunting a last vigilante factoid and, as a result, I'm spending a lot of turns in the sewers. After robbing someone at least twice in an ascension: I find myself making larger alligators at noon and a getting ginger beer at midnight.

Extra sprinkles and a decent consumable never hurt.
 
Last edited:

xKiv

Active member
I get the high-end ginger wine. (Which I should probably drink some of and post the results somewhere? I want mafia to know how many advs it gives, so it gets listed at an appropriate place in booze lists ...)
 

Veracity

Developer
Staff member
Discovery: You can get the Violet Fog in the Gingerbread City. It takes a turn but does not advance time in the city.

KoLmafia automated it and got me a munchies pill, but 8 turns later, the script prepared for Noon and got a fight, and then got a choice it was not expecting and aborted.

I'll have to figure out how to deal with that, somehow. I wonder if I counted that in _gingerbreadCityTurns? Answer: yes.

_gingerbreadCityTurns=31

I'll have to rethink how I count those, too. Probably increment only for GC monsters and GC choices.

And I'd like to figure out how to make the script continue from where it left off if I restart it after stopping it, which will depend on that count being correct.
 

ereinion

Member
If it's any help, my preliminary ginger-farming script looks like this:

Code:
int get_price(item item_to_check, float acceptable_age) {
    return ((historical_age(item_to_check) <= acceptable_age)? historical_price(item_to_check) : mall_price(item_to_check));
}

void ginger_outfit() {
    item it;
    familiar fam = $familiar[Chocolate Lab];
    buffer maximizer_string;
    slot[item] ginger_drop_items;
    
    ginger_drop_items[$item[sour ball and chain]]    =    $slot[acc1];
    ginger_drop_items[$item[candy dog collar]]        =    $slot[familiar];
    ginger_drop_items[$item[sprinkle-begging cup]]    =    $slot[off-hand];
    ginger_drop_items[$item[gingerbread hoodie]]    =    $slot[shirt];
    
    maximizer_string.append("sprinkle drops, 0.1 familiar weight, 0.01 mp regen, -tie");
    
    if (!have_familiar(fam)) {
        it = fam.hatchling;
        if (get_price(it, 0.5) <= 1000000) {
            if (buy (1, it, 1000000) > 0) {
                use (1, it);
            }
        }
    }
    use_familiar(fam);
    
    foreach it in ginger_drop_items {
        if (available_amount(it) <= 0 && is_tradeable(it)) {
            if (get_price(it, 0.5) <= 200000) {
                buy (1, it, 200000);
            }
        }
        if (can_equip(it)) {
            if (equip(ginger_drop_items[it], it)) {
                maximizer_string.append(", -" + to_string(ginger_drop_items[it]));
            }
        }
    }
    maximize(maximizer_string, false);
}

void main() {
    int i;
    
    ginger_outfit();
    
    while (to_int(get_property("_gingerbreadCityTurns")) < 19 && i < 40) {
        adv1($location[Gingerbread Upscale Retail District], -1, "");
        i = i + 1;
    }
    while (to_int(get_property("_gingerbreadCityTurns")) < 20 && i < 50) {
        adv1($location[Gingerbread Civic Center], -1, "");
        i = i + 1;
    }
    while (to_int(get_property("_gingerbreadCityTurns")) < 30 && i < 80) {
        adv1($location[Gingerbread Upscale Retail District], -1, "");
        i = i + 1;
    }
}

However, I ran into the same issue as you with turn-free adventures increasing the counter, so I abondoned the project in favor of ascending. It's all very basic, so I don't know if it's actually of any use, but I figured it wouldn't hurt to share it.
 

AlbinoRhino

Active member
I'll have to rethink how I count those, too. Probably increment only for GC monsters and GC choices.

The last I checked, free turtle drops DO advance the city counter, while free weiner dogs DO NOT advance it. I happened to be a Tamer when I was writing a counter for this (long before you added _gingerbreadCityTurns).
 
And here comes Pooter the Ignorant again. I have the Gingerbread City script installed and configured. I also have it's usage set to "true" in the Meat Farming script. I own the City and can adventure in it manually. When I run Gingerbread City in the cli, nothing happens. Nor will the Meat Farming script adventure there. There are no entries regarding it added to the ascension log. Mafia doesn't hang - the graphical CLI simply repeats my "run Gingerbread City" command. Any hints on how to debug this would be appreciated.
 

Veracity

Developer
Staff member
Look at the settings in the Gingerbread City script

Chose a place to adventure in the morning
Chose a thing to do at Noon
Chose a place to adventure in the afternoon
Choose a thing to do at Midnight
Chose a place to adventure in the night

Run the configureVGC.ash script for help.
 
Dug around in my prefs and found two typos: gingerbreadCityAvail=able\=true which gave an invalid entry in prefref Gingerbread City, and VGCNoon=candy (missing period). Quit mafia, corrected the errors, and now when I invoke the script it tells me that I've already adventured there, which I did. I'll fully test it after RO, but I'm pretty sure these typos caused the problem.
 

Veracity

Developer
Staff member
Yeah. I will, very soon, make this script able to pick up from where you left off, having previously adventured. KoLmafia has all the settings we need to detect how many turns you have spent there, so, how hard can it be to just pick up after that many turns?

Well, it's a "simple matter of coding" - but I haven't done that coding yet. Soon. :)
 

Veracity

Developer
Staff member
The last I checked, free turtle drops DO advance the city counter, while free weiner dogs DO NOT advance it. I happened to be a Tamer when I was writing a counter for this (long before you added _gingerbreadCityTurns).
For some reason, I just saw this.

I could have sworn KoL made Turtle Tamer choices not happen in the Gingerbread city. Perhaps I am hallucinating.

If what you said is true, that is completely ridiculous. I vastly prefer to become an AT rather than a TT after an Avatar run, but after I start my one and only Noob run, in a week or so, perhaps I will have to end up as a TT at the end, just so I can test this kind of thing.

#crap.
 

Veracity

Developer
Staff member
I'm planning on adding the concept of a "quest".

You set VGC.Noon and VGC.Midnight to your "preferred" value. For me, probably, "robbery" and "high-end ginger wine", respectively.

You then select a "quest". This will look at various tracking settings that KoLmafia maintains as well as the contents of your inventory to determine which day you are on - or if you are finished - and will override one of both of Noon and Midnight to advance you in the "quest".

I envision 3 possible "quests". Here are my notes on the topic:

Code:
// Allow configuration of a "quest", where the Noon and/or Midnight
// choices change from day to day and your progress can be determined
// from settings and/or inventory. Based on your progress, one or both
// choices will override your non-quest settings.
//
// "blackmail" quest (7 days):
//  1-3	(Midnight x 3) "Muscle" -> gingerMuscleChoice == 3 -> gingerSubwayLineUnlocked
//    4	(Midnight) "fruit-leather negatives" -> gain fruit-leather negatives
//    5	(Noon) "photo counter" -> lose fruit-leather negatives & gingerNegativesDropped
//    6	(Noon) "photo counter" -> gain gingerbread blackmail photos
//    7	(Noon) "briefcase full of sprinkles" -> gain briefcase full of sprinkles & lose gingerbread blackmail photos & gingerBlackmailAccomplished
//
// "raygun" quest (10 days):
//  1-3	(Midnight x 3) "Mysticality" -> gingerLawChoice == 3
//    4	(Noon) "teethpick" -> gain teethpick
// 4-10	(Midnight x 7) "dig" -> gingerDigCount == 7 -> gain sugar raygun & lose teethpick
//
// "blackmail+raygun" (14 days):
//  1-3	(Midnight x 3) "Muscle" -> gingerMuscleChoice == 3 -> gingerSubwayLineUnlocked
//    4	(Midnight) "fruit-leather negatives" -> gain fruit-leather negatives
//    5	(Noon) "photo counter" -> lose fruit-leather negatives & gingerNegativesDropped
//    5	(Midnight) "Mysticality" -> gingerLawChoice == 1
//    6	(Noon) "photo counter" -> gain gingerbread blackmail photos
//    6	(Midnight) "Mysticality" -> gingerLawChoice == 2
//    7	(Noon) "briefcase full of sprinkles" -> gain briefcase full of sprinkles & lose gingerbread blackmail photos & gingerBlackmailAccomplished
//    7	(Midnight) "Mysticality" -> gingerLawChoice == 3
//    8	(Noon) "teethpick" -> gain teethpick
// 8-14	(Midnight x 7) "dig" -> gingerDigCount == 7 -> gain sugar raygun & lose teethpick
For the single quests - blackmail and raygun - we can simply look at the appropriate settings and decide which day we are on.
For the combined quest - blackmail+raygun - we can probably do the same, but it might be a little trickier to handle the three overlapping says, if you have made some progress on the raygun quest previously, for example.

Also, we don't (currently) reset the two settings it looks at - gingerLawChoice and gingerDigCount - on ascension, as I don't think it's been confirmed that you can actually run this quest once per ascension - although it would be stupid not to be able to.

I have ascended multiple times since getting my raygun and I just manually reset those to settings to 0. I will attempt the quest and see if, in fact, the teethpick becomes available again on day 4.
 
Top