Bug - Fixed Spelunky: Killing the shopkeeper doesn't update wincount/nextNoncombat

Hellno

Member
This seems to be a recent issue but I can't see anything spelunky related in the release history so it's probably some indirect cause? Whenever I kill a shopkeeper the following values don't update:

Code:
spelunkyWinCount
spelunkyNextNoncombat

It happened on my multi yesterday and for me today, so I'm guessing it's unlikely I've messed something up.
 

Veracity

Developer
Staff member
As part of handling Batfellow combats, I refactored the handling of all "limitmode" combats. Which is to say, I moved all the code in FightRequest.updateRoundData for Spelunky into SpelunkyRequest.wonFight. That said, the following code used to be in FightRequest but is now in SpelunkyRequest:

Code:
		if ( !monsterName.equals( "shopkeeper" ) && !monsterName.equals( "ghost (spelunky)" ) )
		{
			SpelunkyRequest.incrementWinCount();
		}
so, this wasn't a change in behavior.

Why do you think it is a bug?
 

Hellno

Member
Why do you think it is a bug?

Maybe I wasn't clear. When you kill the shopkeeper (which is a non-combat encounter), mafia thinks that the next encounter will be the same non-combat. So if I kill the shopkeeper in a phase 1 NC, mafia will think I have another phase 1 NC in the next adventure.

Before fighting shopkeeper:

Code:
spelunkyWinCount = 3
spelunkyNextNoncombat = 1

After fighting shopkeeper:

Code:
spelunkyWinCount = 3
spelunkyNextNoncombat = 1

What the values should be (and used to be) after fighting shopkeeper):

Code:
spelunkyWinCount = 0
spelunkyNextNoncombat = 2
 

Veracity

Developer
Staff member
Studying the code more, the code for managing spelunkyWinCount and spelunkyNextNoncombat for shopkeepers was never in FightRequest; it was always done as part of taking a choice adventure. SpelunkyRequest.parseChoice:

Code:
		if ( choice != 1040 && choice != 1041 )
		{
			// If you win more than three fights before taking a
			// noncombat, the extra wins count towards the next
			// noncombat
			Preferences.decrement( "spelunkyWinCount", 3 );

			// Shopkeeper doesn't increment the counter til you leave or fight
			if ( choice != 1028 || decision >= 5 )
			{
				SpelunkyRequest.incrementNonCombatPhase();
			}
		}
I can't think of any reason we'd stop calling SpelunkyRequest.parseChoice. I'll look around and see what might have changed that.
 

Veracity

Developer
Staff member
Can I see your session log leading up to the fight with the shopkeeper, please?
Maybe even a DEBUG log of the choice adventure and the fight.
 

Hellno

Member
These are the three times I fought the shopkeeper (pm'd the full log)- the issue occurred after all 3 fights. There doesn't seem to be any debug logging.

Code:
{18} The Ice Caves
Encounter: A Shop
Buyingack the shopkeeper
Took choice 1028/5: chance to fight shopkeeper
choice.php?pwd&whichchoice=1028&option=5
Encounter: shopkeeper
Round 0: hellno wins initiative!
Round 1: hellno attacks!
Round 2: shopkeeper takes 9 damage. (51 moxie vs. 60 defense)
Round 2: shopkeeper drops 4 attack power. (60 -> 56)
Round 2: shopkeeper drops 3 defense. (60 -> 57)
Round 2: Your skeleton buddy punches your foe for 9 damage.
Round 2: shopkeeper takes 9 damage. (51 moxie vs. 57 defense)
Round 2: With your swoopy cape and your springy boots, you jump and swoop out of your foe's reach.
Round 2: hellno attacks!
Round 3: shopkeeper takes 11 damage. (51 moxie vs. 57 defense)
Round 3: shopkeeper drops 4 attack power. (56 -> 52)
Round 3: shopkeeper drops 4 defense. (57 -> 53)
Round 3: Your skeleton buddy punches your foe for 9 damage.
Round 3: shopkeeper takes 9 damage. (51 moxie vs. 53 defense)
Round 3: You lose 6 hit points (52 attack vs. 51 moxie)
Round 3: hellno attacks!
Round 4: shopkeeper takes 8 damage. (51 moxie vs. 53 defense)
Round 4: shopkeeper drops 4 attack power. (52 -> 48)
Round 4: shopkeeper drops 4 defense. (53 -> 49)
Round 4: Your skeleton buddy punches your foe for 9 damage.
Round 4: shopkeeper takes 9 damage. (51 moxie vs. 49 defense)
Round 4: You lose 4 hit points (48 attack vs. 51 moxie)
Round 4: hellno attacks!
Round 5: shopkeeper takes 10 damage. (51 moxie vs. 49 defense)
Round 5: shopkeeper drops 3 attack power. (48 -> 45)
Round 5: shopkeeper drops 3 defense. (49 -> 46)
Round 5: Your skeleton buddy punches your foe for 8 damage.
Round 5: shopkeeper takes 8 damage. (51 moxie vs. 46 defense)
Round 5: With your swoopy cape and your springy boots, you jump and swoop out of your foe's reach.
Round 5: hellno attacks!
Round 6: shopkeeper takes 14 damage. (51 moxie vs. 46 defense)
Round 6: shopkeeper drops 4 attack power. (45 -> 41)
Round 6: shopkeeper drops 3 defense. (46 -> 43)
Round 6: Your skeleton buddy punches your foe for 8 damage.
Round 6: shopkeeper takes 8 damage. (51 moxie vs. 43 defense)
Round 6: You lose 1 hit point (41 attack vs. 51 moxie)
Round 6: hellno attacks!
Round 7: shopkeeper takes 14 damage. (51 moxie vs. 43 defense)
Round 7: shopkeeper drops 4 attack power. (41 -> 37)
Round 7: shopkeeper drops 3 defense. (43 -> 40)
Round 7: Your skeleton buddy punches your foe for 8 damage.
Round 7: shopkeeper takes 8 damage. (51 moxie vs. 40 defense)
Round 7: With your swoopy cape and your springy boots, you jump and swoop out of your foe's reach.
Round 7: hellno attacks!
Round 8: shopkeeper takes 17 damage. (51 moxie vs. 40 defense)
Round 8: shopkeeper drops 3 attack power. (37 -> 34)
Round 8: shopkeeper drops 3 defense. (40 -> 37)
Round 8: Your skeleton buddy punches your foe for 10 damage.
Round 8: shopkeeper takes 10 damage. (51 moxie vs. 37 defense)
Round 8: You lose 1 hit point (34 attack vs. 51 moxie)
Round 8: hellno attacks!
Round 9: shopkeeper takes 21 damage. (51 moxie vs. 37 defense)
Round 9: shopkeeper drops 5 attack power. (34 -> 29)
Round 9: shopkeeper drops 5 defense. (37 -> 32)
Round 9: hellno wins the fight!
After Battle: You gain 44 gold
After Battle: You got 5 ropes!
You acquire an item: heavy pickaxe
You acquire an item: jetpack
You acquire an item: spiked boots


{9} The Ice Caves
Encounter: Hostile Work Environment
Took choice 1045/1: fight shopkeeper
choice.php?pwd&whichchoice=1045&option=1
Encounter: shopkeeper
Round 0: hellno wins initiative!
Round 1: hellno attacks!
Round 2: shopkeeper takes 15 damage. (60 moxie vs. 60 defense)
Round 2: shopkeeper drops 3 attack power. (60 -> 57)
Round 2: shopkeeper drops 5 defense. (60 -> 55)
Round 2: Your skeleton buddy punches your foe for 8 damage.
Round 2: shopkeeper takes 8 damage. (60 moxie vs. 55 defense)
Round 2: You leap out of your foe's reach with your springy boots, and hover there with your jetpack, sticking your tongue out at him.
Round 2: hellno attacks!
Round 3: shopkeeper takes 12 damage. (60 moxie vs. 55 defense)
Round 3: shopkeeper drops 5 attack power. (57 -> 52)
Round 3: shopkeeper drops 4 defense. (55 -> 51)
Round 3: Your skeleton buddy punches your foe for 9 damage.
Round 3: shopkeeper takes 9 damage. (60 moxie vs. 51 defense)
Round 3: You lose 4 hit points (52 attack vs. 60 moxie)
Round 3: hellno attacks!
Round 4: shopkeeper takes 15 damage. (60 moxie vs. 51 defense)
Round 4: shopkeeper drops 4 attack power. (52 -> 48)
Round 4: shopkeeper drops 3 defense. (51 -> 48)
Round 4: Your skeleton buddy punches your foe for 8 damage.
Round 4: shopkeeper takes 8 damage. (60 moxie vs. 48 defense)
Round 4: You lose 4 hit points (48 attack vs. 60 moxie)
Round 4: hellno attacks!
Round 5: shopkeeper takes 17 damage. (60 moxie vs. 48 defense)
Round 5: shopkeeper drops 5 attack power. (48 -> 43)
Round 5: shopkeeper drops 4 defense. (48 -> 44)
Round 5: Your skeleton buddy punches your foe for 8 damage.
Round 5: shopkeeper takes 8 damage. (60 moxie vs. 44 defense)
Round 5: You leap out of your foe's reach with your springy boots, and hover there with your jetpack, sticking your tongue out at him.
Round 5: hellno attacks!
Round 6: shopkeeper takes 21 damage. (60 moxie vs. 44 defense)
Round 6: shopkeeper drops 5 attack power. (43 -> 38)
Round 6: shopkeeper drops 5 defense. (44 -> 39)
Round 6: Your skeleton buddy punches your foe for 8 damage.
Round 6: shopkeeper takes 8 damage. (60 moxie vs. 39 defense)
Round 6: You lose 1 hit point (38 attack vs. 60 moxie)
Round 6: hellno attacks!
Round 7: shopkeeper takes 26 damage. (60 moxie vs. 39 defense)
Round 7: shopkeeper drops 3 attack power. (38 -> 35)
Round 7: shopkeeper drops 5 defense. (39 -> 34)
Round 7: Your skeleton buddy punches your foe for 9 damage.
Round 7: shopkeeper takes 9 damage. (60 moxie vs. 34 defense)
Round 7: hellno wins the fight!
After Battle: You gain 42 gold
After Battle: You got 5 bombs!
After Battle: You got a key!


{10} The Ice Caves
Encounter: Hostile Work Environment
Took choice 1045/1: fight shopkeeper
choice.php?pwd&whichchoice=1045&option=1
Encounter: shopkeeper
Round 0: hellno wins initiative!
Round 1: hellno attacks!
Round 2: shopkeeper takes 12 damage. (62 moxie vs. 60 defense)
Round 2: shopkeeper drops 5 attack power. (60 -> 55)
Round 2: shopkeeper drops 3 defense. (60 -> 57)
Round 2: Your skeleton buddy punches your foe for 8 damage.
Round 2: shopkeeper takes 8 damage. (62 moxie vs. 57 defense)
Round 2: You lose 4 hit points (55 attack vs. 62 moxie)
Round 2: hellno attacks!
Round 3: shopkeeper takes 12 damage. (62 moxie vs. 57 defense)
Round 3: shopkeeper drops 3 attack power. (55 -> 52)
Round 3: shopkeeper drops 5 defense. (57 -> 52)
Round 3: Your skeleton buddy punches your foe for 9 damage.
Round 3: shopkeeper takes 9 damage. (62 moxie vs. 52 defense)
Round 3: You lose 3 hit points (52 attack vs. 62 moxie)
Round 3: hellno attacks!
Round 4: shopkeeper takes 16 damage. (62 moxie vs. 52 defense)
Round 4: shopkeeper drops 3 attack power. (52 -> 49)
Round 4: shopkeeper drops 5 defense. (52 -> 47)
Round 4: Your skeleton buddy punches your foe for 10 damage.
Round 4: shopkeeper takes 10 damage. (62 moxie vs. 47 defense)
Round 4: You lose 5 hit points (49 attack vs. 62 moxie)
Round 4: hellno attacks!
Round 5: shopkeeper takes 21 damage. (62 moxie vs. 47 defense)
Round 5: shopkeeper drops 4 attack power. (49 -> 45)
Round 5: shopkeeper drops 4 defense. (47 -> 43)
Round 5: Your skeleton buddy punches your foe for 9 damage.
Round 5: shopkeeper takes 9 damage. (62 moxie vs. 43 defense)
Round 5: You leap out of your foe's reach with your springy boots, and hover there with your jetpack, sticking your tongue out at him.
Round 5: hellno attacks!
Round 6: shopkeeper takes 25 damage. (62 moxie vs. 43 defense)
Round 6: shopkeeper drops 5 attack power. (45 -> 40)
Round 6: shopkeeper drops 5 defense. (43 -> 38)
Round 6: Your skeleton buddy punches your foe for 9 damage.
Round 6: shopkeeper takes 9 damage. (62 moxie vs. 38 defense)
Round 6: You lose 3 hit points (40 attack vs. 62 moxie)
Round 6: hellno attacks!
Round 7: shopkeeper takes 29 damage. (62 moxie vs. 38 defense)
Round 7: shopkeeper drops 5 attack power. (40 -> 35)
Round 7: shopkeeper drops 5 defense. (38 -> 33)
Round 7: hellno wins the fight!
After Battle: You gain 38 gold
After Battle: You got 5 ropes!
After Battle: You got 5 ropes!
 

Veracity

Developer
Staff member
Yeah... revision 16728 did this in GenericRequest:

Code:
		if ( urlString.startsWith( "choice.php" ) && ChoiceManager.handlingChoice && !this.isChatRequest && !this.isDescRequest )
		{
			// Handle choices BEFORE result processing
			ChoiceManager.postChoice1( this );
		}
That check for "urlString.startsWith( "choice.php" )" is new. Since the choice option to fight the shopkeeper redirects to fight.php, that means that ChoiceManager.postChoice1 is no longer called to let SpelunkyRequest do its thing.

Perhaps lost could comment on the issue that prompted this change?
Perhaps there is a different solution.
Otherwise, FightRequest will need to do something when you start a fight with a shopkeeper...
 

heeheehee

Developer
Staff member
That check for "urlString.startsWith( "choice.php" )" is new. Since the choice option to fight the shopkeeper redirects to fight.php, that means that ChoiceManager.postChoice1 is no longer called to let SpelunkyRequest do its thing.
I knew that was going to break something...

If there's a way to check the pre-redirect urlString, then that would be a better fix. As is, ChoiceManager.lastResponseText can be set to any page's HTML if you can walk away from said choice; this caused a NPE in certain cases with LT&T quest tracking.
 

Veracity

Developer
Staff member
Code:
		case 1171: // LT&T Office
			if ( ChoiceManager.lastDecision < 4 )
			{
				QuestDatabase.setQuestProgress( Quest.TELEGRAM, QuestDatabase.STARTED );
				Preferences.setInteger( "lttQuestDifficulty", ChoiceManager.lastDecision );
				Preferences.setInteger( "lttQuestStageCount", 0 );
				Matcher matcher = TELEGRAM_PATTERN.matcher( ChoiceManager.lastResponseText );
				for ( int i = 0; i < ChoiceManager.lastDecision ; i++ )
				{
					if ( !matcher.find() )
					{
						break;
					}
				}
				Preferences.setString( "lttQuestName", matcher.group(1) );
			}
			break;
Yeah, well, that is obviously not robust, since matcher.group(1) can be called when matcher.find() just failed.

Here's a thought: where do we set ChoiceManager.lastResponseText?

In ChoiceManager.preChoice when we first visit a page, we set it to null
In ChoiceManager.visitChoice we set it to the responsetext of the request
In ChoiceManager.postChoice1, we set it to the responsetext of the request

Perhaps we should do those last two only if the URL of the request starts with choice.php?
If it does not, either the choice redirected, or you "walked away" from the choice.

Look again at GenericRequest:

Code:
		if ( ChoiceManager.handlingChoice && !this.isChatRequest && !this.isDescRequest )
		{
			// Handle choices BEFORE registering Encounter
			ChoiceManager.postChoice0( this );
		}
and

Code:
		if ( urlString.startsWith( "choice.php" ) && ChoiceManager.handlingChoice && !this.isChatRequest && !this.isDescRequest )
		{
			// Handle choices BEFORE result processing
			ChoiceManager.postChoice1( this );
		}
and

Code:
		if ( ChoiceManager.handlingChoice && !this.isChatRequest && !this.isDescRequest )
		{
			// Handle choices AFTER result processing
			ChoiceManager.postChoice2( this );
		}
See all that stuff about isChatRequest and isDescRequest? We always ignore those, since you can do those in the middle of any choice.

Choices can legitimately lead to a fight - or to another choice - and neither is "walking away".
But going to main or adventure or inventory or whatever requires that you "walked away" from the choice.

Perhaps preChoice and postChoice1 and postChoice2 should make their own decision about whether the request actually continues the choice - or, perhaps, even constitutes "walking away" from the request. Putting it inline in GenericRequest saves the method call, but it really should be up to ChoiceManager.

Code:
		this.isChatRequest =
			this.formURLString.startsWith( "newchatmessages.php" ) ||
			this.formURLString.startsWith( "submitnewchat.php" );

		this.isDescRequest = this.formURLString.startsWith( "desc_" );
Bth of those are used in places other than choice handling.
 

Veracity

Developer
Staff member
Revision 16740 passes the urlString to ChoiceManager.postChoice0, postChoice1, and postChoice2. Those methods will not do any processing if the request was not from choice.php or fight.php - i.e., the expect response from a (possibly redirected) choice request.

Untested, as none of my multis have turns available. But, how bad can it be? ;)
 

Hellno

Member
This fix seems to have broken something. I'm in the first spelunky shop atm, trying to buy something gives me an error ("The server closed the connection without sending any data.") and the following in the debug log:

Code:
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
          KoLmafia v17.2 r16740, Mac OS X, Java 1.8.0_73
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 Please note: do not post this log in the KoLmafia thread of KoL's
 Gameplay-Discussion forum. If you would like the KoLmafia dev team
 to look at it, please write a bug report at kolmafia.us. Include
 specific information about what you were doing when you made this
 and include this log as an attachment.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 Timestamp: Mon Feb 22 22:50:15 CET 2016
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


Unexpected error, debug log printed.
class java.lang.NullPointerException: null
java.lang.NullPointerException
	at java.util.regex.Matcher.getTextLength(Matcher.java:1283)
	at java.util.regex.Matcher.reset(Matcher.java:309)
	at java.util.regex.Matcher.<init>(Matcher.java:229)
	at java.util.regex.Pattern.matcher(Pattern.java:1093)
	at net.sourceforge.kolmafia.request.SpelunkyRequest.logShop(SpelunkyRequest.java:870)
	at net.sourceforge.kolmafia.session.ChoiceManager.preChoice(ChoiceManager.java:6635)
	at net.sourceforge.kolmafia.request.GenericRequest.execute(GenericRequest.java:1525)
	at net.sourceforge.kolmafia.request.GenericRequest.run(GenericRequest.java:1320)
	at net.sourceforge.kolmafia.request.RelayRequest.run(RelayRequest.java:3065)
	at net.sourceforge.kolmafia.RequestThread.postRequest(RequestThread.java:286)
	at net.sourceforge.kolmafia.RequestThread.postRequest(RequestThread.java:249)
	at net.sourceforge.kolmafia.webui.RelayAgent.readServerResponse(RelayAgent.java:567)
	at net.sourceforge.kolmafia.webui.RelayAgent.performRelay(RelayAgent.java:161)
	at net.sourceforge.kolmafia.webui.RelayAgent.run(RelayAgent.java:134)



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
          KoLmafia v17.2 r16740, Mac OS X, Java 1.8.0_73
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 Please note: do not post this log in the KoLmafia thread of KoL's
 Gameplay-Discussion forum. If you would like the KoLmafia dev team
 to look at it, please write a bug report at kolmafia.us. Include
 specific information about what you were doing when you made this
 and include this log as an attachment.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 Timestamp: Mon Feb 22 22:50:42 CET 2016
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


Unexpected error, debug log printed.
class java.lang.NullPointerException: null
java.lang.NullPointerException
	at java.util.regex.Matcher.getTextLength(Matcher.java:1283)
	at java.util.regex.Matcher.reset(Matcher.java:309)
	at java.util.regex.Matcher.<init>(Matcher.java:229)
	at java.util.regex.Pattern.matcher(Pattern.java:1093)
	at net.sourceforge.kolmafia.request.SpelunkyRequest.logShop(SpelunkyRequest.java:870)
	at net.sourceforge.kolmafia.session.ChoiceManager.preChoice(ChoiceManager.java:6635)
	at net.sourceforge.kolmafia.request.GenericRequest.execute(GenericRequest.java:1525)
	at net.sourceforge.kolmafia.request.GenericRequest.run(GenericRequest.java:1320)
	at net.sourceforge.kolmafia.request.RelayRequest.run(RelayRequest.java:3065)
	at net.sourceforge.kolmafia.RequestThread.postRequest(RequestThread.java:286)
	at net.sourceforge.kolmafia.RequestThread.postRequest(RequestThread.java:249)
	at net.sourceforge.kolmafia.webui.RelayAgent.readServerResponse(RelayAgent.java:567)
	at net.sourceforge.kolmafia.webui.RelayAgent.performRelay(RelayAgent.java:161)
	at net.sourceforge.kolmafia.webui.RelayAgent.run(RelayAgent.java:134)

(i tried buying twice, which is why the above log is duplicated)
 
Top