/** * Copyright (c) 2005-2017, KoLmafia development team * http://kolmafia.sourceforge.net/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * [1] Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * [2] Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * [3] Neither the name "KoLmafia" nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package net.sourceforge.kolmafia.session; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; import java.util.LinkedList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.sourceforge.kolmafia.AdventureResult; import net.sourceforge.kolmafia.FamiliarData; import net.sourceforge.kolmafia.KoLAdventure; import net.sourceforge.kolmafia.KoLCharacter; import net.sourceforge.kolmafia.KoLConstants; import net.sourceforge.kolmafia.KoLConstants.CraftingType; import net.sourceforge.kolmafia.KoLmafia; import net.sourceforge.kolmafia.Modifiers; import net.sourceforge.kolmafia.MonsterData; import net.sourceforge.kolmafia.RequestLogger; import net.sourceforge.kolmafia.RequestThread; import net.sourceforge.kolmafia.SpecialOutfit; import net.sourceforge.kolmafia.StaticEntity; import net.sourceforge.kolmafia.listener.NamedListenerRegistry; import net.sourceforge.kolmafia.listener.PreferenceListenerRegistry; import net.sourceforge.kolmafia.combat.MonsterStatusTracker; import net.sourceforge.kolmafia.objectpool.AdventurePool; import net.sourceforge.kolmafia.objectpool.Concoction; import net.sourceforge.kolmafia.objectpool.ConcoctionPool; import net.sourceforge.kolmafia.objectpool.EffectPool; import net.sourceforge.kolmafia.objectpool.FamiliarPool; import net.sourceforge.kolmafia.objectpool.ItemPool; import net.sourceforge.kolmafia.persistence.AdventureDatabase; import net.sourceforge.kolmafia.persistence.ConcoctionDatabase; import net.sourceforge.kolmafia.persistence.DebugDatabase; import net.sourceforge.kolmafia.persistence.EffectDatabase; import net.sourceforge.kolmafia.persistence.EquipmentDatabase; import net.sourceforge.kolmafia.persistence.ItemDatabase; import net.sourceforge.kolmafia.persistence.QuestDatabase; import net.sourceforge.kolmafia.persistence.QuestDatabase.Quest; import net.sourceforge.kolmafia.preferences.Preferences; import net.sourceforge.kolmafia.request.ChateauRequest; import net.sourceforge.kolmafia.request.CreateItemRequest; import net.sourceforge.kolmafia.request.EquipmentRequest; import net.sourceforge.kolmafia.request.FightRequest; import net.sourceforge.kolmafia.request.GenericRequest; import net.sourceforge.kolmafia.request.HermitRequest; import net.sourceforge.kolmafia.request.PlaceRequest; import net.sourceforge.kolmafia.request.UseItemRequest; import net.sourceforge.kolmafia.session.BugbearManager; import net.sourceforge.kolmafia.session.HaciendaManager; import net.sourceforge.kolmafia.session.IslandManager; import net.sourceforge.kolmafia.utilities.LockableListFactory; import net.sourceforge.kolmafia.utilities.StringUtilities; import net.sourceforge.kolmafia.webui.BarrelDecorator; public class ResultProcessor { private static final Pattern DISCARD_PATTERN = Pattern.compile( "You discard your (.*?)\\." ); private static boolean receivedClover = false; private static boolean receivedDisassembledClover = false; private static boolean autoCrafting = false; public static boolean receivedClover() { return ResultProcessor.receivedClover; } public static boolean receivedDisassembledClover() { return ResultProcessor.receivedDisassembledClover; } public static boolean shouldDisassembleClovers( String formURLString ) { return ResultProcessor.receivedClover && !GenericRequest.ascending && FightRequest.getCurrentRound() == 0 && InventoryManager.cloverProtectionActive() && isCloverURL( formURLString ); } public static boolean disassembledClovers( String formURLString ) { return ResultProcessor.receivedDisassembledClover && InventoryManager.cloverProtectionActive() && isCloverURL( formURLString ); } private static boolean isCloverURL( String formURLString ) { return formURLString.startsWith( "adventure.php" ) || formURLString.startsWith( "choice.php" ) || formURLString.startsWith( "hermit.php" ) || formURLString.startsWith( "mallstore.php" ) || formURLString.startsWith( "town_fleamarket.php" ) || formURLString.startsWith( "barrel.php" ) || // Marmot sign can give you a clover after a fight formURLString.startsWith( "fight.php" ) || // Using a 31337 scroll formURLString.contains( "whichitem=553" ) || // ...without in-line loading can redirect to inventory ( formURLString.startsWith( "inventory.php" ) && formURLString.contains( "action=message" ) ); } public static Pattern ITEM_TABLE_PATTERN = Pattern.compile( "<table class=\"item\".*?rel=\"(.*?)\".*?title=\"(.*?)\".*?descitem\\(([\\d]*)\\).*?</table>" ); public static Pattern BOLD_NAME_PATTERN = Pattern.compile( "<b>([^<]*)</b>(?: \\((stored in Hagnk's Ancestral Mini-Storage|automatically equipped)\\))?" ); public static String processItems( boolean combatResults, final String results, final List<AdventureResult> items ) { // Results now come in like this: // // <table class="item" style="float: none" rel="id=617&s=137&q=0&d=1&g=0&t=1&n=1&m=1&u=u"> // <tr><td><img src="http://images.kingdomofloathing.com/itemimages/rcandy.gif" // alt="Angry Farmer candy" title="Angry Farmer candy" class=hand onClick='descitem(893169457)'></td> // <td valign=center class=effect>You acquire an item: <b>Angry Farmer candy</b></td></tr></table> // // Or, in haiku: // // <table class="item" style="float: none" rel="id=83&s=5&q=0&d=1&g=0&t=1&n=1&m=0&u=."> // <tr><td><img src="http://images.kingdomofloathing.com/itemimages/rustyshaft.gif" // alt="rusty metal shaft" title="rusty metal shaft" class=hand onClick='descitem(228339790)'></td> // <td valign=center class=effect><b>rusty metal shaft</b><br>was once your foe's, is now yours.<br> // Beaters-up, keepers.</td></tr></table> // // Pre-process all such matches and save them to a list of items. // Register new items. // Check multi-usability and plurals // // In Spelunky: // // <table><tr><td><img style='vertical-align: middle' class=hand // src='http://images.kingdomofloathing.com/itemimages/shotgun.gif' // onclick='descitem(606913715)'></td><td valign=center>You acquire an item: <b>shotgun</b> // (automatically equipped)</td></tr></table> StringBuffer buffer = new StringBuffer(); boolean changed = false; Matcher itemMatcher = ResultProcessor.ITEM_TABLE_PATTERN.matcher( results ); while ( itemMatcher.find() ) { String relString = itemMatcher.group( 1 ); String itemName = itemMatcher.group( 2 ); String descId = itemMatcher.group( 3 ); Matcher boldMatcher = ResultProcessor.BOLD_NAME_PATTERN.matcher( itemMatcher.group(0) ); String boldName = boldMatcher.find() ? boldMatcher.group(1) : null; String comment = boldName != null ? boldMatcher.group(2) : null; // If we don't know this descid, it's an unknown item. if ( ItemDatabase.getItemIdFromDescription( descId ) == -1 ) { ItemDatabase.registerItem( itemName, descId, relString, boldName ); } // Extract item from the relstring AdventureResult item = ItemDatabase.itemFromRelString( relString ); int itemId = item.getItemId(); int count = item.getCount(); // Check if multiusability conflicts with our expectations boolean multi= ItemDatabase.relStringMultiusable( relString ); boolean ourMulti = ItemDatabase.isMultiUsable( itemId ); if ( multi != ourMulti ) { String message = ( multi ) ? itemName + " is multiusable, but KoLmafia thought it was not" : itemName + " is not multiusable, but KoLmafia thought it was"; RequestLogger.printLine( message ); RequestLogger.updateSessionLog( message ); ItemDatabase.registerMultiUsability( itemId, multi ); } // If we got more than one, check if plural name // conflicts with our expectations String plural = ItemDatabase.extractItemsPlural( count, boldName ); String ourPlural = plural == null ? null : ItemDatabase.getPluralName( itemId ); if ( plural != null && !plural.equals( ourPlural ) ) { String message = "Unexpected plural of '" + itemName + "' found: " + plural; RequestLogger.printLine( message ); RequestLogger.updateSessionLog( message ); ItemDatabase.registerPlural( itemId, plural ); } // Perform special processing, if indicated if ( comment != null ) { itemMatcher.appendReplacement( buffer, "" ); changed = true; // If the item went to Hagnk's... if ( comment.contains( "Hagnk" ) ) { // move it to Hagnk's and remove from page text String message = "Stored in Hagnk's: " + item.toString(); RequestLogger.printLine( message ); if ( Preferences.getBoolean( "logAcquiredItems" ) ) { RequestLogger.updateSessionLog( message ); } AdventureResult.addResultToList( KoLConstants.storage, item ); } // If the item was automatically equipped... else if ( comment.contains( "automatically equipped" ) ) { // add to inventory, equip it, and remove from page text String acquisition = "You acquire and equip an item:"; ResultProcessor.processItem( combatResults, acquisition, item, null ); EquipmentManager.autoequipItem( item ); } } // Otherwise, add it to the list of items we found else if ( items != null ) { items.add( item ); } } if ( changed ) { itemMatcher.appendTail( buffer ); return buffer.toString(); } return results; } public static LinkedList<AdventureResult> parseItems( final String results ) { LinkedList<AdventureResult> items = new LinkedList<AdventureResult>(); Matcher itemMatcher = ResultProcessor.ITEM_TABLE_PATTERN.matcher( results ); while ( itemMatcher.find() ) { String relString = itemMatcher.group( 1 ); String itemName = itemMatcher.group( 2 ); String descId = itemMatcher.group( 3 ); Matcher boldMatcher = ResultProcessor.BOLD_NAME_PATTERN.matcher( itemMatcher.group(0) ); String boldName = boldMatcher.find() ? boldMatcher.group(1) : null; boolean hagnk = boldName != null && boldMatcher.group(2) != null; // If we don't know this descid, it's an unknown item. if ( ItemDatabase.getItemIdFromDescription( descId ) == -1 ) { ItemDatabase.registerItem( itemName, descId, relString, boldName ); } if ( !hagnk ) { items.add( ItemDatabase.itemFromRelString( relString ) ); } } return items; } // <table><tr><td><img class=hand src="http://images.kingdomofloathing.com/itemimages/breath.gif" onClick='eff("7ecbd57bcb86d63be06bb6d4b8e7229f");' width=30 height=30 alt="Hot Breath" title="Hot Breath"></td><td valign=center class=effect>You acquire an effect: <b>Hot Breath</b><br>(duration: 5 Adventures)</td></tr></table> // <table><tr><td><img class=hand src="http://images.kingdomofloathing.com/itemimages/milk.gif" onClick='eff("225aa10e75476b0ad5fa576c89df3901");' width=30 height=30></td><td valign=center class=effect>You lose some of an effect: <b>Got Milk</b> (5 Adventures)</td></tr></table> public static Pattern EFFECT_TABLE_PATTERN = Pattern.compile( "<table><tr><td><img[^>]*eff\\(\"(.*?)\"\\)[^>]*>.*?class=effect>(.*?)<b>(.*?)</b>(?:<br>| )\\((?:duration: )?(\\d+) Adventures?\\)</td></tr></table>" ); public static LinkedList<AdventureResult> parseEffects( String results ) { // Results now come in like this: // // <table><tr><td>You narrow your eyes and begin to leer at things.<center><table><tr><td> // <img class=hand src="http://images.kingdomofloathing.com/itemimages/discoleer.gif" // onClick='eff("bc3d4aad3454fcd82c066ef3949749ca");' width=30 height=30 alt="Disco Leer" // title="Disco Leer"></td><td valign=center class=effect>You acquire an effect: <b>Disco Leer</b> // <br>(duration: 10 Adventures)</td></tr></table></center></td></tr></table> // // Pre-process all such matches and add them to the passed in list of effects. LinkedList<AdventureResult> effects = new LinkedList<AdventureResult>(); Matcher effectMatcher = ResultProcessor.EFFECT_TABLE_PATTERN.matcher( results ); while ( effectMatcher.find() ) { String descId = effectMatcher.group( 1 ); String effectName = effectMatcher.group( 3 ); int effectId = EffectDatabase.getEffectIdFromDescription( descId ); // If we don't know this effectId, it's an unknown effect if ( effectId == -1 ) { effectId = EffectDatabase.learnEffectId( effectName, descId ); } String acquisition = effectMatcher.group( 2 ); int duration = StringUtilities.parseInt( effectMatcher.group( 4 ) ); if ( acquisition.contains( "lose" ) ) { duration = -duration; } AdventureResult effect = EffectPool.get( effectId, duration ); effects.add( effect ); } return effects; } public static boolean processResults( boolean combatResults, String results ) { return ResultProcessor.processResults( combatResults, results, null ); } public static boolean processResults( boolean combatResults, String results, List<AdventureResult> data ) { ResultProcessor.receivedClover = false; ResultProcessor.receivedDisassembledClover = false; if ( data == null && RequestLogger.isDebugging() ) { RequestLogger.updateDebugLog( "Processing results..." ); } // If items are wrapped in a table with a "rel" string, that // precisely identifies what has been acquired. // // Pre-process all such matches and save them to a list of items. // Register new items. // Check multi-usability and plurals LinkedList<AdventureResult> items = new LinkedList<AdventureResult>(); results = ResultProcessor.processItems( combatResults, results, items ); // Process effects similarly, saving them to a list of effects. // Register new effects. LinkedList<AdventureResult> effects = ResultProcessor.parseEffects( results ); boolean requiresRefresh = false; try { requiresRefresh = processNormalResults( combatResults, results, data, items, effects ); } finally { if ( data == null ) { KoLmafia.applyEffects(); } } return requiresRefresh; } private static boolean processNormalResults( boolean combatResults, String results, List<AdventureResult> data, LinkedList<AdventureResult> items, LinkedList<AdventureResult> effects ) { // Whacky, whacky KoL can insert <head> sections within the <body> String body = KoLConstants.HEAD_PATTERN.matcher( results ).replaceAll( "" ); String plainTextResult = KoLConstants.ANYTAG_BUT_ITALIC_PATTERN.matcher( body ).replaceAll( KoLConstants.LINE_BREAK ); if ( data == null ) { ResultProcessor.processFamiliarWeightGain( plainTextResult ); } LinkedList<String> parsedResults = new LinkedList<String>( Arrays.asList( plainTextResult.split( KoLConstants.LINE_BREAK ) ) ); boolean shouldRefresh = false; while ( parsedResults.size() > 0 ) { shouldRefresh |= ResultProcessor.processNextResult( combatResults, parsedResults, data, items, effects ); } return shouldRefresh; } public static boolean processFamiliarWeightGain( final String results ) { if ( results.contains( "gains a pound" ) || // The following are Haiku results results.contains( "gained a pound" ) || results.contains( "puts on weight" ) || results.contains( "gaining weight" ) || // The following are Anapest results results.contains( "just got heavier" ) || results.contains( "put on some weight" ) ) { KoLCharacter.incrementFamilarWeight(); FamiliarData familiar = KoLCharacter.getFamiliar(); String fam1 = familiar.getName() + ", the " + familiar.getWeight() + " lb. " + familiar.getRace(); String message = "Your familiar gains a pound: " + fam1; RequestLogger.printLine( message ); RequestLogger.updateSessionLog( message ); return true; } return false; } private static boolean processNextResult( boolean combatResults, LinkedList<String> parsedResults, List<AdventureResult> data, LinkedList<AdventureResult> items, LinkedList<AdventureResult> effects ) { String lastToken = parsedResults.remove(); // Skip bogus lead necklace drops from the Baby Bugged Bugbear if ( lastToken.equals( " Parse error (function not found) in arena.php line 2225" ) ) { parsedResults.remove(); return false; } // Skip skill acquisition - it's followed by a boldface // which makes the parser think it's found an item. if ( lastToken.contains( "You acquire a skill" ) || lastToken.contains( "You learn a skill" ) || lastToken.contains( "You gain a skill" ) || lastToken.contains( "You have learned a skill" ) || lastToken.contains( "You acquire a new skill" ) ) { return false; } String acquisition = lastToken.trim(); if ( acquisition.startsWith( "You acquire an effect" ) || acquisition.startsWith( "You lose an effect" ) || acquisition.startsWith( "You lose some of an effect" ) ) { return ResultProcessor.processEffect( parsedResults, acquisition, data, effects ); } if ( acquisition.startsWith( "You acquire an intrinsic" ) || acquisition.startsWith( "You lose an intrinsic" ) ) { return ResultProcessor.processIntrinsic( parsedResults, acquisition, data ); } if ( acquisition.startsWith( "You acquire" ) ) { if ( acquisition.contains( "clan trophy" ) ) { return false; } ResultProcessor.processItem( combatResults, parsedResults, acquisition, data, items ); return false; } if ( lastToken.startsWith( "You gain" ) || lastToken.startsWith( "You lose " ) || lastToken.startsWith( "You spent " ) ) { // Chatty pirate message if ( lastToken.startsWith( "You lose your temper" ) ) { return false; } return ResultProcessor.processGainLoss( lastToken, data ); } if ( lastToken.startsWith( "You discard" ) ) { ResultProcessor.processDiscard( lastToken ); } return false; } private static void processItem( boolean combatResults, LinkedList<String> parsedResults, String acquisition, List<AdventureResult> data, LinkedList<AdventureResult> items ) { String item = parsedResults.remove(); if ( item.equals( "7 Years of Bad Luck" ) ) { return; } if ( item.equals( "Tales of the West: Cow Punching" ) ) { // Accommodate KoL bug: extra space in name item = "Tales of the West: Cow Punching"; } if ( acquisition.contains( "an item" ) ) { AdventureResult result = items.size() == 0 ? null : items.getFirst(); if ( result != null && item.equals( result.getName() ) ) { items.removeFirst(); ResultProcessor.processItem( combatResults, acquisition, result, data ); return; } result = ItemPool.get( item, 1 ); if ( result.getItemId() == -1 ) { RequestLogger.printLine( "Unrecognized item found: " + item ); } boolean autoEquip = parsedResults.size() > 0 && parsedResults.getFirst().contains( "automatically equipped" ); if ( autoEquip ) { // This happens in Spelunky parsedResults.remove(); acquisition = "You acquire and equip an item:"; } ResultProcessor.processItem( combatResults, acquisition, result, data ); if ( autoEquip ) { EquipmentManager.autoequipItem( result ); } return; } if ( acquisition.contains( "a bounty item" ) ) { // Bounty items are no longer real items return; } // The name of the item follows the number that appears after // the first index. int spaceIndex = item.indexOf( " " ); String countString = ""; String itemName; if ( spaceIndex != -1 ) { countString = item.substring( 0, spaceIndex ); itemName = item.substring( spaceIndex ).trim(); } else { itemName = item; } if ( !StringUtilities.isNumeric( countString ) ) { countString = "1"; itemName = item; } AdventureResult result = items.size() == 0 ? null : items.getFirst(); if ( result != null && itemName.equals( result.getName() ) ) { items.removeFirst(); ResultProcessor.processItem( combatResults, acquisition, result, data ); return; } int itemCount = StringUtilities.parseInt( countString ); // If we got more than one, do substring matching. This might // allow recognition of an unknown (or changed) plural form. int itemId = ItemDatabase.getItemId( itemName, itemCount, itemCount > 1 ); if ( itemId < 0 ) { RequestLogger.printLine( "Unrecognized item found: " + item ); result = AdventureResult.tallyItem( itemName, itemCount, false ); } else { result = ItemPool.get( itemId, itemCount ); if ( items.size() > 0 ) { AdventureResult first = items.getFirst(); if ( first.getName().equals( result.getName() ) ) { result = items.removeFirst(); } } } ResultProcessor.processItem( combatResults, acquisition, result, data ); } public static void processItem( boolean combatResults, String acquisition, AdventureResult result, List<AdventureResult> data ) { if ( data != null ) { AdventureResult.addResultToList( data, result ); return; } String message = acquisition + " " + result.toString(); RequestLogger.printLine( message ); if ( Preferences.getBoolean( "logAcquiredItems" ) ) { RequestLogger.updateSessionLog( message ); } ResultProcessor.processResult( combatResults, result ); } public static Pattern DURATION_PATTERN = Pattern.compile( "\\((?:duration: )?(\\d+) Adventures?\\)" ); private static boolean processEffect( LinkedList<String> parsedResults, String acquisition, List<AdventureResult> data, LinkedList<AdventureResult> effects ) { if ( data != null ) { return false; } String effectName = parsedResults.remove(); AdventureResult effect = effects.size() == 0 ? null : effects.getFirst(); if ( effect != null && effectName.equals( effect.getName() ) ) { effects.removeFirst(); return ResultProcessor.processEffect( false, acquisition, effect, data ); } int effectId = EffectDatabase.getEffectId( effectName ); int duration = 0; if ( acquisition.contains( "Adventures" ) ) { String lastToken = parsedResults.remove(); Matcher m = DURATION_PATTERN.matcher( lastToken ); if ( m.find() ) { duration = StringUtilities.parseInt( m.group(1) ); } if ( acquisition.startsWith( "You lose" ) ) { duration = -duration; } } effect = EffectPool.get( effectId, duration ); return ResultProcessor.processEffect( false, acquisition, effect, data ); } public static boolean processEffect( boolean combatResults, String acquisition, AdventureResult result, List<AdventureResult> data ) { if ( data != null ) { AdventureResult.addResultToList( data, result ); return false; } String message = acquisition + " " + result.getName() + " (" + result.getCount() + ")"; RequestLogger.printLine( message ); if ( Preferences.getBoolean( "logStatusEffects" ) ) { RequestLogger.updateSessionLog( message ); } return ResultProcessor.processResult( combatResults, result ); } private static boolean processIntrinsic( LinkedList<String> parsedResults, String acquisition, List<AdventureResult> data ) { if ( data != null ) { return false; } String effectName = parsedResults.remove(); String message = acquisition + " " + effectName; RequestLogger.printLine( message ); if ( Preferences.getBoolean( "logStatusEffects" ) ) { RequestLogger.updateSessionLog( message ); } int effectId = EffectDatabase.getEffectId( effectName ); AdventureResult result = EffectPool.get( effectId, Integer.MAX_VALUE ); if ( message.startsWith( "You lose" ) ) { AdventureResult.removeResultFromList( KoLConstants.activeEffects, result ); } else { KoLConstants.activeEffects.add( result ); LockableListFactory.sort( KoLConstants.activeEffects ); } return true; } public static boolean processGainLoss( String lastToken, final List<AdventureResult> data ) { int periodIndex = lastToken.indexOf( "." ); if ( periodIndex != -1 ) { lastToken = lastToken.substring( 0, periodIndex ); } int parenIndex = lastToken.indexOf( "(" ); if ( parenIndex != -1 ) { lastToken = lastToken.substring( 0, parenIndex ); } lastToken = lastToken.trim(); if ( lastToken.contains( "Meat" ) ) { return ResultProcessor.processMeat( lastToken, data ); } if ( data != null ) { return false; } if ( lastToken.startsWith( "You gain a" ) || lastToken.startsWith( "You gain some" ) ) { RequestLogger.printLine( lastToken ); if ( Preferences.getBoolean( "logStatGains" ) ) { RequestLogger.updateSessionLog( lastToken ); } // Update Hatter deed since new hats may now be equippable PreferenceListenerRegistry.firePreferenceChanged( "(hats)" ); return true; } return ResultProcessor.processStatGain( lastToken, data ); } private static boolean possibleMeatDrop( int drop, int bonus ) { double rate = (KoLCharacter.getMeatDropPercentAdjustment() + 100 + bonus) / 100.0; return Math.floor( Math.ceil( drop / rate ) * rate ) == drop; } public static boolean processMeat( String text, boolean won, boolean nunnery ) { AdventureResult result = ResultProcessor.parseResult( text ); if ( result == null ) { return true; } if ( won && nunnery ) { IslandManager.addNunneryMeat( result ); return false; } if ( won && Preferences.getBoolean( "meatDropSpading" ) ) { int drop = result.getCount(); if ( !ResultProcessor.possibleMeatDrop( drop, 0 ) ) { StringBuffer buf = new StringBuffer( "Alert - possible unknown meat bonus:" ); if ( KoLCharacter.currentNumericModifier( Modifiers.SPORADIC_MEATDROP ) != 0.0f ) { buf.append( " (sporadic!)" ); } if ( KoLCharacter.currentNumericModifier( Modifiers.MEAT_BONUS ) != 0.0f ) { buf.append( " (ant tool!)" ); } for ( int i = 1; i <= 100 && buf.length() < 80; ++i ) { if ( ResultProcessor.possibleMeatDrop( drop, i ) ) { buf.append( " +" ); buf.append( i ); } if ( ResultProcessor.possibleMeatDrop( drop, -i ) ) { buf.append( " -" ); buf.append( i ); } } RequestLogger.updateSessionLog( "Spade " + buf ); buf.insert( 0, "<font color=green>\u2660" ); buf.append( "</font>" ); RequestLogger.printLine( buf.toString() ); } } return ResultProcessor.processMeat( text, result, null ); } public static boolean processMeat( String lastToken, List<AdventureResult> data ) { AdventureResult result = ResultProcessor.parseResult( lastToken ); if ( result == null ) { return true; } return ResultProcessor.processMeat( lastToken, result, data ); } private static boolean processMeat( String lastToken, AdventureResult result, List<AdventureResult> data ) { if ( data != null ) { AdventureResult.addResultToList( data, result ); return false; } // KoL can tell you that you lose meat - Leprechaun theft, // chewing bug vendors, etc. - but you can only lose as much // meat as you actually have in inventory. int amount = result.getCount(); int available = KoLCharacter.getAvailableMeat(); if ( amount < 0 && -amount > available ) { amount = -available; lastToken = "You lose " + String.valueOf( -amount ) + " Meat"; result = new AdventureResult( AdventureResult.MEAT, amount ); } if ( amount == 0 ) { return false; } RequestLogger.printLine( lastToken ); if ( Preferences.getBoolean( "logGainMessages" ) ) { RequestLogger.updateSessionLog( lastToken ); } return ResultProcessor.processResult( result ); } public static boolean processStatGain( String lastToken, List<AdventureResult> data ) { if ( data != null ) { return false; } AdventureResult result = ResultProcessor.parseResult( lastToken ); if ( result == null ) { return true; } RequestLogger.printLine( lastToken ); if ( Preferences.getBoolean( "logStatGains" ) ) { RequestLogger.updateSessionLog( lastToken ); } return ResultProcessor.processResult( result ); } private static void processDiscard( String lastToken ) { Matcher matcher = ResultProcessor.DISCARD_PATTERN.matcher( lastToken ); if ( matcher.find() ) { AdventureResult item = ItemPool.get( matcher.group( 1 ), -1 ); AdventureResult.addResultToList( KoLConstants.inventory, item ); AdventureResult.addResultToList( KoLConstants.tally, item ); switch ( item.getItemId() ) { case ItemPool.INSTANT_KARMA: Preferences.increment( "bankedKarma", 11 ); break; } } } public static AdventureResult parseResult( String result ) { result = result.trim(); if ( RequestLogger.isDebugging() ) { RequestLogger.updateDebugLog( "Parsing result: " + result ); } try { AdventureResult retval = AdventureResult.parseResult( result ); // If AdventureResult could not parse it, log it if ( retval == null ) { String message = "Could not parse: " + StringUtilities.globalStringDelete( result, " " ); RequestLogger.printLine( message ); RequestLogger.updateSessionLog( message ); } return retval; } catch ( Exception e ) { // This should not happen. Therefore, print // a stack trace for debug purposes. StaticEntity.printStackTrace( e ); return null; } } /** * Utility. The method used to process a result. By default, this will * also add an adventure result to the tally. Use this whenever the * result is already known and no additional parsing is needed. * * @param result Result to add to the running tally of adventure results */ public static boolean processResult( AdventureResult result ) { return ResultProcessor.processResult( false, result ); } public static boolean processResult( boolean combatResults, AdventureResult result ) { // This should not happen, but punt if the result was null. if ( result == null ) { return false; } if ( RequestLogger.isDebugging() ) { RequestLogger.updateDebugLog( "Processing result: " + result ); } String resultName = result.getName(); boolean shouldRefresh = false; // Process the adventure result in this section; if // it's a status effect, then add it to the recent // effect list. Otherwise, add it to the tally. if ( result.isItem() ) { AdventureResult.addResultToList( KoLConstants.tally, result ); } else if ( result.isStatusEffect() ) { int active = result.getCount( KoLConstants.activeEffects ); int duration = result.getCount(); shouldRefresh |= duration > 0 ? active == 0 : active == duration; AdventureResult.addResultToList( KoLConstants.recentEffects, result ); } else if ( resultName.equals( AdventureResult.SUBSTATS ) ) { // Update substat delta and fullstat delta, if necessary int [] counts = result.getCounts(); // Update AdventureResult.SESSION_SUBSTATS in place // Update AdventureResult.SESSION_FULLSTATS in place boolean substatChanged = false; boolean fullstatChanged = false; int count = counts[ 0 ]; if ( count != 0 ) { long stat = KoLCharacter.getTotalMuscle(); long diff = KoLCharacter.calculateBasePoints( stat + count ) - KoLCharacter.calculateBasePoints( stat ); AdventureResult.SESSION_SUBSTATS[ 0 ] += count; AdventureResult.SESSION_FULLSTATS[ 0 ] += diff; substatChanged = true; fullstatChanged |= ( diff != 0 ); } count = counts[ 1 ]; if ( count != 0 ) { long stat = KoLCharacter.getTotalMysticality(); long diff = KoLCharacter.calculateBasePoints( stat + count ) - KoLCharacter.calculateBasePoints( stat ); AdventureResult.SESSION_SUBSTATS[ 1 ] += count; AdventureResult.SESSION_FULLSTATS[ 1 ] += diff; substatChanged = true; fullstatChanged |= ( diff != 0 ); } count = counts[ 2 ]; if ( count != 0 ) { long stat = KoLCharacter.getTotalMoxie(); long diff = KoLCharacter.calculateBasePoints( stat + count ) - KoLCharacter.calculateBasePoints( stat ); AdventureResult.SESSION_SUBSTATS[ 2 ] += count; AdventureResult.SESSION_FULLSTATS[ 2 ] += diff; substatChanged = true; fullstatChanged |= ( diff != 0 ); } int size = KoLConstants.tally.size(); if ( substatChanged && size > 2 ) { LockableListFactory.fireContentsChanged( KoLConstants.tally, 2, 2 ); } if ( fullstatChanged ) { shouldRefresh = true; if ( size > 3 ) { LockableListFactory.fireContentsChanged( KoLConstants.tally, 3, 3 ); } } } else if ( resultName.equals( AdventureResult.MEAT ) ) { AdventureResult.addResultToList( KoLConstants.tally, result ); KoLCharacter.incrementSessionMeat( result.getCount() ); shouldRefresh = true; } else if ( resultName.equals( AdventureResult.ADV ) ) { if ( result.getCount() < 0 ) { TurnCounter.saveCounters(); AdventureResult.addResultToList( KoLConstants.tally, result.getNegation() ); } } else if ( resultName.equals( AdventureResult.CHOICE ) ) { // Don't let ignored choices delay iteration KoLmafia.tookChoice = true; } ResultProcessor.tallyResult( result, true ); if ( result.isItem() ) { // Do special processing when you get certain items ResultProcessor.gainItem( combatResults, result ); if ( GenericRequest.isBarrelSmash ) { BarrelDecorator.gainItem( result ); } if ( HermitRequest.isWorthlessItem( result.getItemId() ) ) { result = HermitRequest.WORTHLESS_ITEM.getInstance( result.getCount() ); } return false; } if ( result.isStatusEffect() ) { switch ( result.getEffectId() ) { case EffectPool.GARISH: // If you gain or lose Gar-ish, and autoGarish // not set, benefit of Lasagna changes if ( !Preferences.getBoolean( "autoGarish" ) ) { ConcoctionDatabase.setRefreshNeeded( true ); } break; case EffectPool.INIGOS: case EffectPool.CRAFT_TEA: // If you gain or lose Inigo's or Craft Tea, what you can // craft changes ConcoctionDatabase.setRefreshNeeded( true ); break; case EffectPool.RECORD_HUNGER: case EffectPool.DRUNK_AVUNCULAR: case EffectPool.BARREL_OF_LAUGHS: case EffectPool.BEER_BARREL_POLKA: // Turn generation from food and booze changes ConcoctionDatabase.setRefreshNeeded( true ); break; case EffectPool.CHILLED_TO_THE_BONE: int duration = result.getCount(); if ( duration <= 0 ) break; Preferences.setInteger( "_chilledToTheBone", (int) Math.pow( 3, duration ) ); break; } return shouldRefresh; } GoalManager.updateProgress( result ); return shouldRefresh; } public static boolean processItem( int itemId, int count ) { return ResultProcessor.processResult( ItemPool.get( itemId, count ) ); } public static void removeItem( int itemId ) { AdventureResult ar = ItemPool.get( itemId, -1 ); if ( KoLConstants.inventory.contains( ar ) ) { ResultProcessor.processResult( ar ); } } public static void removeAllItems( int itemId ) { int count = InventoryManager.getCount( itemId ); if ( count > 0 ) { AdventureResult ar = ItemPool.get( itemId, -count ); ResultProcessor.processResult( ar ); } } public static boolean processMeat( int amount ) { return ResultProcessor.processResult( new AdventureResult( AdventureResult.MEAT, amount ) ); } public static void processAdventuresLeft( int amount ) { if ( amount != 0 ) { KoLCharacter.setAdventuresLeft( KoLCharacter.getAdventuresLeft() + amount ); } } public static void processAdventuresUsed( int amount ) { if ( amount != 0 ) { ResultProcessor.processResult( new AdventureResult( AdventureResult.ADV, -amount ) ); } } /** * Processes a result received through adventuring. This places items * inside of inventories and lots of other good stuff. */ public static final void tallyResult( final AdventureResult result, final boolean updateCalculatedLists ) { // Treat the result as normal from this point forward. // Figure out which list the result should be added to // and add it to that list. String resultName = result.getName(); if ( resultName == null ) { return; } if ( result.isItem() ) { // Certain items that you "gain" don't really enter inventory switch (result.getItemId() ) { case ItemPool.CHATEAU_MUSCLE: case ItemPool.CHATEAU_MYST: case ItemPool.CHATEAU_MOXIE: case ItemPool.CHATEAU_FAN: case ItemPool.CHATEAU_CHANDELIER: case ItemPool.CHATEAU_SKYLIGHT: case ItemPool.CHATEAU_BANK: case ItemPool.CHATEAU_JUICE_BAR: ChateauRequest.gainItem( result ); return; } AdventureResult.addResultToList( KoLConstants.inventory, result ); if ( updateCalculatedLists ) { EquipmentManager.processResult( result ); ConcoctionDatabase.setRefreshNeeded( result.getItemId() ); } } else if ( resultName.equals( AdventureResult.HP ) ) { KoLCharacter.setHP( KoLCharacter.getCurrentHP() + result.getCount(), KoLCharacter.getMaximumHP(), KoLCharacter.getBaseMaxHP() ); } else if ( resultName.equals( AdventureResult.MP ) ) { KoLCharacter.setMP( KoLCharacter.getCurrentMP() + result.getCount(), KoLCharacter.getMaximumMP(), KoLCharacter.getBaseMaxMP() ); } else if ( resultName.equals( AdventureResult.MEAT ) ) { KoLCharacter.setAvailableMeat( KoLCharacter.getAvailableMeat() + result.getCount() ); if ( updateCalculatedLists ) { ConcoctionDatabase.setRefreshNeeded( false ); } } else if ( resultName.equals( AdventureResult.ADV ) ) { if ( result.getCount() < 0 ) { AdventureResult[] effectsArray = new AdventureResult[ KoLConstants.activeEffects.size() ]; KoLConstants.activeEffects.toArray( effectsArray ); for ( int i = effectsArray.length - 1; i >= 0; --i ) { AdventureResult effect = effectsArray[ i ]; int duration = effect.getCount(); if ( duration == Integer.MAX_VALUE ) { // Intrinsic effect } else if ( KoLCharacter.getClassType() == KoLCharacter.COWPUNCHER && effect.getEffectId() == EffectPool.COWRRUPTION ) { // Does not decrement } else if ( duration + result.getCount() <= 0 ) { KoLConstants.activeEffects.remove( i ); // If you lose Inigo's or Craft Tea, what you can craft changes int effectId = effect.getEffectId(); if ( effectId == EffectPool.INIGOS || effectId == EffectPool.CRAFT_TEA ) { ConcoctionDatabase.setRefreshNeeded( true ); } } else { KoLConstants.activeEffects.set( i, effect.getInstance( effect.getCount() + result.getCount() ) ); } } KoLCharacter.setCurrentRun( KoLCharacter.getCurrentRun() - result.getCount() ); } } else if ( resultName.equals( AdventureResult.DRUNK ) ) { KoLCharacter.setInebriety( KoLCharacter.getInebriety() + result.getCount() ); } else if ( resultName.equals( AdventureResult.FULL ) ) { KoLCharacter.setFullness( KoLCharacter.getFullness() + result.getCount() ); } else if ( resultName.equals( AdventureResult.SUBSTATS ) ) { if ( result.isMuscleGain() ) { KoLCharacter.incrementTotalMuscle( result.getCount() ); } else if ( result.isMysticalityGain() ) { KoLCharacter.incrementTotalMysticality( result.getCount() ); } else if ( result.isMoxieGain() ) { KoLCharacter.incrementTotalMoxie( result.getCount() ); } } else if ( resultName.equals( AdventureResult.PVP ) ) { KoLCharacter.setAttacksLeft( KoLCharacter.getAttacksLeft() + result.getCount() ); } } private static void gainItem( boolean combatResults, AdventureResult result ) { int itemId = result.getItemId(); int count = result.getCount(); ConcoctionDatabase.setRefreshNeeded( itemId ); // All results, whether positive or negative, are // handled here. switch ( itemId ) { case ItemPool.GG_TICKET: case ItemPool.SNACK_VOUCHER: case ItemPool.LUNAR_ISOTOPE: case ItemPool.ODD_SILVER_COIN: case ItemPool.BEACH_BUCK: case ItemPool.WORTHLESS_TRINKET: case ItemPool.WORTHLESS_GEWGAW: case ItemPool.WORTHLESS_KNICK_KNACK: case ItemPool.YETI_FUR: case ItemPool.LUCRE: case ItemPool.SAND_DOLLAR: case ItemPool.CRIMBUCK: case ItemPool.BONE_CHIPS: case ItemPool.CRIMBCO_SCRIP: case ItemPool.AWOL_COMMENDATION: case ItemPool.MR_ACCESSORY: case ItemPool.UNCLE_BUCK: case ItemPool.FAT_LOOT_TOKEN: case ItemPool.FUDGECULE: case ItemPool.FDKOL_COMMENDATION: case ItemPool.WARBEAR_WHOSIT: case ItemPool.KRUEGERAND: case ItemPool.SHIP_TRIP_SCRIP: case ItemPool.CHRONER: case ItemPool.BURT: case ItemPool.FRESHWATER_FISHBONE: case ItemPool.CRIMBO_CREDIT: case ItemPool.TOPIARY_NUGGLET: case ItemPool.FUNFUNDS: case ItemPool.TOXIC_GLOBULE: case ItemPool.VOLCOINO: case ItemPool.BACON: case ItemPool.COP_DOLLAR: case ItemPool.PRICELESS_DIAMOND: // Pulverized ascension rewards case ItemPool.WICKERBITS: case ItemPool.BAKELITE_BITS: // BatFellow currencies case ItemPool.INCRIMINATING_EVIDENCE: case ItemPool.DANGEROUS_CHEMICALS: case ItemPool.KIDNAPPED_ORPHAN: case ItemPool.HIGH_GRADE_METAL: case ItemPool.HIGH_TENSILE_STRENGTH_FIBERS: case ItemPool.HIGH_GRADE_EXPLOSIVES: // The Traveling Trader usually wants twinkly wads case ItemPool.TWINKLY_WAD: // You can trade tokens for tickets case ItemPool.GG_TOKEN: // You can go to spaaace with a transponder case ItemPool.TRANSPORTER_TRANSPONDER: NamedListenerRegistry.fireChange( "(coinmaster)" ); break; case ItemPool.FAKE_HAND: NamedListenerRegistry.fireChange( "(fakehands)" ); break; case ItemPool.BLACK_BARTS_BOOTY: // Whether you just got Black Bart's booty or just used // it to get the skill, you ain't gettin' another this season. Preferences.setBoolean( "blackBartsBootyAvailable", false ); break; case ItemPool.HOLIDAY_FUN_BOOK: Preferences.setBoolean( "holidayHalsBookAvailable", false ); break; case ItemPool.ANTAGONISTIC_SNOWMAN_KIT: Preferences.setBoolean( "antagonisticSnowmanKitAvailable", false ); break; case ItemPool.MAP_TO_KOKOMO: Preferences.setBoolean( "mapToKokomoAvailable", false ); break; case ItemPool.ESSENCE_OF_BEAR: Preferences.setBoolean( "essenceOfBearAvailable", false ); break; case ItemPool.MANUAL_OF_NUMBEROLOGY: Preferences.setBoolean( "manualOfNumberologyAvailable", false ); break; case ItemPool.ROM_OF_OPTIMALITY: Preferences.setBoolean( "ROMOfOptimalityAvailable", false ); break; case ItemPool.SCHOOL_OF_HARD_KNOCKS_DIPLOMA: Preferences.setBoolean( "schoolOfHardKnocksDiplomaAvailable", false ); break; } if ( ItemDatabase.isCandyItem( itemId ) ) { NamedListenerRegistry.fireChange( "(candy)" ); } // From here on out, only positive results are handled. if ( count < 0 ) { return; } if ( EquipmentDatabase.isHat( result ) ) { PreferenceListenerRegistry.firePreferenceChanged( "(hats)" ); } switch ( itemId ) { case ItemPool.GMOB_POLLEN: if ( combatResults ) { // Record that we beat the guy made of bees. Preferences.setBoolean( "guyMadeOfBeesDefeated", true ); } break; case ItemPool.ROASTED_MARSHMALLOW: // Special Yuletide adventures if ( KoLAdventure.lastAdventureId() == AdventurePool.YULETIDE ) { ResultProcessor.removeItem( ItemPool.MARSHMALLOW ); } break; // Sticker weapons may have been folded from the other form case ItemPool.STICKER_SWORD: ResultProcessor.removeItem( ItemPool.STICKER_CROSSBOW ); break; case ItemPool.STICKER_CROSSBOW: ResultProcessor.removeItem( ItemPool.STICKER_SWORD ); break; case ItemPool.MOSQUITO_LARVA: QuestDatabase.setQuestProgress( Quest.LARVA, "step1" ); break; case ItemPool.BITCHIN_MEATCAR: case ItemPool.DESERT_BUS_PASS: case ItemPool.PUMPKIN_CARRIAGE: case ItemPool.TIN_LIZZIE: // Desert beach unlocked KoLCharacter.setDesertBeachAvailable(); break; case ItemPool.RUSTY_SCREWDRIVER: QuestDatabase.setQuestProgress( Quest.UNTINKER, "step1" ); break; case ItemPool.JUNK_JUNK: QuestDatabase.setQuestProgress( Quest.HIPPY, "step3" ); break; case ItemPool.DINGY_DINGHY: case ItemPool.SKIFF: case ItemPool.YELLOW_SUBMARINE: // Island unlocked Preferences.setInteger( "lastIslandUnlock", KoLCharacter.getAscensions() ); break; case ItemPool.TISSUE_PAPER_IMMATERIA: QuestDatabase.setQuestProgress( Quest.GARBAGE, "step3" ); break; case ItemPool.TIN_FOIL_IMMATERIA: QuestDatabase.setQuestProgress( Quest.GARBAGE, "step4" ); break; case ItemPool.GAUZE_IMMATERIA: QuestDatabase.setQuestProgress( Quest.GARBAGE, "step5" ); break; case ItemPool.PLASTIC_WRAP_IMMATERIA: QuestDatabase.setQuestProgress( Quest.GARBAGE, "step6" ); break; case ItemPool.SOCK: // If you get a S.O.C.K., you lose all the Immateria ResultProcessor.processItem( ItemPool.TISSUE_PAPER_IMMATERIA, -1 ); ResultProcessor.processItem( ItemPool.TIN_FOIL_IMMATERIA, -1 ); ResultProcessor.processItem( ItemPool.GAUZE_IMMATERIA, -1 ); ResultProcessor.processItem( ItemPool.PLASTIC_WRAP_IMMATERIA, -1 ); QuestDatabase.setQuestProgress( Quest.GARBAGE, "step7" ); break; case ItemPool.BROKEN_WINGS: case ItemPool.SUNKEN_EYES: // Make the blackbird so you don't need to have the familiar with you ResultProcessor.autoCreate( ItemPool.REASSEMBLED_BLACKBIRD ); break; case ItemPool.BUSTED_WINGS: case ItemPool.BIRD_BRAIN: // Make the Crow so you don't need to have the familiar with you ResultProcessor.autoCreate( ItemPool.RECONSTITUTED_CROW ); break; case ItemPool.PIRATE_FLEDGES: QuestDatabase.setQuestProgress( Quest.PIRATE, "step6"); break; case ItemPool.MACGUFFIN_DIARY: case ItemPool.ED_DIARY: // If you get your father's MacGuffin diary, you lose // your forged identification documents ResultProcessor.processItem( ItemPool.FORGED_ID_DOCUMENTS, -1 ); QuestDatabase.setQuestProgress( Quest.BLACK, "step3" ); // Automatically use the diary to open zones if ( Preferences.getBoolean( "autoQuest" ) ) { RequestThread.postRequest( UseItemRequest.getInstance( result ) ); } break; case ItemPool.VOLCANO_MAP: // A counter was made in case we lost the fight against the // final assassin, but since this dropped we won the fight TurnCounter.stopCounting( "Nemesis Assassin window begin" ); TurnCounter.stopCounting( "Nemesis Assassin window end" ); QuestDatabase.setQuestProgress( Quest.NEMESIS, "step25" ); // Automatically use the map to open zones if ( Preferences.getBoolean( "autoQuest" ) ) { RequestThread.postRequest( UseItemRequest.getInstance( result ) ); } break; case ItemPool.FIRST_PIZZA: case ItemPool.LACROSSE_STICK: case ItemPool.EYE_OF_THE_STARS: case ItemPool.STANKARA_STONE: case ItemPool.MURPHYS_FLAG: case ItemPool.SHIELD_OF_BROOK: QuestDatabase.advanceQuest( Quest.SHEN ); break; case ItemPool.PALINDROME_BOOK_2: // If you get "2 Love Me, Vol. 2", you lose // the items you put on the shelves ResultProcessor.processItem( ItemPool.PHOTOGRAPH_OF_GOD, -1 ); ResultProcessor.processItem( ItemPool.PHOTOGRAPH_OF_RED_NUGGET, -1 ); ResultProcessor.processItem( ItemPool.PHOTOGRAPH_OF_OSTRICH_EGG, -1 ); ResultProcessor.processItem( ItemPool.PHOTOGRAPH_OF_DOG, -1 ); QuestDatabase.setQuestIfBetter( Quest.PALINDOME, "step1" ); break; case ItemPool.WET_STUNT_NUT_STEW: // If you have been asked to get the stew, you now have it. if ( QuestDatabase.isQuestStep( Quest.PALINDOME, "step3" ) ) { QuestDatabase.setQuestProgress( Quest.PALINDOME, "step4" ); } break; case ItemPool.MEGA_GEM: // If you get the Mega Gem, you lose your wet stunt nut // stew ResultProcessor.processItem( ItemPool.WET_STUNT_NUT_STEW, -1 ); QuestDatabase.setQuestIfBetter( Quest.PALINDOME, "step5" ); break; case ItemPool.HOLY_MACGUFFIN: QuestDatabase.setQuestProgress( Quest.PYRAMID, QuestDatabase.FINISHED ); break; case ItemPool.CONFETTI: // If you get the confetti, you lose the Holy MacGuffin if ( KoLConstants.inventory.contains( ItemPool.get( ItemPool.HOLY_MACGUFFIN, 1 ) ) ) { ResultProcessor.processItem( ItemPool.HOLY_MACGUFFIN, -1 ); QuestDatabase.setQuestProgress( Quest.PYRAMID, QuestDatabase.FINISHED ); QuestDatabase.setQuestProgress( Quest.MANOR, QuestDatabase.FINISHED ); QuestDatabase.setQuestProgress( Quest.WORSHIP, QuestDatabase.FINISHED ); QuestDatabase.setQuestProgress( Quest.PALINDOME, QuestDatabase.FINISHED ); QuestDatabase.setQuestProgress( Quest.MACGUFFIN, QuestDatabase.FINISHED ); } break; case ItemPool.MORTAR_DISSOLVING_RECIPE: QuestDatabase.setQuestIfBetter( Quest.MANOR, "step2" ); if ( Preferences.getBoolean( "autoQuest" ) ) { boolean equipSpecs = KoLConstants.inventory.contains( ItemPool.get( ItemPool.SPOOKYRAVEN_SPECTACLES, 1 ) ); if ( equipSpecs ) { SpecialOutfit.createImplicitCheckpoint(); RequestThread.postRequest( new EquipmentRequest( ItemPool.get( ItemPool.SPOOKYRAVEN_SPECTACLES, 1 ), EquipmentManager.ACCESSORY3 ) ); } RequestThread.postRequest( UseItemRequest.getInstance( ItemPool.MORTAR_DISSOLVING_RECIPE ) ); if ( equipSpecs ) { SpecialOutfit.restoreImplicitCheckpoint(); } boolean hasSpecs = equipSpecs || KoLCharacter.hasEquipped( ItemPool.get( ItemPool.SPOOKYRAVEN_SPECTACLES, 1 ) ); KoLmafia.updateDisplay( "Mortar-dissolving recipe used with Lord Spookyraven's spectacles " + ( hasSpecs ? "" : "NOT " ) + "equipped." ); // Ugly hacky fix for the above UseItemRequest for some reason not triggering the code there if ( hasSpecs ) { Preferences.setString( "spookyravenRecipeUsed", "with_glasses" ); } else { Preferences.setString( "spookyravenRecipeUsed", "no_glasses" ); } } break; case ItemPool.MOLYBDENUM_MAGNET: // When you get the molybdenum magnet, tell quest handler IslandManager.startJunkyardQuest(); break; case ItemPool.MOLYBDENUM_HAMMER: case ItemPool.MOLYBDENUM_SCREWDRIVER: case ItemPool.MOLYBDENUM_PLIERS: case ItemPool.MOLYBDENUM_WRENCH: // When you get a molybdenum item, tell quest handler IslandManager.resetGremlinTool(); break; case ItemPool.SPOOKY_BICYCLE_CHAIN: if ( combatResults ) QuestDatabase.setQuestIfBetter( Quest.BUGBEAR, "step3" ); break; case ItemPool.RONALD_SHELTER_MAP: case ItemPool.GRIMACE_SHELTER_MAP: QuestDatabase.setQuestIfBetter( Quest.GENERATOR, "step1" ); break; case ItemPool.SPOOKY_LITTLE_GIRL: QuestDatabase.setQuestIfBetter( Quest.GENERATOR, "step2" ); break; case ItemPool.EMU_UNIT: // If you get an E.M.U. Unit, you lose all the E.M.U. parts ResultProcessor.processItem( ItemPool.EMU_JOYSTICK, -1 ); ResultProcessor.processItem( ItemPool.EMU_ROCKET, -1 ); ResultProcessor.processItem( ItemPool.EMU_HELMET, -1 ); ResultProcessor.processItem( ItemPool.EMU_HARNESS, -1 ); QuestDatabase.setQuestIfBetter( Quest.GENERATOR, "step3" ); break; case ItemPool.OVERCHARGED_POWER_SPHERE: case ItemPool.EL_VIBRATO_HELMET: case ItemPool.EL_VIBRATO_SPEAR: case ItemPool.EL_VIBRATO_PANTS: if ( combatResults ) ResultProcessor.removeItem( ItemPool.POWER_SPHERE ); break; case ItemPool.BROKEN_DRONE: if ( combatResults ) ResultProcessor.removeItem( ItemPool.DRONE ); break; case ItemPool.REPAIRED_DRONE: if ( combatResults ) ResultProcessor.removeItem( ItemPool.BROKEN_DRONE ); break; case ItemPool.AUGMENTED_DRONE: if ( combatResults ) ResultProcessor.removeItem( ItemPool.REPAIRED_DRONE ); break; case ItemPool.TRAPEZOID: ResultProcessor.removeItem( ItemPool.POWER_SPHERE ); break; case ItemPool.CITADEL_SATCHEL: ResultProcessor.processMeat( -300 ); break; case ItemPool.LUCKY_RABBIT_FOOT: if ( RequestLogger.getLastURLString().startsWith( "guild.php" ) ) { QuestDatabase.setQuestIfBetter( Quest.CITADEL, QuestDatabase.FINISHED ); } break; case ItemPool.HAROLDS_BELL: ResultProcessor.processItem( ItemPool.HAROLDS_HAMMER, -1 ); break; // These update the session results for the item swapping in // the Gnome's Going Postal quest. case ItemPool.REALLY_BIG_TINY_HOUSE: ResultProcessor.processItem( ItemPool.RED_PAPER_CLIP, -1 ); break; case ItemPool.NONESSENTIAL_AMULET: ResultProcessor.processItem( ItemPool.REALLY_BIG_TINY_HOUSE, -1 ); break; case ItemPool.WHITE_WINE_VINAIGRETTE: ResultProcessor.processItem( ItemPool.NONESSENTIAL_AMULET, -1 ); break; case ItemPool.CURIOUSLY_SHINY_AX: ResultProcessor.processItem( ItemPool.WHITE_WINE_VINAIGRETTE, -1 ); break; case ItemPool.CUP_OF_STRONG_TEA: ResultProcessor.processItem( ItemPool.CURIOUSLY_SHINY_AX, -1 ); break; case ItemPool.MARINATED_STAKES: ResultProcessor.processItem( ItemPool.CUP_OF_STRONG_TEA, -1 ); break; case ItemPool.KNOB_BUTTER: ResultProcessor.processItem( ItemPool.MARINATED_STAKES, -1 ); break; case ItemPool.VIAL_OF_ECTOPLASM: ResultProcessor.processItem( ItemPool.KNOB_BUTTER, -1 ); break; case ItemPool.BOOCK_OF_MAGIKS: ResultProcessor.processItem( ItemPool.VIAL_OF_ECTOPLASM, -1 ); break; case ItemPool.EZ_PLAY_HARMONICA_BOOK: ResultProcessor.processItem( ItemPool.BOOCK_OF_MAGIKS, -1 ); break; case ItemPool.FINGERLESS_HOBO_GLOVES: ResultProcessor.processItem( ItemPool.EZ_PLAY_HARMONICA_BOOK, -1 ); break; case ItemPool.CHOMSKYS_COMICS: ResultProcessor.processItem( ItemPool.FINGERLESS_HOBO_GLOVES, -1 ); break; case ItemPool.GNOME_DEMODULIZER: ResultProcessor.removeItem( ItemPool.CHOMSKYS_COMICS ); break; case ItemPool.SHOPPING_LIST: QuestDatabase.setQuestIfBetter( Quest.MEATCAR, QuestDatabase.STARTED ); break; case ItemPool.MUS_MANUAL: case ItemPool.MYS_MANUAL: case ItemPool.MOX_MANUAL: ResultProcessor.processItem( ItemPool.DUSTY_BOOK, -1 ); ResultProcessor.processItem( ItemPool.FERNSWARTHYS_KEY, -1 ); break; case ItemPool.FRATHOUSE_BLUEPRINTS: ResultProcessor.processItem( ItemPool.CARONCH_MAP, -1 ); ResultProcessor.processItem( ItemPool.CARONCH_NASTY_BOOTY, -1 ); QuestDatabase.setQuestIfBetter( Quest.PIRATE, "step2" ); break; case ItemPool.CARONCH_DENTURES: QuestDatabase.setQuestIfBetter( Quest.PIRATE, "step3" ); break; case ItemPool.TEN_LEAF_CLOVER: ResultProcessor.receivedClover = true; break; case ItemPool.DISASSEMBLED_CLOVER: ResultProcessor.receivedDisassembledClover = true; break; case ItemPool.EXORCISED_SANDWICH: QuestDatabase.setQuestProgress( Quest.MYST, "step1" ); break; case ItemPool.BIG_KNOB_SAUSAGE: QuestDatabase.setQuestProgress( Quest.MUSCLE, "step1" ); break; case ItemPool.BATSKIN_BELT: if ( combatResults ) { QuestDatabase.setQuestProgress( Quest.BAT, "step4" ); ResultProcessor.autoCreate( ItemPool.BADASS_BELT ); } break; case ItemPool.KNOB_GOBLIN_CROWN: case ItemPool.KNOB_GOBLIN_BALLS: case ItemPool.KNOB_GOBLIN_CODPIECE: if ( combatResults ) { QuestDatabase.setQuestProgress( Quest.GOBLIN, QuestDatabase.FINISHED ); } break; case ItemPool.DODECAGRAM: if ( KoLConstants.inventory.contains( ItemPool.get( ItemPool.CANDLES, 1 ) ) && KoLConstants.inventory.contains( ItemPool.get( ItemPool.BUTTERKNIFE, 1 ) ) ) { QuestDatabase.setQuestProgress( Quest.FRIAR, "step2" ); } break; case ItemPool.CANDLES: if ( KoLConstants.inventory.contains( ItemPool.get( ItemPool.DODECAGRAM, 1 ) ) && KoLConstants.inventory.contains( ItemPool.get( ItemPool.BUTTERKNIFE, 1 ) ) ) { QuestDatabase.setQuestProgress( Quest.FRIAR, "step2" ); } break; case ItemPool.BUTTERKNIFE: if ( KoLConstants.inventory.contains( ItemPool.get( ItemPool.DODECAGRAM, 1 ) ) && KoLConstants.inventory.contains( ItemPool.get( ItemPool.CANDLES, 1 ) ) ) { QuestDatabase.setQuestProgress( Quest.FRIAR, "step2" ); } break; case ItemPool.BONERDAGON_CHEST: QuestDatabase.setQuestProgress( Quest.CYRPT, "step1" ); break; case ItemPool.BONERDAGON_SKULL: if ( combatResults ) { QuestDatabase.setQuestProgress( Quest.CYRPT, QuestDatabase.FINISHED ); ResultProcessor.autoCreate( ItemPool.BADASS_BELT ); } break; case ItemPool.GROARS_FUR: case ItemPool.WINGED_YETI_FUR: QuestDatabase.setQuestProgress( Quest.TRAPPER, "step5" ); break; case ItemPool.MISTY_CLOAK: case ItemPool.MISTY_ROBE: case ItemPool.MISTY_CAPE: if ( RequestLogger.getLastURLString().contains( "action=highlands_dude" ) ) { QuestDatabase.setQuestProgress( Quest.TOPPING, QuestDatabase.FINISHED ); QuestDatabase.setQuestProgress( Quest.LOL, QuestDatabase.STARTED ); Preferences.setInteger( "booPeakProgress", 0 ); Preferences.setInteger( "twinPeakProgress", 15 ); Preferences.setInteger( "oilPeakProgress", 0 ); } break; case ItemPool.HEMP_STRING: case ItemPool.BONERDAGON_VERTEBRA: ResultProcessor.autoCreate( ItemPool.BONERDAGON_NECKLACE ); break; case ItemPool.SNAKEHEAD_CHARM: if ( result.getCount( KoLConstants.inventory ) >= 2 && !InventoryManager.hasItem( ItemPool.TALISMAN ) ) { ResultProcessor.autoCreate( ItemPool.TALISMAN ); } break; case ItemPool.COPPERHEAD_CHARM: case ItemPool.COPPERHEAD_CHARM_RAMPANT: if ( InventoryManager.hasItem( ItemPool.COPPERHEAD_CHARM ) ) { QuestDatabase.setQuestProgress( Quest.SHEN, QuestDatabase.FINISHED ); } if ( InventoryManager.hasItem( ItemPool.COPPERHEAD_CHARM_RAMPANT ) ) { QuestDatabase.setQuestProgress( Quest.RON, QuestDatabase.FINISHED ); } if ( InventoryManager.hasItem( ItemPool.COPPERHEAD_CHARM ) && InventoryManager.hasItem( ItemPool.COPPERHEAD_CHARM_RAMPANT ) && !InventoryManager.hasItem( ItemPool.TALISMAN ) ) { Concoction conc = new Concoction( ItemPool.get( ItemPool.TALISMAN, 1 ), CraftingType.ACOMBINE, EnumSet.noneOf( KoLConstants.CraftingRequirements.class ), EnumSet.noneOf( KoLConstants.CraftingMisc.class ), 0 ); conc.addIngredient( ItemPool.get( ItemPool.COPPERHEAD_CHARM, 1 ) ); conc.addIngredient( ItemPool.get( ItemPool.COPPERHEAD_CHARM_RAMPANT, 1 ) ); ConcoctionPool.set( conc ); ResultProcessor.autoCreate( ItemPool.TALISMAN ); } break; case ItemPool.EYE_OF_ED: QuestDatabase.setQuestProgress( Quest.MANOR, QuestDatabase.FINISHED ); break; case ItemPool.MCCLUSKY_FILE_PAGE5: ResultProcessor.autoCreate( ItemPool.MCCLUSKY_FILE ); break; case ItemPool.MOSS_COVERED_STONE_SPHERE: Preferences.setInteger( "hiddenApartmentProgress", 7 ); QuestDatabase.setQuestProgress( Quest.CURSES, QuestDatabase.FINISHED ); if ( QuestDatabase.isQuestFinished( Quest.DOCTOR ) && QuestDatabase.isQuestFinished( Quest.BUSINESS ) && QuestDatabase.isQuestFinished( Quest.SPARE ) ) { QuestDatabase.setQuestProgress( Quest.WORSHIP, "step4" ); } break; case ItemPool.DRIPPING_STONE_SPHERE: Preferences.setInteger( "hiddenHospitalProgress", 7 ); QuestDatabase.setQuestProgress( Quest.DOCTOR, QuestDatabase.FINISHED ); if ( QuestDatabase.isQuestFinished( Quest.CURSES ) && QuestDatabase.isQuestFinished( Quest.BUSINESS ) && QuestDatabase.isQuestFinished( Quest.SPARE ) ) { QuestDatabase.setQuestProgress( Quest.WORSHIP, "step4" ); } break; case ItemPool.CRACKLING_STONE_SPHERE: // Lose McClusky File when you kill the Protector Spirit ResultProcessor.processItem( ItemPool.MCCLUSKY_FILE, -1 ); Preferences.setInteger( "hiddenOfficeProgress", 7 ); QuestDatabase.setQuestProgress( Quest.BUSINESS, QuestDatabase.FINISHED ); if ( QuestDatabase.isQuestFinished( Quest.CURSES ) && QuestDatabase.isQuestFinished( Quest.DOCTOR ) && QuestDatabase.isQuestFinished( Quest.SPARE ) ) { QuestDatabase.setQuestProgress( Quest.WORSHIP, "step4" ); } break; case ItemPool.SCORCHED_STONE_SPHERE: Preferences.setInteger( "hiddenBowlingAlleyProgress", 7 ); QuestDatabase.setQuestProgress( Quest.SPARE, QuestDatabase.FINISHED ); if ( QuestDatabase.isQuestFinished( Quest.CURSES ) && QuestDatabase.isQuestFinished( Quest.BUSINESS ) && QuestDatabase.isQuestFinished( Quest.DOCTOR ) ) { QuestDatabase.setQuestProgress( Quest.WORSHIP, "step4" ); } break; case ItemPool.ANCIENT_AMULET: // If you get the ancient amulet, you lose the 4 stone triangles, and have definitely completed quest actions ResultProcessor.processItem( ItemPool.STONE_TRIANGLE, -4 ); Preferences.setInteger( "hiddenApartmentProgress", 8 ); Preferences.setInteger( "hiddenHospitalProgress", 8 ); Preferences.setInteger( "hiddenOfficeProgress", 8 ); Preferences.setInteger( "hiddenBowlingAlleyProgress", 8 ); QuestDatabase.setQuestProgress( Quest.WORSHIP, QuestDatabase.FINISHED ); break; case ItemPool.STAFF_OF_FATS: QuestDatabase.setQuestProgress( Quest.PALINDOME, QuestDatabase.FINISHED ); break; case ItemPool.ANCIENT_BOMB: ResultProcessor.processItem( ItemPool.ANCIENT_BRONZE_TOKEN, -1 ); break; case ItemPool.CARONCH_MAP: QuestDatabase.setQuestProgress( Quest.PIRATE, QuestDatabase.STARTED ); break; case ItemPool.CARONCH_NASTY_BOOTY: QuestDatabase.setQuestIfBetter( Quest.PIRATE, "step1" ); break; case ItemPool.BILLIARDS_KEY: QuestDatabase.setQuestProgress( Quest.SPOOKYRAVEN_NECKLACE, "step1" ); break; case ItemPool.LIBRARY_KEY: QuestDatabase.setQuestProgress( Quest.SPOOKYRAVEN_NECKLACE, "step3" ); break; case ItemPool.SPOOKYRAVEN_NECKLACE: Preferences.setInteger( "writingDesksDefeated", 5 ); QuestDatabase.setQuestProgress( Quest.SPOOKYRAVEN_NECKLACE, "step4" ); break; case ItemPool.DUSTY_POPPET: QuestDatabase.setQuestProgress( Quest.SPOOKYRAVEN_BABIES, QuestDatabase.STARTED ); break; case ItemPool.BABY_GHOSTS: QuestDatabase.setQuestProgress( Quest.SPOOKYRAVEN_BABIES, "step1" ); ResultProcessor.removeItem( ItemPool.DUSTY_POPPET ); ResultProcessor.removeItem( ItemPool.RICKETY_ROCKING_HORSE ); ResultProcessor.removeItem( ItemPool.ANTIQUE_JACK_IN_THE_BOX ); break; case ItemPool.GHOST_FORMULA: QuestDatabase.setQuestProgress( Quest.SPOOKYRAVEN_BABIES, QuestDatabase.FINISHED ); ResultProcessor.removeItem( ItemPool.BABY_GHOSTS ); break; case ItemPool.NEOPRENE_SKULLCAP: if ( combatResults ) { QuestDatabase.setQuestProgress( Quest.BAT, "step4" ); } break; case ItemPool.GOBLIN_WATER: if ( combatResults ) { QuestDatabase.setQuestProgress( Quest.GOBLIN, QuestDatabase.FINISHED ); } break; case ItemPool.HAND_CARVED_BOKKEN: case ItemPool.HAND_CARVED_BOW: case ItemPool.HAND_CARVED_STAFF: if ( RequestLogger.getLastURLString().contains( "action=lc_marty" ) ) { QuestDatabase.setQuestProgress( Quest.SWAMP, QuestDatabase.FINISHED ); } break; case ItemPool.WORSE_HOMES_GARDENS: QuestDatabase.setQuestProgress( Quest.HIPPY, "step1" ); ConcoctionDatabase.setRefreshNeeded( false ); break; case ItemPool.STEEL_LIVER: case ItemPool.STEEL_STOMACH: case ItemPool.STEEL_SPLEEN: QuestDatabase.setQuestProgress( Quest.AZAZEL, QuestDatabase.FINISHED ); break; case ItemPool.BATHYSPHERE: QuestDatabase.setQuestProgress( Quest.SEA_OLD_GUY, QuestDatabase.STARTED ); break; case ItemPool.WRIGGLING_FLYTRAP_PELLET: QuestDatabase.setQuestProgress( Quest.SEA_MONKEES, QuestDatabase.STARTED ); break; case ItemPool.BUBBLIN_STONE: QuestDatabase.setQuestProgress( Quest.SEA_MONKEES, "step3" ); break; case ItemPool.DAS_BOOT: case ItemPool.FISHY_PIPE: case ItemPool.FISH_MEAT_CRATE: case ItemPool.DAMP_WALLET: if ( RequestLogger.getLastURLString().contains( "action=oldman_oldman" ) ) { ResultProcessor.removeItem( ItemPool.DAMP_OLD_BOOT ); QuestDatabase.setQuestProgress( Quest.SEA_OLD_GUY, QuestDatabase.FINISHED ); } break; case ItemPool.PREGNANT_FLAMING_MUSHROOM: ResultProcessor.processItem( ItemPool.FLAMING_MUSHROOM, -1 ); break; case ItemPool.PREGNANT_FROZEN_MUSHROOM: ResultProcessor.processItem( ItemPool.FROZEN_MUSHROOM, -1 ); break; case ItemPool.PREGNANT_STINKY_MUSHROOM: ResultProcessor.processItem( ItemPool.STINKY_MUSHROOM, -1 ); break; case ItemPool.GRANDMAS_NOTE: QuestDatabase.setQuestProgress( Quest.SEA_MONKEES, "step7" ); break; case ItemPool.GRANDMAS_MAP: ResultProcessor.processItem( ItemPool.GRANDMAS_NOTE, -1 ); ResultProcessor.processItem( ItemPool.FUCHSIA_YARN, -1 ); ResultProcessor.processItem( ItemPool.CHARTREUSE_YARN, -1 ); QuestDatabase.setQuestProgress( Quest.SEA_MONKEES, "step8" ); break; case ItemPool.BLACK_GLASS: QuestDatabase.setQuestProgress( Quest.SEA_MONKEES, "step12" ); break; case ItemPool.SMALL_STONE_BLOCK: ResultProcessor.processItem( ItemPool.IRON_KEY, -1 ); break; case ItemPool.CRIMBOMINATION_CONTRAPTION: ResultProcessor.removeItem( ItemPool.WRENCH_HANDLE ); ResultProcessor.removeItem( ItemPool.HEADLESS_BOLTS ); ResultProcessor.removeItem( ItemPool.AGITPROP_INK ); ResultProcessor.removeItem( ItemPool.HANDFUL_OF_WIRES ); ResultProcessor.removeItem( ItemPool.CHUNK_OF_CEMENT ); ResultProcessor.removeItem( ItemPool.PENGUIN_GRAPPLING_HOOK ); ResultProcessor.removeItem( ItemPool.CARDBOARD_ELF_EAR ); ResultProcessor.removeItem( ItemPool.SPIRALING_SHAPE ); break; case ItemPool.HAMMER_OF_SMITING: case ItemPool.CHELONIAN_MORNINGSTAR: case ItemPool.GREEK_PASTA_OF_PERIL: case ItemPool.SEVENTEEN_ALARM_SAUCEPAN: case ItemPool.SHAGADELIC_DISCO_BANJO: case ItemPool.SQUEEZEBOX_OF_THE_AGES: QuestDatabase.setQuestProgress( Quest.NEMESIS, "step8" ); break; case ItemPool.FIZZING_SPORE_POD: if ( InventoryManager.getCount( ItemPool.FIZZING_SPORE_POD ) + count >= 6 && ( QuestDatabase.isQuestStep( Quest.NEMESIS, "step12" ) || QuestDatabase.isQuestStep( Quest.NEMESIS, "step13" ) ) ) { QuestDatabase.setQuestProgress( Quest.NEMESIS, "step14" ); } break; case ItemPool.SCALP_OF_GORGOLOK: case ItemPool.ELDER_TURTLE_SHELL: case ItemPool.COLANDER_OF_EMERIL: case ItemPool.ANCIENT_SAUCEHELM: case ItemPool.DISCO_FRO_PICK: case ItemPool.EL_SOMBRERO_DE_LOPEZ: if ( combatResults ) { QuestDatabase.setQuestProgress( Quest.NEMESIS, "step16" ); } break; case ItemPool.KRAKROXS_LOINCLOTH: case ItemPool.GALAPAGOSIAN_CUISSES: case ItemPool.ANGELHAIR_CULOTTES: case ItemPool.NEWMANS_OWN_TROUSERS: case ItemPool.VOLARTTAS_BELLBOTTOMS: case ItemPool.LEDERHOSEN_OF_THE_NIGHT: if ( combatResults ) { QuestDatabase.setQuestProgress( Quest.NEMESIS, "step27" ); } break; case ItemPool.HELLSEAL_DISGUISE: ResultProcessor.processItem( ItemPool.HELLSEAL_HIDE, -6 ); ResultProcessor.processItem( ItemPool.HELLSEAL_BRAIN, -6 ); ResultProcessor.processItem( ItemPool.HELLSEAL_SINEW, -6 ); break; case ItemPool.DECODED_CULT_DOCUMENTS: ResultProcessor.processItem( ItemPool.CULT_MEMO, -5 ); break; // If you acquire this item you've just completed Nemesis quest // Contents of Hacienda for Accordion Thief changes case ItemPool.BELT_BUCKLE_OF_LOPEZ: if ( combatResults ) { HaciendaManager.questCompleted(); } // fall through case ItemPool.INFERNAL_SEAL_CLAW: case ItemPool.TURTLE_POACHER_GARTER: case ItemPool.SPAGHETTI_BANDOLIER: case ItemPool.SAUCEBLOB_BELT: case ItemPool.NEW_WAVE_BLING: if ( combatResults ) { QuestDatabase.setQuestProgress( Quest.NEMESIS, QuestDatabase.FINISHED ); } break; case ItemPool.PIXEL_CHAIN_WHIP: if ( combatResults ) { // If you acquire a pixel chain whip, you lose // the pixel whip you were wielding and wield // the chain whip in its place. AdventureResult whip = ItemPool.get( ItemPool.PIXEL_WHIP, 1 ); EquipmentManager.transformEquipment( whip, result ); ResultProcessor.processItem( itemId, -1 ); } break; case ItemPool.PIXEL_MORNING_STAR: if ( combatResults ) { // If you acquire a pixel morning star, you // lose the pixel chain whip you were wielding // and wield the morning star in its place. AdventureResult chainWhip = ItemPool.get( ItemPool.PIXEL_CHAIN_WHIP, 1 ); EquipmentManager.transformEquipment( chainWhip, result ); ResultProcessor.processItem( itemId, -1 ); } break; case ItemPool.REFLECTION_OF_MAP: if ( combatResults ) { int current = Preferences.getInteger( "pendingMapReflections" ); current = Math.max( 0, current - 1); Preferences.setInteger( "pendingMapReflections", current ); } break; case ItemPool.GONG: if ( combatResults ) { Preferences.increment( "_gongDrops", 1 ); } break; case ItemPool.SLIME_STACK: if ( combatResults ) { int dropped = Preferences.increment( "slimelingStacksDropped", 1 ); if ( dropped > Preferences.getInteger( "slimelingStacksDue" ) ) { // in case it's out of sync, nod and smile Preferences.setInteger( "slimelingStacksDue", dropped ); } } break; case ItemPool.ABSINTHE: if ( combatResults ) { Preferences.increment( "_absintheDrops", 1 ); } break; case ItemPool.ASTRAL_MUSHROOM: if ( combatResults ) { Preferences.increment( "_astralDrops", 1 ); } break; case ItemPool.AGUA_DE_VIDA: if ( combatResults ) { Preferences.increment( "_aguaDrops", 1 ); } break; case ItemPool.DEVILISH_FOLIO: if ( combatResults ) { Preferences.increment( "_kloopDrops", 1 ); } break; case ItemPool.GROOSE_GREASE: if ( combatResults ) { Preferences.increment( "_grooseDrops", 1 ); } break; case ItemPool.GG_TOKEN: if ( combatResults ) { Preferences.increment( "_tokenDrops", 1 ); } // Fall through case ItemPool.GG_TICKET: // If this is the first token or ticket we've gotten // this ascension, visit the wrong side of the tracks // to unlock the arcade. if ( Preferences.getInteger( "lastArcadeAscension" ) < KoLCharacter.getAscensions() ) { Preferences.setInteger( "lastArcadeAscension", KoLCharacter.getAscensions() ); RequestThread.postRequest( new PlaceRequest( "town_wrong" ) ); } break; case ItemPool.TRANSPORTER_TRANSPONDER: if ( combatResults ) { Preferences.increment( "_transponderDrops", 1 ); } break; case ItemPool.UNCONSCIOUS_COLLECTIVE_DREAM_JAR: if ( combatResults ) { Preferences.increment( "_dreamJarDrops", 1 ); } break; case ItemPool.HOT_ASHES: if ( combatResults ) { Preferences.increment( "_hotAshesDrops", 1 ); } break; case ItemPool.PSYCHOANALYTIC_JAR: if ( combatResults ) { Preferences.increment( "_jungDrops", 1 ); Preferences.setInteger( "jungCharge", 0 ); KoLCharacter.findFamiliar( FamiliarPool.ANGRY_JUNG_MAN ).setCharges( 0 ); } break; case ItemPool.TALES_OF_SPELUNKING: if ( combatResults ) { Preferences.increment( "_spelunkingTalesDrops", 1 ); } break; case ItemPool.POWDERED_GOLD: if ( combatResults ) { Preferences.increment( "_powderedGoldDrops", 1 ); } break; case ItemPool.MINI_MARTINI: if ( combatResults ) { Preferences.increment( "_miniMartiniDrops", 1 ); } break; case ItemPool.POWER_PILL: if ( combatResults ) { Preferences.increment( "_powerPillDrops", 1 ); } break; case ItemPool.MACHINE_SNOWGLOBE: if ( combatResults ) { Preferences.increment( "_snowglobeDrops", 1 ); } break; case ItemPool.LIVER_PIE: case ItemPool.BADASS_PIE: case ItemPool.FISH_PIE: case ItemPool.PIPING_PIE: case ItemPool.IGLOO_PIE: case ItemPool.TURNOVER: case ItemPool.DEAD_PIE: case ItemPool.THROBBING_PIE: if ( combatResults && KoLCharacter.currentFamiliar.getId() == FamiliarPool.GRINDER ) { Preferences.increment( "_pieDrops", 1 ); Preferences.setInteger( "_piePartsCount", -1 ); Preferences.setString( "pieStuffing", "" ); } break; case ItemPool.GOOEY_PASTE: case ItemPool.BEASTLY_PASTE: case ItemPool.OILY_PASTE: case ItemPool.ECTOPLASMIC: case ItemPool.GREASY_PASTE: case ItemPool.BUG_PASTE: case ItemPool.HIPPY_PASTE: case ItemPool.ORC_PASTE: case ItemPool.DEMONIC_PASTE: case ItemPool.INDESCRIBABLY_HORRIBLE_PASTE: case ItemPool.FISHY_PASTE: case ItemPool.GOBLIN_PASTE: case ItemPool.PIRATE_PASTE: case ItemPool.CHLOROPHYLL_PASTE: case ItemPool.STRANGE_PASTE: case ItemPool.MER_KIN_PASTE: case ItemPool.SLIMY_PASTE: case ItemPool.PENGUIN_PASTE: case ItemPool.ELEMENTAL_PASTE: case ItemPool.COSMIC_PASTE: case ItemPool.HOBO_PASTE: case ItemPool.CRIMBO_PASTE: if ( combatResults ) { Preferences.increment( "_pasteDrops", 1 ); } break; case ItemPool.BEER_LENS: if ( combatResults ) { Preferences.increment( "_beerLensDrops", 1 ); } break; case ItemPool.COTTON_CANDY_CONDE: case ItemPool.COTTON_CANDY_PINCH: case ItemPool.COTTON_CANDY_SMIDGEN: case ItemPool.COTTON_CANDY_SKOSHE: case ItemPool.COTTON_CANDY_PLUG: case ItemPool.COTTON_CANDY_PILLOW: case ItemPool.COTTON_CANDY_BALE: if ( combatResults ) { Preferences.increment( "_carnieCandyDrops", 1 ); } break; case ItemPool.LESSER_GRODULATED_VIOLET: case ItemPool.TIN_MAGNOLIA: case ItemPool.BEGPWNIA: case ItemPool.UPSY_DAISY: case ItemPool.HALF_ORCHID: if ( combatResults ) { Preferences.increment( "_mayflowerDrops", 1 ); } break; case ItemPool.EVILOMETER: Preferences.setInteger( "cyrptTotalEvilness", 200 ); Preferences.setInteger( "cyrptAlcoveEvilness", 50 ); Preferences.setInteger( "cyrptCrannyEvilness", 50 ); Preferences.setInteger( "cyrptNicheEvilness", 50 ); Preferences.setInteger( "cyrptNookEvilness", 50 ); break; case ItemPool.TEACHINGS_OF_THE_FIST: // save which location the scroll was found in. String setting = AdventureDatabase.fistcoreLocationToSetting( KoLAdventure.lastAdventureId() ); if ( setting != null ) { Preferences.setBoolean( setting, true ); } break; case ItemPool.KEYOTRON: BugbearManager.resetStatus(); Preferences.setInteger( "lastKeyotronUse", KoLCharacter.getAscensions() ); break; case ItemPool.JICK_JAR: if ( RequestLogger.getLastURLString().contains( "action=jung" ) ) { Preferences.setBoolean( "_psychoJarFilled", true ); ResultProcessor.removeItem( ItemPool.PSYCHOANALYTIC_JAR ); } break; case ItemPool.SUSPICIOUS_JAR: case ItemPool.GOURD_JAR: case ItemPool.MYSTIC_JAR: case ItemPool.OLD_MAN_JAR: case ItemPool.ARTIST_JAR: case ItemPool.MEATSMITH_JAR: if ( RequestLogger.getLastURLString().contains( "action=jung" ) ) { ResultProcessor.removeItem( ItemPool.PSYCHOANALYTIC_JAR ); } break; case ItemPool.BRICKO_EYE: if ( RequestLogger.getLastURLString().startsWith( "campground.php" ) || RequestLogger.getLastURLString().startsWith( "skills.php" ) ) { Preferences.increment( "_brickoEyeSummons" ); } break; case ItemPool.DIVINE_CHAMPAGNE_POPPER: case ItemPool.DIVINE_CRACKER: case ItemPool.DIVINE_FLUTE: if ( RequestLogger.getLastURLString().startsWith( "campground.php" ) || RequestLogger.getLastURLString().startsWith( "skills.php" ) ) { Preferences.increment( "_favorRareSummons" ); } break; case ItemPool.YELLOW_TAFFY: if ( RequestLogger.getLastURLString().startsWith( "campground.php" ) || RequestLogger.getLastURLString().startsWith( "skills.php" ) ) { Preferences.increment( "_taffyRareSummons" ); Preferences.increment( "_taffyYellowSummons" ); } break; case ItemPool.GREEN_TAFFY: case ItemPool.INDIGO_TAFFY: if ( RequestLogger.getLastURLString().startsWith( "campground.php" ) || RequestLogger.getLastURLString().startsWith( "skills.php" ) ) { Preferences.increment( "_taffyRareSummons" ); } break; case ItemPool.BOSS_HELM: case ItemPool.BOSS_CLOAK: case ItemPool.BOSS_SWORD: case ItemPool.BOSS_SHIELD: case ItemPool.BOSS_PANTS: case ItemPool.BOSS_GAUNTLETS: case ItemPool.BOSS_BOOTS: case ItemPool.BOSS_BELT: if ( combatResults ) { ResultProcessor.removeItem( ItemPool.GAMEPRO_WALKTHRU ); } break; case ItemPool.CARROT_NOSE: if ( combatResults ) { Preferences.increment( "_carrotNoseDrops" ); } break; case ItemPool.COSMIC_SIX_PACK: Preferences.setBoolean( "_cosmicSixPackConjured", true ); break; case ItemPool.COBBS_KNOB_MAP: QuestDatabase.setQuestProgress( Quest.GOBLIN, QuestDatabase.STARTED ); break; case ItemPool.MERKIN_LOCKKEY: MonsterData monster = MonsterStatusTracker.getLastMonster(); if ( monster == null ) { break; } String lockkeyMonster = monster.getName(); Preferences.setString( "merkinLockkeyMonster", lockkeyMonster ); if ( lockkeyMonster.equals( "Mer-kin burglar" ) ) { Preferences.setInteger( "choiceAdventure312", 1 ); } else if ( lockkeyMonster.equals( "Mer-kin raider" ) ) { Preferences.setInteger( "choiceAdventure312", 2 ); } else if ( lockkeyMonster.equals( "Mer-kin healer" ) ) { Preferences.setInteger( "choiceAdventure312", 3 ); } break; case ItemPool.YEARBOOK_CAMERA: { String desc = DebugDatabase.rawItemDescriptionText( ItemPool.YEARBOOK_CAMERA ); int upgrades = ItemDatabase.parseYearbookCamera( desc ); Preferences.setInteger( "yearbookCameraAscensions", upgrades ); break; } case ItemPool.CLANCY_LUTE: if ( combatResults ) { QuestDatabase.setQuestProgress( Quest.CLANCY, "step5" ); } break; case ItemPool.BEER_BATTERED_ACCORDION: case ItemPool.BARITONE_ACCORDION: case ItemPool.MAMAS_SQUEEZEBOX: case ItemPool.GUANCERTINA: case ItemPool.ACCORDION_FILE: case ItemPool.ACCORD_ION: case ItemPool.BONE_BANDONEON: case ItemPool.PENTATONIC_ACCORDION: case ItemPool.NON_EUCLIDEAN_NON_ACCORDION: case ItemPool.ACCORDION_OF_JORDION: case ItemPool.AUTOCALLIOPE: case ItemPool.ACCORDIONOID_ROCCA: case ItemPool.PYGMY_CONCERTINETTE: case ItemPool.GHOST_ACCORDION: case ItemPool.PEACE_ACCORDION: case ItemPool.ALARM_ACCORDION: case ItemPool.BAL_MUSETTE_ACCORDION: case ItemPool.CAJUN_ACCORDION: case ItemPool.QUIRKY_ACCORDION: if ( combatResults ) { StringBuilder buffer = new StringBuilder( Preferences.getString( "_stolenAccordions" ) ); if ( buffer.length() > 0 ) { buffer.append( "," ); } buffer.append( itemId ); Preferences.setString( "_stolenAccordions", buffer.toString() ); } break; case ItemPool.DAMP_OLD_BOOT: QuestDatabase.setQuestProgress( Quest.SEA_OLD_GUY, "step1" ); Preferences.setBoolean( "dampOldBootPurchased", true ); break; case ItemPool.GRIMSTONE_MASK: if ( combatResults ) { if ( KoLCharacter.getFamiliar().equals( KoLCharacter.findFamiliar( FamiliarPool.GRIMSTONE_GOLEM ) ) ) { Preferences.increment( "_grimstoneMaskDrops" ); Preferences.setInteger( "grimstoneCharge", 0 ); KoLCharacter.findFamiliar( FamiliarPool.GRIMSTONE_GOLEM ).setCharges( 0 ); } else { Preferences.increment( "_grimstoneMaskDropsCrown" ); } } break; case ItemPool.GRIM_FAIRY_TALE: if ( combatResults ) { if ( KoLCharacter.getFamiliar().equals( KoLCharacter.findFamiliar( FamiliarPool.GRIM_BROTHER ) ) ) { Preferences.increment( "_grimFairyTaleDrops" ); } else { Preferences.increment( "_grimFairyTaleDropsCrown" ); } } break; case ItemPool.HOARDED_CANDY_WAD: if ( combatResults ) { Preferences.increment( "_hoardedCandyDropsCrown" ); } break; case ItemPool.SPACE_BEAST_FUR: if ( combatResults ) { // It could still drop from a space beast while this is true, but that would // be harder to check for if ( KoLCharacter.currentBjorned.getId() == FamiliarPool.TWITCHING_SPACE_CRITTER || KoLCharacter.currentEnthroned.getId() == FamiliarPool.TWITCHING_SPACE_CRITTER ) { Preferences.increment( "_spaceFurDropsCrown" ); } } case ItemPool.PROFESSOR_WHAT_GARMENT: QuestDatabase.setQuestProgress( Quest.SHIRT, "step1" ); break; case ItemPool.PROFESSOR_WHAT_TSHIRT: { String lastURL = RequestLogger.getLastURLString(); if ( lastURL.startsWith( "place.php" ) && lastURL.contains( "whichplace=mountains" ) && lastURL.contains( "action=mts_melvin" ) ) { QuestDatabase.setQuestProgress( Quest.SHIRT, QuestDatabase.FINISHED ); ResultProcessor.removeItem( ItemPool.PROFESSOR_WHAT_GARMENT ); ResponseTextParser.learnSkill( "Torso Awaregness" ); } break; } case ItemPool.THINKNERD_PACKAGE: if ( combatResults ) { Preferences.increment( "_thinknerdPackageDrops" ); } break; case ItemPool.STEAM_FIST_1: case ItemPool.STEAM_FIST_2: case ItemPool.STEAM_FIST_3: case ItemPool.STEAM_TRIP_1: case ItemPool.STEAM_TRIP_2: case ItemPool.STEAM_TRIP_3: case ItemPool.STEAM_METEOID_1: case ItemPool.STEAM_METEOID_2: case ItemPool.STEAM_METEOID_3: case ItemPool.STEAM_DEMON_1: case ItemPool.STEAM_DEMON_2: case ItemPool.STEAM_DEMON_3: case ItemPool.STEAM_PLUMBER_1: case ItemPool.STEAM_PLUMBER_2: case ItemPool.STEAM_PLUMBER_3: if ( combatResults ) { Preferences.increment( "_steamCardDrops" ); } break; case ItemPool.PENCIL_THIN_MUSHROOM: if ( InventoryManager.getCount( ItemPool.PENCIL_THIN_MUSHROOM ) >= 9 ) { QuestDatabase.setQuestProgress( Quest.JIMMY_MUSHROOM, "step1" ); } break; case ItemPool.SAILOR_SALT: if ( InventoryManager.getCount( ItemPool.SAILOR_SALT ) >= 49 ) { QuestDatabase.setQuestProgress( Quest.JIMMY_SALT, "step1" ); } break; case ItemPool.TACO_DAN_RECEIPT: if ( InventoryManager.getCount( ItemPool.TACO_DAN_RECEIPT ) >= 9 ) { QuestDatabase.setQuestProgress( Quest.TACO_DAN_AUDIT, "step1" ); } break; case ItemPool.BROUPON: if ( InventoryManager.getCount( ItemPool.BROUPON ) >= 14 ) { QuestDatabase.setQuestProgress( Quest.BRODEN_DEBT, "step1" ); } break; case ItemPool.ELIZABETH_DOLLIE: if ( combatResults ) { Preferences.setString( "nextSpookyravenElizabethRoom", "none" ); } break; case ItemPool.STEPHEN_LAB_COAT: if ( combatResults ) { Preferences.setString( "nextSpookyravenStephenRoom", "none" ); } break; case ItemPool.WINE_BOMB: EquipmentManager.discardEquipment( ItemPool.UNSTABLE_FULMINATE ); break; case ItemPool.LIGHTNING_MILK: // These are starting skills if no turns have been played this ascension if ( KoLCharacter.getCurrentRun() == 0 ) { Preferences.setInteger( "heavyRainsStartingLightning", count ); } break; case ItemPool.AQUA_BRAIN: // These are starting skills if no turns have been played this ascension if ( KoLCharacter.getCurrentRun() == 0 ) { Preferences.setInteger( "heavyRainsStartingRain", count ); } break; case ItemPool.THUNDER_THIGH: // These are starting skills if no turns have been played this ascension if ( KoLCharacter.getCurrentRun() == 0 ) { Preferences.setInteger( "heavyRainsStartingThunder", count ); } break; case ItemPool.EXPERIMENTAL_SERUM_P00: if ( InventoryManager.getCount( ItemPool.EXPERIMENTAL_SERUM_P00 ) >= 4 && QuestDatabase.isQuestStep( Quest.SERUM, QuestDatabase.STARTED ) ) { QuestDatabase.setQuestProgress( Quest.SERUM, "step1" ); } break; case ItemPool.MINI_CASSETTE_RECORDER: QuestDatabase.setQuestProgress( Quest.JUNGLE_PUN, QuestDatabase.STARTED ); Preferences.setInteger( "junglePuns", 0 ); break; case ItemPool.GORE_BUCKET: QuestDatabase.setQuestProgress( Quest.GORE, QuestDatabase.STARTED ); Preferences.setInteger( "goreCollected", 0 ); break; case ItemPool.FINGERNAIL_CLIPPERS: QuestDatabase.setQuestProgress( Quest.CLIPPER, QuestDatabase.STARTED ); Preferences.setInteger( "fingernailsClipped", 0 ); break; case ItemPool.ESP_COLLAR: QuestDatabase.setQuestProgress( Quest.FAKE_MEDIUM, "step1" ); break; case ItemPool.GPS_WATCH: QuestDatabase.setQuestProgress( Quest.OUT_OF_ORDER, QuestDatabase.STARTED ); break; case ItemPool.PROJECT_TLB: QuestDatabase.setQuestProgress( Quest.OUT_OF_ORDER, "step2" ); break; case ItemPool.PACK_OF_SMOKES: if ( InventoryManager.getCount( ItemPool.PACK_OF_SMOKES ) >= 10 ) { QuestDatabase.setQuestProgress( Quest.SMOKES, "step1" ); } break; case ItemPool.SUBJECT_37_FILE: QuestDatabase.setQuestProgress( Quest.ESCAPE, "step1" ); break; case ItemPool.GOTO: if ( QuestDatabase.isQuestStep( Quest.ESCAPE, "step2" ) ) { QuestDatabase.setQuestProgress( Quest.ESCAPE, "step3" ); } break; case ItemPool.WEREMOOSE_SPIT: if ( QuestDatabase.isQuestStep( Quest.ESCAPE, "step4" ) ) { QuestDatabase.setQuestProgress( Quest.ESCAPE, "step5" ); } break; case ItemPool.ABOMINABLE_BLUBBER: if ( QuestDatabase.isQuestStep( Quest.ESCAPE, "step6" ) ) { QuestDatabase.setQuestProgress( Quest.ESCAPE, "step7" ); } break; case ItemPool.FRIENDLY_TURKEY: case ItemPool.AGITATED_TURKEY: case ItemPool.AMBITIOUS_TURKEY: if ( combatResults && KoLCharacter.currentFamiliar.getId() == FamiliarPool.FIST_TURKEY ) { Preferences.increment( "_turkeyBooze" ); } break; case ItemPool.XIBLAXIAN_ALLOY: case ItemPool.XIBLAXIAN_CIRCUITRY: case ItemPool.XIBLAXIAN_POLYMER: if ( combatResults ) { Preferences.increment( "_holoWristDrops" ); // This will be incremented to 0 during later processing Preferences.setInteger( "_holoWristProgress", -1 ); } break; case ItemPool.ED_EYE: EquipmentManager.removeEquipment( ItemPool.ED_STAFF ); ResultProcessor.removeItem( ItemPool.ED_STAFF ); break; case ItemPool.SCARAB_BEETLE_STATUETTE: QuestDatabase.setQuestProgress( Quest.FINAL, QuestDatabase.FINISHED ); break; case ItemPool.MEATSMITH_CHECK: QuestDatabase.setQuestProgress( Quest.MEATSMITH, "step1" ); break; case ItemPool.TOXIC_GLOBULE: if ( InventoryManager.getCount( ItemPool.TOXIC_GLOBULE ) + count >= 20 && QuestDatabase.isQuestStep( Quest.GIVE_ME_FUEL, QuestDatabase.STARTED ) ) { QuestDatabase.setQuestProgress( Quest.GIVE_ME_FUEL, "step1" ); } break; case ItemPool.LUBE_SHOES: QuestDatabase.setQuestProgress( Quest.SUPER_LUBER, QuestDatabase.STARTED ); break; case ItemPool.TRASH_NET: QuestDatabase.setQuestProgress( Quest.FISH_TRASH, QuestDatabase.STARTED ); Preferences.setInteger( "dinseyFilthLevel", 100 ); break; case ItemPool.MASCOT_MASK: QuestDatabase.setQuestProgress( Quest.ZIPPITY_DOO_DAH, QuestDatabase.STARTED ); break; case ItemPool.FRAUDWORT: if ( InventoryManager.getCount( ItemPool.FRAUDWORT ) + count >= 3 && InventoryManager.getCount( ItemPool.SHYSTERWEED ) >= 3 && InventoryManager.getCount( ItemPool.SWINDLEBLOSSOM ) >= 3 ) { QuestDatabase.setQuestIfBetter( Quest.DOC, "step1" ); } break; case ItemPool.SHYSTERWEED: if ( InventoryManager.getCount( ItemPool.FRAUDWORT ) >= 3 && InventoryManager.getCount( ItemPool.SHYSTERWEED ) + count >= 3 && InventoryManager.getCount( ItemPool.SWINDLEBLOSSOM ) >= 3 ) { QuestDatabase.setQuestIfBetter( Quest.DOC, "step1" ); } break; case ItemPool.SWINDLEBLOSSOM: if ( InventoryManager.getCount( ItemPool.FRAUDWORT ) >= 3 && InventoryManager.getCount( ItemPool.SHYSTERWEED ) >= 3 && InventoryManager.getCount( ItemPool.SWINDLEBLOSSOM ) + count >= 3 ) { QuestDatabase.setQuestIfBetter( Quest.DOC, "step1" ); } break; case ItemPool.MIRACLE_WHIP: Preferences.setBoolean( "itemBoughtPerAscension8266", true ); // Deliberate fallthrough case ItemPool.SPHYGMAYOMANOMETER: case ItemPool.REFLEX_HAMMER: case ItemPool.MAYO_LANCE: Preferences.setBoolean( "_mayoDeviceRented", true ); break; case ItemPool.NO_HANDED_PIE: QuestDatabase.setQuestProgress( Quest.ARMORER, "step4" ); break; case ItemPool.POPULAR_PART: QuestDatabase.setQuestProgress( Quest.ARMORER, QuestDatabase.FINISHED ); ResultProcessor.removeItem( ItemPool.NO_HANDED_PIE ); break; case ItemPool.SUPERHEATED_METAL: case ItemPool.SUPERDUPERHEATED_METAL: if ( combatResults ) { ResultProcessor.removeItem( ItemPool.HEAT_RESISTANT_SHEET_METAL ); } break; case ItemPool.BARREL_LID: Preferences.setBoolean( "prayedForProtection", true ); break; case ItemPool.BARREL_HOOP_EARRING: Preferences.setBoolean( "prayedForGlamour", true ); break; case ItemPool.BANKRUPTCY_BARREL: Preferences.setBoolean( "prayedForVigor", true ); break; // Correct Snojo progress based on drops - note that it increments after the fight! case ItemPool.ANCIENT_MEDICINAL_HERBS: if ( combatResults ) { int progress = Preferences.getInteger( "snojoMuscleWins" ); // Always should be a multiple of 7 for this drop, after the counter increments later! if ( progress % 7 != 6 ) { Preferences.setInteger( "snojoMuscleWins", (int) Math.floor( progress / 7 ) * 7 + 6 ); } } break; case ItemPool.ICE_RICE: if ( combatResults ) { int progress = Preferences.getInteger( "snojoMysticalityWins" ); // Always should be a multiple of 7 for this drop, after the counter increments later! if ( progress % 7 != 6 ) { Preferences.setInteger( "snojoMysticalityWins", (int) Math.floor( progress / 7 ) * 7 + 6 ); } } break; case ItemPool.ICED_PLUM_WINE: if ( combatResults ) { int progress = Preferences.getInteger( "snojoMoxieWins" ); // Always should be a multiple of 7 for this drop, after the counter increments later! if ( progress % 7 != 6 ) { Preferences.setInteger( "snojoMoxieWins", (int) Math.floor( progress / 7 ) * 7 + 6 ); } } break; case ItemPool.TRAINING_BELT: if ( combatResults ) { Preferences.setInteger( "snojoMuscleWins", 10 ); } break; case ItemPool.TRAINING_LEGWARMERS: if ( combatResults ) { Preferences.setInteger( "snojoMysticalityWins", 10 ); } break; case ItemPool.TRAINING_HELMET: if ( combatResults ) { Preferences.setInteger( "snojoMoxieWins", 10 ); } break; case ItemPool.SCROLL_SHATTERING_PUNCH: if ( combatResults ) { Preferences.setInteger( "snojoMuscleWins", 49 ); } break; case ItemPool.SCROLL_SNOKEBOMB: if ( combatResults ) { Preferences.setInteger( "snojoMysticalityWins", 49 ); } break; case ItemPool.SCROLL_SHIVERING_MONKEY: if ( combatResults ) { Preferences.setInteger( "snojoMoxieWins", 49 ); } break; case ItemPool.EXPERIMENTAL_GENE_THERAPY: case ItemPool.SELF_DEFENSE_TRAINING: case ItemPool.CONFIDENCE_BUILDING_HUG: BatManager.gainItem( result ); break; case ItemPool.COWBOY_BOOTS: EquipmentRequest.checkCowboyBoots(); break; case ItemPool.ROBIN_EGG: if ( combatResults ) { // This will be updated to 0 in FightRequest later Preferences.setInteger( "rockinRobinProgress", -1 ); } break; case ItemPool.WAX_GLOB: if ( combatResults ) { // This will be updated to 0 in FightRequest later Preferences.setInteger( "optimisticCandleProgress", -1 ); } break; case ItemPool.NO_SPOON: QuestDatabase.setQuestProgress( Quest.ORACLE, "step1" ); break; case ItemPool.TALES_OF_DREAD: Preferences.setBoolean( "itemBoughtPerCharacter6423", true ); break; case ItemPool.BRASS_DREAD_FLASK: Preferences.setBoolean( "itemBoughtPerCharacter6428", true ); break; case ItemPool.SILVER_DREAD_FLASK: Preferences.setBoolean( "itemBoughtPerCharacter6429", true ); break; case ItemPool.NO_HAT: { String rawText = DebugDatabase.rawItemDescriptionText( ItemDatabase.getDescriptionId( itemId ), true ); String mod = DebugDatabase.parseItemEnchantments( rawText, new ArrayList<String>(), KoLConstants.EQUIP_HAT ); Modifiers.overrideModifier( "Item:[" + itemId + "]", mod ); Preferences.setString( "_noHatModifier", mod ); } break; case ItemPool.HOT_JELLY: case ItemPool.COLD_JELLY: case ItemPool.SPOOKY_JELLY: case ItemPool.SLEAZE_JELLY: case ItemPool.STENCH_JELLY: if ( combatResults ) { Preferences.increment( "_spaceJellyfishDrops" ); } break; } // Gaining items can achieve goals. GoalManager.updateProgress( result ); } public static void autoCreate( final int itemId ) { if ( ResultProcessor.autoCrafting || !Preferences.getBoolean( "autoCraft" ) ) { return; } ConcoctionDatabase.refreshConcoctionsNow(); CreateItemRequest creator = CreateItemRequest.getInstance( itemId ); // getQuantityPossible() should take meat paste or // Knoll Sign into account int possible = creator.getQuantityPossible(); if ( possible > 0 ) { ResultProcessor.autoCrafting = true; creator.setQuantityNeeded( 1 ); RequestThread.postRequest( creator ); ResultProcessor.autoCrafting = false; } } private static final Pattern HIPPY_PATTERN = Pattern.compile( "we donated (\\d+) meat" ); public static boolean onlyAutosellDonationsCount = true; public static void handleDonations( final String urlString, final String responseText ) { // Apparently, only autoselling items counts towards the trophy.. if ( ResultProcessor.onlyAutosellDonationsCount ) { return; } // ITEMS // Dolphin King's map: // // The treasure includes some Meat, but you give it away to // some moist orphans. They need it to buy dry clothes. if ( responseText.contains( "give it away to moist orphans" ) ) { KoLCharacter.makeCharitableDonation( 150 ); return; } // chest of the Bonerdagon: // // The Cola Wars Veterans Administration is really gonna // appreciate the huge donation you're about to make! if ( responseText.contains( "Cola Wars Veterans Administration" ) ) { KoLCharacter.makeCharitableDonation( 3000 ); return; } // ancient vinyl coin purse // // You head into town and give the Meat to a guy wearing thick // glasses and a tie. Maybe now he'll be able to afford eye // surgery and a new wardrobe. // // black pension check // // You head back to the Black Forest and give the proceeds to // one of the black widows. Any given widow is more or less the // same as any other widow, right? // // old coin purse // // You wander around town until you find somebody named // Charity, and give her the Meat. // // old leather wallet // // You take the Meat to a soup kitchen and hand it to the first // person you see. He smelled bad, so he was probably a // volunteer. // // orcish meat locker // // You unlock the Meat locker with your rusty metal key, and // then dump the contents directly into a charity box at a // nearby convenience store. Those kids with boneitis are sure // to appreciate the gesture. // // Penultimate Fantasy chest // // There some Meat in it, but you drop it off the side of the // airship. It'll probably land on someone needy. // // Warm Subject gift certificate // // Then you walk next door to the hat store, and you give the // hat store all of your Meat. We need all kinds of things in // this economy. // QUESTS // Spooky Forest quest: // // Thanks for the larva, Adventurer. We'll put this to good use. if ( responseText.contains( "Thanks for the larva, Adventurer" ) && !responseText.contains( "You gain" ) ) { KoLCharacter.makeCharitableDonation( 500 ); return; } // Wizard of Ego: from the "Other Class in the Guild" -> place=ocg // Nemesis: from the "Same Class in the Guild" -> place=scg // // You take the Meat into town and drop it in the donation slot // at the orphanage. You know, the one next to the library. if ( responseText.contains( "the one next to the library" ) ) { int donation = urlString.contains( "place=ocg" ) ? 500 : urlString.contains( "place=scg" ) ? 1000 : 0; KoLCharacter.makeCharitableDonation( donation ); return; } // Tr4pz0r quest: // // The furs you divide up between yourself and the Tr4pz0r, the // Meat you divide up between the Tr4pz0r and the needy. if ( responseText.contains( "you divide up between the Tr4pz0r and the needy" ) ) { KoLCharacter.makeCharitableDonation( 5000 ); return; } // Cap'n Caronch: // // (3000 meat with pirate fledges) // Post-filthworm orchard: // // Oh, hey, boss! Welcome back! Hey man, we don't want to // impose on your vow of poverty, so we donated 4248 meat from // our profits to the human fund in your honor. Thanks for // getting rid of those worms, man! Matcher matcher = ResultProcessor.HIPPY_PATTERN.matcher( responseText ); if ( matcher.find() ) { int donation = StringUtilities.parseInt( matcher.group( 1 ) ); KoLCharacter.makeCharitableDonation( donation ); return; } } }