Bug - Fixed r17270 - "auto" button during NC takes you to the Monster Manuel

Bale

Minion
I've got a long sprawling choice.ash override, but the part related to that is this:

Code:
buffer annotate(buffer page) {
	buffer c;
	matcher choices = create_matcher("<input type=hidden name=pwd value='[^']+'><input type=hidden name=whichchoice value=(\\d+)><input type=hidden name=option value=(\\d+)>", page);
	while(choices.find())
		choices.append_replacement(c, choices.group(2)+": "+choices.group(0));
	choices.append_tail(c);
	
	// Add choiceAdventure number to title
	matcher title = create_matcher('<input type=hidden name=whichchoice value=(\\d+)>.+(</form><p></center></td></tr>)</table></center>', c);
	if(title.find())
		return c.replace_string(title.group(2), title.group(2)+"<tr><td><span style='float:right;color:blue;font-weight:bold'>choiceAdventure"+title.group(1)+"</span></td></tr>");
	
	return c;
}

Obviously you'd know how to call that, but for completeness I'd just say that void main() {visit_url().annotate().write();} would do the job.

Huh. It just hit me that the replace_string() in the above code is a lousy way to do that. I should use c.insert(end(title, 2), "...")
 
Last edited:

Veracity

Developer
Staff member
From Bale's "HTML after clicking the "auto" button" log:

Code:
-----From Browser-----
GET /choice.php?action=auto HTTP/1.1
Host: 127.0.0.1:60080
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.52 (Edition beta)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: http://127.0.0.1:60080/choice.php?forceoption=0
Accept-Encoding: gzip, deflate, lzma, sdch
Accept-Language: en-US,en;q=0.8
Cookie: charpwd=200; AWSALB=JF3lW1Ihy5gimK+YNGgIheYy7mx1FMaWBI2orcZsOGzmKqL/v6HJonmWIZPxQXeOrrr5BpDR4YdlYzZOZi769ayzF+tb9JjxBX13d569yMH/5xrqg6FPZeAevTE3
----------
-----To Browser-----
HTTP/1.1 200 OK
Server: nginx/1.8.1
Vary: Accept-Encoding
Set-Cookie: AWSALB=MPM9iq05V64HjKnRJ3ljKeRYEce6G7q9NSY+QCMPOEB6bfMhVcG2SAfFtzpVO1j7WQAu9ihIWAvNbmtM98nsAVROvfeoVaMpWHid9vAFoar7LKECLultb+U7jphu; Expires=Wed, 19 Oct 2016 00:56:44 GMT; Path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Date: Wed, 12 Oct 2016 00:56:44 GMT
X-Powered-By: PHP/5.3.29
Content-Type: text/html; charset=UTF-8
Content-Length: 75386
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
----------
Near as I can tell, this log has nothing but the browser request/response. In particular, it completely omits the actual request to KoL. From what you said, that must be a request to go to the "G" page.

I deduce that the page that generated the choice page you are looking at was "choice.php?forceoption=0" (from the Referer header of the browser request.

Have to look at how we handle "choice.php?action=auto".
 

heeheehee

Developer
Staff member
webui/RelayAgent.java:
Code:
		else if ( this.path.equals( "/choice.php?action=auto" ) )
		{
			ChoiceManager.processChoiceAdventure( this.request, "choice.php", ChoiceManager.lastResponseText );
			if ( StaticEntity.userAborted || KoLmafia.refusesContinue() )
			{
				// Resubmit the choice request to let the user see it again
				KoLmafia.forceContinue();
				request.constructURLString( "choice.php?forceoption=0" );
				RequestThread.postRequest( this.request );
				RelayAgent.errorRequest = null;
			}
		}

Manuel is questlog.php, not choice.php, so presumably that means we can restrict our search to ChoiceManager.processChoiceAdventure(req, url, responseText). If this is indeed the root cause, then the likeliest culprit is that one of the ChoiceManager choice handling methods mutates the request object's URL.
 

Veracity

Developer
Staff member
I think we can restrict our search to choice.php relay overrides.

I looked at how we handle choice.php?action=auto and I can't see how it can possibly submit anything except calls to choice.php.

However, recall my observation that Bale's log had everything except Browser requests/responses stripped out? The DEBUG log certainly had actual KoL requests/responses in it - as well as logging of relay scripts - but we didn't see it.

I suspect that many of you do not know about the TRACE log? Just as you can say "debug on" and "debug off", you can say "debug trace on" and "debug trace off" and get a much more succinct log file.

Revision 17290 soups it up a bit: like the DEBUG log, it will log start/stop of relay scripts. Also, for yucks, I added a traceprint( string) function which prints to the trace file, if it is open.

Ignoring the helper functions, this is my choice.ash relay script:

Code:
void main()
{
        traceprint( "path = " + get_path_full() );
	buffer page = visit_url();

	if ( page.contains_text( 'bgcolor=blue><b>Pick a Card</b>' ) )
	{
	    deck_draws( page );
	    return;
	}

	if ( page.contains_text( 'bgcolor=blue><b>Play against the Witchess Pieces</b>' ) )
	{
	    witchess_fights( page );
	    return;
	}

	page.write();
	return;
}
Not especially interesting, but sort of a proof of concept.

I then did a "debug trace on" and went to the Relay Browser.

I visited Spookyraven Manor - with Bale's relay script in place:

Code:
1476800627049: From Browser: GET /place.php?whichplace=town_right HTTP/1.1
1476800627101: Starting relay script: place.town_right.ash
1476800627102: Finished relay script: place.town_right.ash
1476800627103: Requesting: https://www.kingdomofloathing.com/place.php?whichplace=town_right
1476800627246: Retrieved: https://www.kingdomofloathing.com/place.php?whichplace=town_right
1476800627249: To Browser: HTTP/1.1 200 OK: /place.php?whichplace=town_right
1476800627288: From Browser: GET /basics.js HTTP/1.1
1476800627289: To Browser: HTTP/1.1 200 OK: /basics.js
1476800628709: From Browser: GET /place.php?whichplace=manor1 HTTP/1.1
1476800628758: Starting relay script: place.manor1.ash
1476800628760: Requesting: https://www.kingdomofloathing.com/place.php?whichplace=manor1
1476800628825: Retrieved: https://www.kingdomofloathing.com/place.php?whichplace=manor1
1476800628830: Finished relay script: place.manor1.ash
1476800628831: To Browser: HTTP/1.1 200 OK: /place.php?whichplace=manor1
1476800628879: From Browser: GET /basics.js HTTP/1.1
1476800628880: To Browser: HTTP/1.1 200 OK: /basics.js
Notice that the relay script requested "place.php?whichplace=manor1" and decorated it, exactly as expected.

Now, what happens when you hit the "auto" button? Does a relay override get a chance to run?

Here is the Hidden Office Building:

Code:
1476800837181: From Browser: GET /adventure.php?snarfblat=343 HTTP/1.1
1476800837194: Requesting: https://www.kingdomofloathing.com/adventure.php?snarfblat=343
1476800837331: Retrieved: https://www.kingdomofloathing.com/adventure.php?snarfblat=343
1476800837331: To Browser: HTTP/1.1 302 Found: /adventure.php?snarfblat=343
1476800837337: From Browser: GET /choice.php?forceoption=0 HTTP/1.1
1476800837391: Starting relay script: choice.ash
1476800837393: trace: path = choice.php?forceoption=0
1476800837393: Requesting: https://www.kingdomofloathing.com/choice.php?forceoption=0
1476800837440: Retrieved: https://www.kingdomofloathing.com/choice.php?forceoption=0
1476800837462: Finished relay script: choice.ash
1476800837463: To Browser: HTTP/1.1 200 OK: /choice.php?forceoption=0
I adventured, got redirected to the choice, my choice.ash script executed - and did its traceprint - and left me looking at the choice page, as expected.

Observation: the "To Browser" logs the "status line" and the path of the request that generated it. That looks confusing for the "302 found", since it is not actually redirecting TO that path; the redirect location will be in the "Location" header. Perhaps that message could be improved to look something like "To Browser: HTTP/1.1 302 Found: /adventure.php?snarfblat=343 -> choice.php?forceoption=0"

I hit the "auto" button.

Code:
1476800840874: From Browser: GET /choice.php?action=auto HTTP/1.1
1476800840894: Starting relay script: choice.ash
1476800840895: trace: path = choice.php
1476800840896: Requesting: https://www.kingdomofloathing.com/choice.php?whichchoice=786&option=6&pwd
1476800840950: Retrieved: https://www.kingdomofloathing.com/choice.php?whichchoice=786&option=6&pwd
1476800840953: Finished relay script: choice.ash
1476800840953: To Browser: HTTP/1.1 200 OK: /choice.php?action=auto
Look at that! My choice.ash script was given control. All it really did was:

traceprint
page = visit_url()
page.write( page )

I'm not exactly sure how visit_url() for "choice.php?action=auto" turned into taking the default - "choice.php?whichchoice=786&option=6&pwd" - but that was exactly right.

But you know - it didn't HAVE to do that. It could have chosen to go to Monster Manuel instead.

I suggest that people who are having this problem do the following:

- update to revision 17290
- run with "debug trace on" - which is WAY smaller than a simple "debug on"
- When/if the "auto" button gives you Manuel, look in the TRACE file and find everything between "From Browser: GET /choice.php?action=auto HTTP/1.1" and "To Browser: HTTP/1.1 200 OK: /choice.php?action=auto"
- Show it here

Thanks.
 
r17290: traceprint replaced print (without the color parameter), this is breaking scripts that don't print with beautiful colors.

Code:
> ash print("apples");

Internal error: no method for print ()
Returned: void

> ash print("apples", "red");

apples
Returned: void
 
Last edited:

Veracity

Developer
Staff member
Revision 17291 restores the erroneously removed print() variant and also logs redirects more clearly in the TRACE file.
 

Magus_Prime

Well-known member
Got one. This time it was a Spookyraven NC and, the first time I selected "auto" the browser went to the "H" page of the Monster Manuel. Here's the section of the log:

Code:
1476870457358: From Browser: GET /choice.php?action=auto HTTP/1.1
1476870457359: Starting relay script: choice.ash
1476870457361: Requesting: https://www.kingdomofloathing.com/choice.php?whichchoice=900&option=1&pwd
1476870457481: Retrieved: https://www.kingdomofloathing.com/choice.php?whichchoice=900&option=1&pwd
1476870457485: Finished relay script: choice.ash
1476870457485: Starting relay script: choice.ash
1476870457486: Requesting: https://www.kingdomofloathing.com/choice.php?whichchoice=900&option=2&pwd
1476870457552: Retrieved: https://www.kingdomofloathing.com/choice.php?whichchoice=900&option=2&pwd
1476870457554: Finished relay script: choice.ash
1476870457555: Starting relay script: choice.ash
1476870457555: Requesting: https://www.kingdomofloathing.com/choice.php?whichchoice=900&option=2&pwd
1476870457772: Retrieved: https://www.kingdomofloathing.com/choice.php?whichchoice=900&option=2&pwd
1476870457798: Starting ASH script: after-adventure.ash
1476870457828: Finished ASH script: after-adventure.ash
1476870457828: Finished relay script: choice.ash
1476870457831: To Browser: HTTP/1.1 200 OK: /choice.php?action=auto

And here is Bale's choice.ash:

Code:
# Writen by Bale
# import "choice.rainman.ash";
# import "place.town_right.ash";

// Step 0 is started. Unstarted and finished are trivial to check.
boolean below_step(string pref, int step) {
	pref = get_property(pref);
	if(pref == "unstarted") return true;
	if(pref == "started") return step > 0;
	if(pref == "finished") return false;
	return pref.substring(4).to_int() < step;
}

// Am I guitarless?
boolean need_guitarrr() {
	foreach it in $items[acoustic guitarrr, stone banjo, massive sitar, dueling banjo, dueling turtle, 4-dimensional guitar, heavy metal thunderrr guitarrr]
		if(available_amount(it) > 0) return false;
	return true;
}

// Check for Dungeons of Doom
boolean need_bangs() {
	int gate_potions, missing_potions;
	boolean inebriety, teleportitis, need_extra;
	for i from 819 to 827 {
		switch(get_property("lastBangPotion"+i)) {
		# case "healing": case "sleepiness": case "confusion": break;
		case "inebriety": inebriety = true; break;
		case "teleportitis": teleportitis = true;
		case "blessing": case "detection": case "mental acuity": case "ettin strength":
			if(available_amount(to_item(i)) == 0)
				missing_potions = missing_potions + 1;
			else gate_potions = gate_potions + 1;
			break;
		case "":
			if(available_amount(to_item(i)) == 0)
				missing_potions = missing_potions + 1;
			if(available_amount(to_item(i)) < 2)
				need_extra = true;
			break;
		}
		if(gate_potions == 5) return false;
	}
	if(teleportitis && inebriety && missing_potions == 0) return false;
	if(need_extra) return true;
	return false;
}

boolean [monster] best_monsters() {
	boolean [monster] mon;
	
	if(have_skill($skill[Summon Smithsness]) && available_amount($item[dirty hobo gloves]) + available_amount($item[Hand in Glove]) == 0)
		mon[ my_ascensions() % 2 == 0? $monster[drunken half-orc hobo]: $monster[hung-over half-orc hobo] ] = true;
	if(available_amount($item[Lady Spookyraven's necklace]) == 0 && get_property("questM20Necklace") != "finished")
		mon[ $monster[writing desk] ] = true;
	if(available_amount($item[killing jar]) == 0 && get_property("questL11Desert") != "finished" && (get_property("gnasirProgress").to_int() & 4) == 0)
		mon[ $monster[banshee librarian] ] = true;
	if(available_amount($item[disposable instant camera]) == 0 && available_amount($item[Lord Spookyraven's spectacles]) == 0)
		mon[ $monster[animated ornate nightstand] ] = true;
	if("questL04Bat".below_step(3))
		mon[ $monster[screambat] ] = true;
	if("questL08Trapper".below_step(3)) {
		if(available_amount($item[ninja rope]) + available_amount($item[ninja crampons]) + available_amount($item[ninja carabiner]) < 3)
			mon[ $monster[ninja snowman assassin] ] = true;
		if(!have_outfit("Mining Gear") && "questL08Trapper".below_step(2)) {
			mon[ $monster[7-Foot Dwarf Foreman] ] = true;
			mon[ $monster[mountain man] ] = true;
		}
	}
	if(get_property("questL07Cyrptic") != "finished") {
		if(get_property("cyrptAlcoveEvilness").to_int() > 25)
			mon[ $monster[modern zmobie] ] = true;
		if(get_property("cyrptCrannyEvilness").to_int() > 25)
			mon[ $monster[swarm of ghuol whelps] ] = true;
	}
	if("questL11Desert".below_step(4) && available_amount($item[drum machine]) == 0)
		mon[ $monster[Blur] ] = true;
	if(available_amount($item[stone wool]) < (get_property("lastTempleUnlock").to_int() == my_ascensions()? 1: 3))
		mon[ $monster[Baa'baa'bu'ran] ] = true;
	if(available_amount($item[Talisman o' Namsilat]) == 0)
		mon[ $monster[gaudy pirate] ] = true;
	if("questL11Palindome".below_step(4) && available_amount($item[wet stunt nut stew]) == 0) {
		if(available_amount($item[wet stew]) == 0) {
			if(available_amount($item[lion oil]) == 0)
				mon[ $monster[whitesnake] ] = true;
			if(available_amount($item[bird rib]) == 0)
				mon[ $monster[white lion] ] = true;
		}
		if(available_amount($item[stunt nuts]) == 0)
		mon[ $monster[Bob Racecar] ] = true;
	}
	if(get_property("questL11Worship") != "finished" && available_amount($item[stone triangle]) == 0
	  && available_amount($item[antique machete]) + available_amount($item[muculent machete]) == 0)
		mon[ $monster[forest spirit] ] = true;
	if(get_property("hiddenTavernUnlock").to_int() < my_ascensions())
		mon[ $monster[pygmy janitor] ] = true;
	if("questL12War".below_step(1)) {
		if(!have_outfit("War Hippy Fatigues")) {
			mon[ $monster[Bailey's Beetle] ] = true;
			mon[ $monster[War Hippy Spy] ] = true;
		}
		if(!have_outfit("Frat Warrior Fatigues"))
			mon[ $monster[Orcish Frat Boy Spy] ] = true;
	}
	if(available_amount($item[barrel of gunpowder]) < 5 && get_property("sidequestLighthouseCompleted") == "none")
		mon[ $monster[lobsterfrogman] ] = true;
	if(get_property("sidequestNunsCompleted") == "none")
		mon[ $monster[dirty thieving brigand] ] = true;
	if(available_amount($item[digital key]) == 0) {
		mon[ $monster[Blooper] ] = true;
		mon[ $monster[ghost] ] = true;
		mon[ $monster[morbid skull] ] = true;
	}
	if(available_amount($item[star hat]) == 0 && available_amount($item[Richard's star key]) == 0 && available_amount($item[star sword]) + available_amount($item[star crossbow]) + available_amount($item[star staff]) == 0) {
		mon[ $monster[Astronomer] ] = true;
		mon[ my_ascensions() % 2 == 0? $monster[Skinflute]: $monster[Camel's Toe] ] = true;
	}
	if(need_guitarrr())
		mon[ $monster[grungy pirate] ] = true;
	if(available_amount($item[Bram's choker]) == 0)
		mon[ $monster[Bram the Stoker] ] = true;
	if((my_primestat() == $stat[moxie] || have_familiar($familiar[Mad Hatrack]))&& available_amount($item[spangly sombrero]) == 0
	  || (have_familiar($familiar[Fancypants Scarecrow]) && available_amount($item[spangly mariachi pants]) == 0))
		mon[ $monster[sleepy mariachi] ] = true;
	if(my_primestat() == $stat[mysticality] && available_amount($item[antique hand mirror]) == 0)
		mon[ $monster[remains of a jilted mistress] ] = true;
	if(get_property("lastDispensaryOpen").to_int() < my_ascensions() && !have_outfit("Knob Goblin Elite Guard Uniform"))
		mon[ $monster[Knob Goblin Elite Guard Captain] ] = true;
	if(need_bangs()) {
		mon[ $monster[Quantum Mechanic] ] = true;
		mon[ $monster[mind flayer] ] = true;
	}
	if(my_path() == "Heavy Rains") { // I might re-use this code for unknown future content
		mon[ $monster[alley catfish] ] = true;
		mon[ $monster[piranhadon] ] = true;
	}

	return mon;
}

buffer rainy_fax(buffer page) {
	string [string] mon;
	boolean [monster] best_monsters = best_monsters();
	matcher select = create_matcher('<option value=(\\d+)>([^<]+)</option>', page);
	while(select.find())
		if(best_monsters contains select.group(2).to_monster())
			mon[ select.group(2) ] = select.group(0);
	
	// Gremlins are trickier because they can appear on the list TWICE so I need to ID them by number
	// <option value=547>erudite gremlin</option>  <option value=549>batwinged gremlin</option>  <option value=551>vegetable gremlin</option>  <option value=553>spider gremlin</option>
	if(available_amount($item[molybdenum magnet]) > 0)
		foreach gremlin in $strings[547, 549, 551, 553] {
			select = create_matcher('<option value='+gremlin+'>([^<]+)</option>', page);
			if(select.find())
				mon[ select.group(1) ] = select.group(0);
		}
	
	if(count(mon) > 0) {
		page.replace_string(">Make: <", ">Make (full list):<");
		buffer filter;
		filter.append("<form action=choice.php method=post><input type=hidden name=pwd value=");
		filter.append(my_hash());
		filter.append("><input type=hidden name=whichchoice value=970>Make (useful monsters): <select name=whichmonster>");
		foreach m,o in mon
			filter.append(o);
		filter.append("</select><input type=hidden name=option value=1><input type=submit class=button name=choice2 value='and Fight!'></form>");
		return page.insert(index_of(page, '</form><form ')+ 7, filter);
	}
	return page;
}

buffer annotate(buffer page) {
	buffer c;
	matcher choices = create_matcher("<input type=hidden name=pwd value='[^']+'><input type=hidden name=whichchoice value=(\\d+)><input type=hidden name=option value=(\\d+)>", page);
	while(choices.find())
		choices.append_replacement(c, choices.group(2)+": "+choices.group(0));
	choices.append_tail(c);
	
	// Add choiceAdventure number to title
	matcher title = create_matcher('<input type=hidden name=whichchoice value=(\\d+)>.+(</form><p></center></td></tr>)</table></center>', c);
	if(title.find())
		return c.replace_string(title.group(2), title.group(2)+"<tr><td><span style='float:right;color:blue;font-weight:bold'>choiceAdventure"+title.group(1)+"</span></td></tr>");
	
	return c;
}

buffer crimbot_factory(buffer page) {

	// View entire image
	int i = index_of(page, "z-index: 1;");
	if(i > 0)
		page = page.insert(index_of(page, "z-index: 1;"), "opacity: 0.5; ");
		
	// Stabilize the image
	# page = page.replace_string("drifty.animate({top: top, left: left}, 2000, 'swing', moveDrifty);", "");
	
	return page;
}

buffer pick_card(buffer page) {

	void addText( string initialText, string addedText ) {
		int index = index_of( page, initialText );
		if ( index == -1 ) return;
		index += length( initialText );
		insert( page, index, " - " + addedText );
	}


	if( !page.contains_text( 'bgcolor=blue><b>Pick a Card</b>' ) )
		return page;
	
	addText( "X of Clubs", "PvP Fights" );
	addText( "X of Diamonds", "cubic zirconia" );
	addText( "X of Hearts", "bubblegum hearts" );
	addText( "X of Spades", "shovels, spading string" );
	addText( "X of Papayas", "papayas" );
	addText( "X of Kumquats", "kumquats" );
	addText( "X of Salads", "delicious salad" );
	addText( "X of Cups", "random booze" );
	addText( "X of Coins", "valuable coins" );
	addText( "X of Swords", "random swords" );
	addText( "X of Wands", "random buffs" );
	addText( "0 - The Fool", "20 turns of +200% moxie" );
	addText( "I - The Magician", "20 turns of +200% myst" );
	addText( "II - The High Priestess", "fight a hippy" );
	addText( "III - The Empress", "500 myst substats" );
	addText( "IV - The Emperor", "fight The Emperor" );
	addText( "V - The Hierophant", "fight a dude" );
	addText( "VI - The Lovers", "500 moxie substats" );
	addText( "VII - The Chariot", "fight a construct" );
	addText( "IX - The Hermit", "fight The Hermit" );
	addText( "X - The Wheel of Fortune", "20 turns of +100% item" );
	addText( "XI - Strength", "20 turns of +200% muscle" );
	addText( "XII - The Hanged Man", "fight an orc" );
	addText( "XIII - Death", "fight an undead" );
	addText( "XIV - Temperance", "fight a hobo" );
	addText( "XV - The Devil", "fight a demon" );
	addText( "XVI - The Tower", "tower key" );
	addText( "XVII - The Star", "fight a constellation" );
	addText( "XVIII - The Moon", "fight a horror" );
	addText( "XXI - The World", "500 muscle substats" );
	addText( "Plains", "white mana" );
	addText( "Swamp", "black mana" );
	addText( "Mountain", "red mana" );
	addText( "Forest", "green mana" );
	addText( "Island", "blue mana" );
	addText( "Healing Salve", "get skill" );
	addText( "Dark Ritual", "get skill" );
	addText( "Lightning Bolt", "get skill" );
	addText( "Giant Growth", "get skill" );
	addText( "Ancestral Recall", "get skill" );
	addText( "The Hive", "fight a bug" );
	addText( "Goblin Sapper", "fight a goblin" );
	addText( "Fire Elemental", "fight an elemental" );
	addText( "Unstable Portal", "fight a weird" );
	addText( "Lead Pipe", "1h club, +50 HP, +100% mus" );
	addText( "Rope", "1h whip, +2 mus stats, 10 fam wt" );
	addText( "Wrench", "1h utensil, +50 MP, 100% spell damage" );
	addText( "Candlestick", "1h wand, 2 myst stats, +100% myst" );
	addText( "Knife", "1h knife, +50% meat, +100% moxie" );
	addText( "Revolver", "1h pistol, +2 moxie stats, +50% init" );
	addText( "Professor Plum", "plums" );
	addText( "Spare Tire", "tires" );
	addText( "Extra Tank", "full meat tank" );
	addText( "Sheep", "3 stone wool" );
	addText( "Year of Plenty", "5 random food" );
	addText( "Mine", "1 of each ore" );
	addText( "Laboratory", "5 random potions" );
	addText( "Werewolf", "fight a beast" );
	addText( "Go Fish", "fight a fish" );
	addText( "Plantable Greeting Card", "fight a plant" );
	addText( "Pirate Birthday Card", "fight a pirate" );
	addText( "Christmas Card", "fight an elf" );
	addText( "Gift Card", "get a gift card" );
	addText( "Suit Warehouse Discount Card", "fight a penguin" );
	addText( "1952 Mickey Mantle", "10k autosell" );
	addText( "Slimer Trading Card", "fight a slime" );
	addText( "Aquarius Horoscope", "fight a mer-kin" );
	addText( "Hunky Fireman Card", "fight a humanoid" );
	addText( "Green Card", "fight a legal alien" );
	addText( "The Race Card", "20 turns of +200% init" );
	
	return page;
}

buffer witchess(buffer page) {
	record reward {
		string match_text;
		item it;
		string type;
		string additional_text;
	};

	static {
		reward [8] witch_pieces;
		witch_pieces[0] = new reward("<b>Pawn</b></a>", $item[armored prawn], "Spleen", "Init +50%");
		witch_pieces[1] = new reward("<b>Knight</b></a>", $item[jumping horseradish], "Food", "Meat +100%");
		witch_pieces[2] = new reward("<b>Bishop</b></a>", $item[Sacramento wine], "Booze", "Item +50%");
		witch_pieces[3] = new reward("<b>Rook</b></a>", $item[Greek fire], "Potion", "ML +25<br>Exp +10");
		witch_pieces[4] = new reward("<b>Ox</b></a>", $item[ox-head shield], "Shield", "Max HP +100<br>DR +26<br>Prismatic Res +2<br>Rollover Fites +8<br>Never Fumble");
		witch_pieces[5] = new reward("<b>King</b></a>", $item[dented scepter], "Club", "Mus Exp +5<br>HP Regen 5-10<br>Mus +50%<br>Wpn Dmg +50%<br>Critical Hit +10%");
		witch_pieces[6] = new reward("<b>Witch</b></a>", $item[battle broom], "Accessory", "Myst Exp +5<br>MP Regen 5-10<br>Myst +50%<br>Spell Dmg +100%<br>Spell Critical +10%");
		witch_pieces[7] = new reward("<b>Queen</b></a>", $item[very pointy crown], "Hat", "Mox Exp +5<br>Rollover Adv +5<br>Mox +50%<br>Combat Rate -5<br>Critical Hit Delevel");
	}

	foreach i, s in witch_pieces {
		buffer rep;
		rep.append(s.match_text);
		rep.append("<br><center><table><tr title='");
		rep.append(s.it);
		rep.append(" (have ");
		rep.append(available_amount(s.it));
		rep.append(")");
		if($items[ox-head shield, dented scepter, battle broom, very pointy crown] contains s.it)
			rep.append("\nWill disappear at the end of day");
		rep.append("'><td><img src='/images/itemimages/");
		rep.append(s.it.image);
		rep.append("' class='hand' onClick='javascript:descitem(");
		rep.append(s.it.descid);
		rep.append(")'></td><td><a onClick='javascript:descitem(");
		rep.append(s.it.descid);
		rep.append(")'><b>");
		rep.append(s.type);
		rep.append("</a></b></td></tr></table></center><div style=\"color:blue; font-size:75%\">");
		rep.append(s.additional_text);
		rep.append("</div>");
		page.replace_string(s.match_text, rep);
	}
	
	// Line up the pieces neatly.
	page.replace_string('<div style="display:inline-block; text-align: center; width: 120px">', '<div style="vertical-align:top; display:inline-block; text-align: center; width: 120px">');
	
	return page;
}
 

buffer special_pages(buffer page) {
	if(page.contains_text('bgcolor=blue><b>Rainy Fax Dreams on your Wedding Day</b>'))
		return rainy_fax(page);
	if(page.contains_text('bgcolor=blue><b>Pick a Card</b>'))
		return pick_card(page);
	if(page.contains_text("Your Witchess set came with a "))
		return witchess(page);
	return page;
}


void main() {
	# if(true) return;
	# foreach key in form_fields() print(key+" -- "+ form_field(key));
	switch(form_field("whichchoice")) {
	case "793":	// The Shore, Inc. > Gift Shop
	case "189":	// O Cap'm, My Cap'm > Set an Open Course for the Virgin Booty
		return;
	case "970": // Rainy Fax Dreams on your Wedding Day
		if(form_fields() contains "whichmonster")
			return; // Don't override combat with faxed monster
		break;
	case "991": // Build a Crimbot!
	case "992": // Inside the Fully Automated Crimbo Factory
		visit_url().crimbot_factory().write();
		return;
	case "1171": // LT&T Office
		# visit_url().ltt().write();
		return;
	}
	visit_url().special_pages().write();
}

The second time I went to the location and hit "auto" it worked as expected.
 
Last edited:

heeheehee

Developer
Staff member
Hm. What are the next few lines in that log? And can you post after-adventure.ash, for completeness's sake?

I don't see anything that seems like it might be the cause, just yet.
 

Magus_Prime

Well-known member
As requested:

Code:
1476870457358: From Browser: GET /choice.php?action=auto HTTP/1.1
1476870457359: Starting relay script: choice.ash
1476870457361: Requesting: https://www.kingdomofloathing.com/choice.php?whichchoice=900&option=1&pwd
1476870457481: Retrieved: https://www.kingdomofloathing.com/choice.php?whichchoice=900&option=1&pwd
1476870457485: Finished relay script: choice.ash
1476870457485: Starting relay script: choice.ash
1476870457486: Requesting: https://www.kingdomofloathing.com/choice.php?whichchoice=900&option=2&pwd
1476870457552: Retrieved: https://www.kingdomofloathing.com/choice.php?whichchoice=900&option=2&pwd
1476870457554: Finished relay script: choice.ash
1476870457555: Starting relay script: choice.ash
1476870457555: Requesting: https://www.kingdomofloathing.com/choice.php?whichchoice=900&option=2&pwd
1476870457772: Retrieved: https://www.kingdomofloathing.com/choice.php?whichchoice=900&option=2&pwd
1476870457798: Starting ASH script: after-adventure.ash
1476870457828: Finished ASH script: after-adventure.ash
1476870457828: Finished relay script: choice.ash
1476870457831: To Browser: HTTP/1.1 200 OK: /choice.php?action=auto
1476870458099: From Browser: GET /hotkeys.js HTTP/1.1
1476870458101: To Browser: HTTP/1.1 200 OK: /hotkeys.js
1476870458130: From Browser: GET /basics.js HTTP/1.1
1476870458133: To Browser: HTTP/1.1 200 OK: /basics.js
1476870458182: From Browser: POST /relay_Guide.ash HTTP/1.1
1476870458182: Starting relay script: relay_Guide.ash
1476870458194: Finished relay script: relay_Guide.ash
1476870458195: To Browser: HTTP/1.1 200 OK: /relay_Guide.ash
1476870458287: From Browser: GET /charpane.php HTTP/1.1
1476870458288: Starting relay script: charpane.ash
1476870458290: Requesting: https://www.kingdomofloathing.com/charpane.php
1476870458393: Retrieved: https://www.kingdomofloathing.com/charpane.php
1476870458671: Finished relay script: charpane.ash
1476870458681: To Browser: HTTP/1.1 200 OK: /charpane.php
1476870458982: From Browser: GET /basics.js HTTP/1.1
1476870458985: To Browser: HTTP/1.1 200 OK: /basics.js
1476870459072: From Browser: GET /chit.css HTTP/1.1
1476870459072: From Browser: GET /chit_custom.css HTTP/1.1
1476870459072: From Browser: GET /chit.js HTTP/1.1
1476870459073: To Browser: HTTP/1.1 404 Not Found: /chit_custom.css
1476870459073: To Browser: HTTP/1.1 200 OK: /chit.css
1476870459074: To Browser: HTTP/1.1 200 OK: /chit.js
1476870460634: From Browser: POST /relay_Guide.ash HTTP/1.1
1476870460635: Starting relay script: relay_Guide.ash
1476870460656: Finished relay script: relay_Guide.ash
1476870460658: To Browser: HTTP/1.1 200 OK: /relay_Guide.ash
1476870462791: From Browser: POST /relay_Guide.ash HTTP/1.1
1476870462792: Starting relay script: relay_Guide.ash
1476870462813: Finished relay script: relay_Guide.ash
1476870462815: To Browser: HTTP/1.1 200 OK: /relay_Guide.ash
1476870464958: From Browser: null
1476870465503: From Browser: POST /relay_Guide.ash HTTP/1.1
1476870465504: Starting relay script: relay_Guide.ash
1476870465530: Finished relay script: relay_Guide.ash

The after-adventure script is, essentially, zarqon's BBB with the addition of Bale's ghost busting logic.

Code:
import <BestBetweenBattle.ash>

//// Bust ghosts with the proton pack.  Assumes the pack is equipped

void bustGhost() {
	item acc3;
	familiar fam;
	location ghostLocation = to_location(get_property("ghostLocation"));
	if(my_inebriety() <= inebriety_limit() && to_boolean(get_property("kingLiberated")) && ghostLocation != $location[none]) {
		switch(ghostLocation) {
		case $location[Inside the Palindome]:
			acc3 = equipped_item($slot[acc3]);
			equip($slot[acc3], $item[Talisman o' Namsilat]);
			break;
		case $location[The Skeleton Store]:
			if(get_property("questM23Meatsmith") == "unstarted") {
				visit_url("shop.php?whichshop=meatsmith&action=talk");
				run_choice(1);
			}
			break;
		case $location[The Overgrown Lot]:
			if(get_property("questM24Doc") == "unstarted") {
				visit_url("shop.php?whichshop=doc&action=talk");
				run_choice(1);
			}
			break;
		case $location[Madness Bakery]:
			if(get_property("questM25Armorer") == "unstarted") {
				visit_url("shop.php?whichshop=armory&action=talk");
				run_choice(1);
			}
			break;
		}
		item back;
		if(!have_equipped($item[protonic accelerator pack])) {
			back = equipped_item($slot[back]);
			equip($item[protonic accelerator pack]);
		}
		if(my_familiar().combat) {
			fam = my_familiar();
			use_familiar($familiar[none]);
		}
		(!adv1(ghostLocation, -1, "skill Summon Love Gnats; while hasskill Shoot Ghost; skill Shoot Ghost; if hasskill Trap Ghost; skill Trap Ghost; endif; endwhile;")); // Trap error condition in case I'm adventuring with goals
		if(acc3 != $item[none])
			equip($slot[acc3], acc3);
		if(fam != $familiar[none])
			use_familiar(fam);
		if(back != $item[none])
			equip(back);
	}
}


void main() {

		bbb();																// Run zarqon's BestBetweenBattle script

//// In future there will be sections for in-ronin and aftercore
		bustGhost();                         // Bust Ghosts but assumes proton pack is worn
}
 
I suggest that people who are having this problem do the following:

- update to revision 17290
- run with "debug trace on" - which is WAY smaller than a simple "debug on"
- When/if the "auto" button gives you Manuel, look in the TRACE file and find everything between "From Browser: GET /choice.php?action=auto HTTP/1.1" and "To Browser: HTTP/1.1 200 OK: /choice.php?action=auto"
- Show it here

Thanks.

Version 17293 - problem crops up every dog nc.
1477013711884: From Browser: GET /choice.php?action=auto HTTP/1.1
1477013711901: To Browser: HTTP/1.1 200 OK: /choice.php?action=auto
 
That's really it? Nothing between From Browser and To Browser?

Here's a larger sample, incorporating those lines:
1477013710214: From Browser: POST /relay_Guide.ash HTTP/1.1
1477013710214: Starting relay script: relay_Guide.ash
1477013710238: Finished relay script: relay_Guide.ash
1477013710239: To Browser: HTTP/1.1 200 OK: /relay_Guide.ash
1477013710749: From Browser: POST /relay_Guide.ash HTTP/1.1
1477013710750: Starting relay script: relay_Guide.ash
1477013710761: Finished relay script: relay_Guide.ash
1477013710762: To Browser: HTTP/1.1 200 OK: /relay_Guide.ash
1477013711265: From Browser: POST /relay_Guide.ash HTTP/1.1
1477013711265: Starting relay script: relay_Guide.ash
1477013711280: Finished relay script: relay_Guide.ash
1477013711280: To Browser: HTTP/1.1 200 OK: /relay_Guide.ash
1477013711796: From Browser: POST /relay_Guide.ash HTTP/1.1
1477013711797: Starting relay script: relay_Guide.ash
1477013711807: Finished relay script: relay_Guide.ash
1477013711808: To Browser: HTTP/1.1 200 OK: /relay_Guide.ash
1477013711884: From Browser: GET /choice.php?action=auto HTTP/1.1
1477013711901: To Browser: HTTP/1.1 200 OK: /choice.php?action=auto

1477013712317: From Browser: POST /relay_Guide.ash HTTP/1.1
1477013712318: Starting relay script: relay_Guide.ash
1477013712334: Finished relay script: relay_Guide.ash
1477013712336: To Browser: HTTP/1.1 200 OK: /relay_Guide.ash
1477013712742: From Browser: GET /images/adventureimages/coldhobo1.gif HTTP/1.1
1477013712774: To Browser: HTTP/1.1 200 OK: /images/adventureimages/coldhobo1.gif
1477013712813: From Browser: GET /images/adventureimages/dvcoldwolf3.gif HTTP/1.1
1477013712843: From Browser: POST /relay_Guide.ash HTTP/1.1
1477013712843: Starting relay script: relay_Guide.ash
1477013712854: Finished relay script: relay_Guide.ash
1477013712856: To Browser: HTTP/1.1 200 OK: /relay_Guide.ash
1477013712871: To Browser: HTTP/1.1 200 OK: /images/adventureimages/dvcoldwolf3.gif
1477013712953: From Browser: GET /newchatmessages.php?aa=0.08005933165862533&j=1&lasttime=1431572396 HTTP/1.1
1477013712953: Requesting: https://www.kingdomofloathing.com/submitnewchat.php?pwd&playerid=2340910&graf=/listen
1477013713063: Retrieved: https://www.kingdomofloathing.com/submitnewchat.php?pwd&playerid=2340910&graf=/listen
1477013713063: Requesting: https://www.kingdomofloathing.com/newchatmessages.php?j=1&lasttime=1431572396
1477013713175: Retrieved: https://www.kingdomofloathing.com/newchatmessages.php?j=1&lasttime=1431572396
1477013713175: To Browser: HTTP/1.1 200 OK: /newchatmessages.php?aa=0.08005933165862533&j=1&lasttime=1431572396
1477013713364: From Browser: POST /relay_Guide.ash HTTP/1.1
1477013713364: Starting relay script: relay_Guide.ash
1477013713380: Finished relay script: relay_Guide.ash
1477013713380: To Browser: HTTP/1.1 200 OK: /relay_Guide.ash
1477013714655: From Browser: POST /relay_Guide.ash HTTP/1.1
1477013714655: Starting relay script: relay_Guide.ash
1477013714671: Finished relay script: relay_Guide.ash
1477013714671: To Browser: HTTP/1.1 200 OK: /relay_Guide.ash
1477013715924: From Browser: GET /newchatmessages.php?aa=0.8736049540179338&j=1&lasttime=1431572396 HTTP/1.1
1477013715924: Requesting: https://www.kingdomofloathing.com/submitnewchat.php?pwd&playerid=2340910&graf=/listen
1477013715940: From Browser: POST /relay_Guide.ash HTTP/1.1
1477013715940: Starting relay script: relay_Guide.ash
1477013715956: Finished relay script: relay_Guide.ash
1477013715956: To Browser: HTTP/1.1 200 OK: /relay_Guide.ash
1477013716034: Retrieved: https://www.kingdomofloathing.com/submitnewchat.php?pwd&playerid=2340910&graf=/listen
1477013716034: Requesting: https://www.kingdomofloathing.com/newchatmessages.php?j=1&lasttime=1431572396
1477013716128: Retrieved: https://www.kingdomofloathing.com/newchatmessages.php?j=1&lasttime=1431572396
1477013716128: To Browser: HTTP/1.1 200 OK: /newchatmessages.php?aa=0.8736049540179338&j=1&lasttime=1431572396
1477013717227: From Browser: POST /relay_Guide.ash HTTP/1.1
1477013717227: Starting relay script: relay_Guide.ash
1477013717243: Finished relay script: relay_Guide.ash
1477013717243: To Browser: HTTP/1.1 200 OK: /relay_Guide.ash
1477013718504: From Browser: POST /relay_Guide.ash HTTP/1.1
1477013718504: Starting relay script: relay_Guide.ash
1477013718520: Finished relay script: relay_Guide.ash
 

Veracity

Developer
Staff member
Interesting. So, what could make KoLmafia get a request form the Browser for choice.php?action=auto and respond to it - with, reportedly, text from the Monster Manuel - without getting a request/response to KoL?

You say this is the "dog" nc and we presented you with an "auto" button which you then pressed. I actually haven't used the "dog". This is the Hallowiener Dog? The WIki seems to indicate that there are 3 "dog" things that are choices:

1106 - Wooof! Wooooooof!
1107 - Playing Fetch*
1108 - Your Dog Found Something Again

All of those have a default of 0 - Manual control.

RelayAgent.readServerResponse says:

Code:
		else if ( this.path.equals( "/choice.php?action=auto" ) )
		{
			ChoiceManager.processChoiceAdventure( this.request, "choice.php", ChoiceManager.lastResponseText );
			if ( StaticEntity.userAborted || KoLmafia.refusesContinue() )
			{
				// Resubmit the choice request to let the user see it again
				KoLmafia.forceContinue();
				request.constructURLString( "choice.php?forceoption=0" );
				RequestThread.postRequest( this.request );
				RelayAgent.errorRequest = null;
			}
		}
It calls ChoiceManager.processChoiceAdventure. If that method aborts (with a message), KoLmafia will submit "choice.php?forceoption=0". It did not do that. Therefore, processChoiceAdventure returned without submitting anything or aborting.

Code:
		if ( GenericRequest.passwordHash.equals( "" ) )
		{
			return;
		}

		for ( int stepCount = 0;
		      !KoLmafia.refusesContinue() && ChoiceManager.stillInChoice( request.responseText );
		      ++stepCount )
		{
If you don't have a password hash, we return without aborting.
If we think you are not "still in a choice", we will not enter the loop.

If we do get in the loop:

Code:
			if ( ChoiceManager.specialChoiceHandling( choice, request ) )
			{
				return;
			}
If this is a "special" choice, we can return without aborting. The "dog" choices are not "special".

And everything after that will either abort or will submit a request to choice.php.

I conclude that ChoiceManager.stillInChoice is returning false.

Code:
	{
		// Doing the Maths has a choice form but, somehow, does not specify choice.php

		// <form method="get" id="">
		//   <input type="hidden" name="whichchoice" value="1103" />
		//   <input type="hidden" name="pwd" value="xxxxxx" />
		//   <input type="hidden" name="option" value="1" />
		//   <input type="text" name="num" value="" maxlen="6" size="6" />
		//   <input type="submit" value="Calculate the Universe" class="button" />
		//   <div style="clear:both"></div>
		// </form>

		return  responseText.contains( "action=choice.php" ) ||
			responseText.contains( "href=choice.php" ) ||
			responseText.contains( "name=\"whichchoice\"" ) ||
			responseText.contains( "href=\"choice.php" );
	}
I'd have to see an actual DEBUG log of getting the "dog" choice.

Now, given that, why would it return saved text for a Manuel page?

RelayAgent:

Code:
			this.readServerResponse();
			this.sendServerResponse();
What does sendServerResponse do?

Code:
		if ( this.request.rawByteBuffer == null )
		{
			if ( this.request.responseText == null )
			{
				return;
			}
...
			// Convert the responseText into a byte buffer
			this.request.rawByteBuffer = this.request.responseText.getBytes( "UTF-8" );
		}
You either have a rawByteBuffer or it builds one from the responseText.

Code:
		this.writer = new PrintStream( this.socket.getOutputStream(), false );
		this.writer.println( this.request.statusLine );
		this.request.printHeaders( this.writer );
		this.writer.println();
		this.writer.write( this.request.rawByteBuffer );
		this.writer.flush();
It sends a response to the Browser.

Note that it DID send a response the the Browser - so either there was a rawByteBuffer or a responseText.

So, a given instance of a RelayAgent has a RelayRequest. It uses that to make KoL requests. It will reuse the request every time it gets a new request from the Browser. Therefore, a previously used request will come with a rawByteBuffer and/or a responseText. When does that get cleared?

RelayRequest.constructURLString() clears rawByteBuffer
GenericRequest.prepareRequest clears responseText

Which is to say, only if we actually submit a request.

So, if choice processing ends up not actually submitting a a request, we will send down whatever the previous response was for this RelayAgent.

I'd be curious to see who/what submitted a request to the Monster Manuel. Presumably, we could see that in your TRACE log.
I'd also be curious to see the choice.php request earlier in your TRACE log.
Lastly, I'd be curious to see the actual response text KoL sent for that - but we'd need a DEBUG log for that.

But in any case, we can do the following:

RelayAgent.readBrowserRequest can clear rawByteBuffer and responseText.
ChoiceManager.processChoiceAdventure already loads responseText from ChoiceManager.lastResponseText. If it returns without aborting - because it thought you were not stillInChoice we will make a new rawByteBuffer out of that and send it on down to the Browser - which will simply refresh the page.

I'll make the change to RelayAgent.readBrowserRequest.
 

Veracity

Developer
Staff member
Except RelayAgent.readBrowserRequest calls the constructURLString method of the request, which clears rawByteBuffer.
A new one will be constructed from the responseText - which should be set by processChoiceAdventure.
So, this continues to be confusing.
 

Veracity

Developer
Staff member
I wonder. I would like to see a TRACE from anybody which shows the following:

choice.php?....stuff... (probably forceoption=0)
questlog.php?...stuff... (Monster Manuel)
choice.php?action=auto

In particular, I'd like to see the stuff surrounding the questlog. Is it a relay script? Guide? (we've seen several examples of people using that) Something else?

CAN you get Monster Manuel while inside a choice? Because, if so, the following code in ChoiceManager.postChoice1:

Code:
		// chat and desc_ requests can come at any time
		if ( request.isChatRequest || request.isDescRequest )
		{
			return;
		}
... will allow processing to occur, and the following code in that same method:

Code:
		if ( ChoiceManager.lastChoice == 0 )
		{
			// We are viewing the choice page for the first time.
			ChoiceManager.visitChoice( request );
			return;
		}
will result in ChoiceManager.lastReponseText getting set to the Manuel page because:

Code:
	public static void visitChoice( final GenericRequest request )
	{
		String text = ChoiceManager.lastResponseText = request.responseText;
		ChoiceManager.lastChoice = ChoiceManager.extractChoice( text );

		if ( ChoiceManager.lastChoice == 0 )
		{
			// choice.php did not offer us any choices.
			// This would be a bug in KoL itself.
			return;
		}
If we are processing a Manuel page believing it is a choice, that is OUR bug.

OK. I can move setting lastResponseText until after that.

I still want to see the TRACE showing the call to questlog.php and surrounding context.
 

Veracity

Developer
Staff member
Answer: you can go anywhere in the questlog and still remain in the choice.

I don't know which script is triggering Manuel for you people, but I can make it not break choice handling.
 

Bale

Minion
Hasn't happened to me in the last 8 days, so I concur.

It's a shame you never figured out what exactly was happening.

Do you want to leave the debugging messages that say "unhandled redirect"? I have been approached by some people who are troubled by those; thinking that there is a problem with their mafia. I've reassured them of course, but it might be nice to not need the reassurance.
 
Top