/** * 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.maximizer; import java.util.Collections; import java.util.Iterator; import net.java.dev.spellcast.utilities.LockableListModel; import net.sourceforge.kolmafia.AdventureResult; import net.sourceforge.kolmafia.FamiliarData; import net.sourceforge.kolmafia.KoLCharacter; import net.sourceforge.kolmafia.KoLConstants; import net.sourceforge.kolmafia.KoLmafia; import net.sourceforge.kolmafia.KoLmafiaCLI; import net.sourceforge.kolmafia.Modifiers; import net.sourceforge.kolmafia.RequestLogger; import net.sourceforge.kolmafia.moods.MoodManager; 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.CandyDatabase; import net.sourceforge.kolmafia.persistence.ConsumablesDatabase; import net.sourceforge.kolmafia.persistence.EffectDatabase; import net.sourceforge.kolmafia.persistence.EquipmentDatabase; import net.sourceforge.kolmafia.persistence.ItemDatabase; import net.sourceforge.kolmafia.persistence.ItemFinder; import net.sourceforge.kolmafia.persistence.MallPriceDatabase; import net.sourceforge.kolmafia.persistence.QuestDatabase; import net.sourceforge.kolmafia.persistence.QuestDatabase.Quest; import net.sourceforge.kolmafia.persistence.SkillDatabase; import net.sourceforge.kolmafia.preferences.Preferences; import net.sourceforge.kolmafia.request.CampgroundRequest; import net.sourceforge.kolmafia.request.ClanLoungeRequest; import net.sourceforge.kolmafia.request.CreateItemRequest; import net.sourceforge.kolmafia.request.EquipmentRequest; import net.sourceforge.kolmafia.request.SkateParkRequest; import net.sourceforge.kolmafia.request.StandardRequest; import net.sourceforge.kolmafia.request.UneffectRequest; import net.sourceforge.kolmafia.request.UseItemRequest; import net.sourceforge.kolmafia.request.UseSkillRequest; import net.sourceforge.kolmafia.session.EquipmentManager; import net.sourceforge.kolmafia.session.InventoryManager; import net.sourceforge.kolmafia.session.Limitmode; import net.sourceforge.kolmafia.session.RabbitHoleManager; import net.sourceforge.kolmafia.session.StoreManager; import net.sourceforge.kolmafia.swingui.MaximizerFrame; import net.sourceforge.kolmafia.utilities.StringUtilities; public class Maximizer { private static boolean firstTime = true; public static final LockableListModel<Boost> boosts = new LockableListModel<Boost>(); public static Evaluator eval; public static String [] maximizationCategories = { "_hoboPower", "_brimstone", "_cloathing", "_slimeHate", "_stickers", "_folderholder", "_cardsleeve", "_smithsness", }; static MaximizerSpeculation best; static int bestChecked; static long bestUpdate; public static boolean maximize( String maximizerString, int maxPrice, int priceLevel, boolean isSpeculationOnly ) { MaximizerFrame.expressionSelect.setSelectedItem( maximizerString ); int equipLevel = isSpeculationOnly ? 1 : -1; // iECOC has to be turned off before actually maximizing as // it would cause all item lookups during the process to just // print the item name and return null. KoLmafiaCLI.isExecutingCheckOnlyCommand = false; Maximizer.maximize( equipLevel, maxPrice, priceLevel, false ); if ( !KoLmafia.permitsContinue() ) { return false; } Modifiers mods = Maximizer.best.calculate(); Modifiers.overrideModifier( "Generated:_spec", mods ); return !Maximizer.best.failed; } public static void maximize( int equipLevel, int maxPrice, int priceLevel, boolean includeAll ) { KoLmafia.forceContinue(); String maxMe = (String) MaximizerFrame.expressionSelect.getSelectedItem(); KoLConstants.maximizerMList.addItem( maxMe ); Maximizer.eval = new Evaluator( maxMe ); // parsing error if ( !KoLmafia.permitsContinue() ) { return; } double current = Maximizer.eval.getScore( KoLCharacter.getCurrentModifiers() ); if ( maxPrice <= 0 ) { maxPrice = Math.min( Preferences.getInteger( "autoBuyPriceLimit" ), KoLCharacter.getAvailableMeat() ); } KoLmafia.updateDisplay( Maximizer.firstTime ? "Maximizing (1st time may take a while)..." : "Maximizing..." ); Maximizer.firstTime = false; Maximizer.boosts.clear(); if ( equipLevel != 0 ) { Maximizer.best = new MaximizerSpeculation(); Maximizer.best.getScore(); // In case the current outfit scores better than any tried combination, // due to some newly-added constraint (such as +melee): Maximizer.best.failed = true; Maximizer.bestChecked = 0; Maximizer.bestUpdate = System.currentTimeMillis() + 5000; try { Maximizer.eval.enumerateEquipment( equipLevel, maxPrice, priceLevel ); } catch ( MaximizerExceededException e ) { Maximizer.boosts.add( new Boost( "", "(maximum achieved, no further combinations checked)", -1, null, 0.0 ) ); } catch ( MaximizerLimitException e ) { Maximizer.boosts.add( new Boost( "", "<font color=red>(hit combination limit, optimality not guaranteed)</font>", -1, null, 0.0 ) ); } catch ( MaximizerInterruptedException e ) { KoLmafia.forceContinue(); Maximizer.boosts.add( new Boost( "", "<font color=red>(interrupted, optimality not guaranteed)</font>", -1, null, 0.0 ) ); } MaximizerSpeculation.showProgress(); boolean[] alreadyDone = new boolean[ EquipmentManager.ALL_SLOTS ]; for ( int slot = EquipmentManager.ACCESSORY1; slot <= EquipmentManager.ACCESSORY3; ++slot ) { if ( Maximizer.best.equipment[ slot ].getItemId() == ItemPool.SPECIAL_SAUCE_GLOVE && EquipmentManager.getEquipment( slot ).getItemId() != ItemPool.SPECIAL_SAUCE_GLOVE ) { equipLevel = Maximizer.emitSlot( slot, equipLevel, maxPrice, priceLevel, current ); alreadyDone[ slot ] = true; } } for ( int slot = 0; slot < EquipmentManager.ALL_SLOTS; ++slot ) { if ( !alreadyDone[ slot ] ) { equipLevel = Maximizer.emitSlot( slot, equipLevel, maxPrice, priceLevel, current ); } } } current = Maximizer.eval.getScore( KoLCharacter.getCurrentModifiers() ); Iterator<String> i = Modifiers.getAllModifiers(); while ( i.hasNext() ) { String lookup = i.next(); // Include skills from absorbing items in Noobcore if ( KoLCharacter.inNoobcore() && lookup.startsWith( "Skill:" ) ) { String name = lookup.substring( 6 ); int skillId = SkillDatabase.getSkillId( name ); if ( skillId < 23001 || skillId > 23125 ) { continue; } if ( KoLCharacter.hasSkill( skillId ) ) { continue; } int absorbsLeft = KoLCharacter.getAbsorbsLimit() - KoLCharacter.getAbsorbs(); if ( absorbsLeft < 1 ) { continue; } MaximizerSpeculation spec = new MaximizerSpeculation(); String mods = Modifiers.getModifierList( "Skill", name ).toString(); spec.setCustom( mods ); double delta = spec.getScore() - current; if ( delta <= 0.0 ) { continue; } int[] itemList = ItemDatabase.getItemListByNoobSkillId( skillId ); if ( itemList == null ) { continue; } // Iterate over items to see if we have access to them int count = 0; for ( int itemId : itemList ) { CheckedItem checkedItem = new CheckedItem( itemId, equipLevel, maxPrice, priceLevel ); // We won't include unavailable items, as this just gets far too large String cmd, text; int price = 0; AdventureResult item = ItemPool.get( itemId ); cmd = "absorb \u00B6" + itemId; text = "absorb " + item.getName() + " (" + name + ", "; if ( checkedItem.inventory > 0 ) { } else if ( checkedItem.initial > 0 ) { String method = InventoryManager.simRetrieveItem( item, equipLevel == -1, false ); if ( !method.equals( "have" ) ) { text = method + " & " + text; } if ( method.equals( "uncloset" ) ) { cmd = "closet take 1 \u00B6" + itemId + ";" + cmd; } // Should be only hitting this after Ronin I think else if ( method.equals( "pull" ) ) { cmd = "pull 1 \u00B6" + itemId + ";" + cmd; } } else if ( checkedItem.creatable > 0 ) { text = "make & " + text; cmd = "make \u00B6" + itemId + ";" + cmd; } else if ( checkedItem.npcBuyable > 0 ) { text = "buy & " + text; cmd = "buy 1 \u00B6" + itemId + ";" + cmd; price = ConcoctionPool.get( item ).price; } else if ( checkedItem.pullable > 0 ) { text = "pull & " + text; cmd = "pull \u00B6" + itemId + ";" + cmd; } else if ( checkedItem.mallBuyable > 0 ) { text = "acquire & " + text; if ( priceLevel > 0 ) { price = StoreManager.getMallPrice( item ); } } else { continue; } if ( price > 0 ) { text = text + KoLConstants.COMMA_FORMAT.format( price ) + " meat, "; } text = text + KoLConstants.MODIFIER_FORMAT.format( delta ) + ")"; text = text + " [" + absorbsLeft + " absorbs remaining]"; if ( count > 0 ) { text = " or " + text; } Maximizer.boosts.add( new Boost( cmd, text, item, delta ) ); count++; } } // Include enchantments from absorbing equipment in Noobcore else if ( KoLCharacter.inNoobcore() && lookup.startsWith( "Item:" ) ) { String name = lookup.substring( 5 ); int itemId = ItemDatabase.getItemId( name ); int absorbsLeft = KoLCharacter.getAbsorbsLimit() - KoLCharacter.getAbsorbs(); if ( absorbsLeft < 1 ) { continue; } // Cannot abosrb undiscardable items if ( !ItemDatabase.isDiscardable( itemId ) ) { continue; } // Can only absorb tradeable and gift items if ( !ItemDatabase.isTradeable( itemId ) && !ItemDatabase.isGiftItem( itemId ) ) { continue; } // Can only get it from Equipment if ( !EquipmentDatabase.isEquipment( itemId ) ) { continue; } MaximizerSpeculation spec = new MaximizerSpeculation(); Modifiers itemMods = Modifiers.getItemModifiers( itemId ); if ( itemMods == null ) { continue; } // Only take numeric modifiers, and not Surgeonosity, from Items in Noobcore StringBuilder mods = new StringBuilder(); for ( int j = 0; j < Modifiers.DOUBLE_MODIFIERS; ++j ) { switch ( j ) { case Modifiers.SURGEONOSITY: continue; } if ( itemMods.get( j ) != 0.0 ) { if ( mods.length() > 0 ) { mods.append( ", " ); } mods.append( Modifiers.getModifierName( j ) + ": " + itemMods.get( j ) ); } } if ( mods.length() == 0 ) { continue; } spec.setCustom( mods.toString() ); double delta = spec.getScore() - current; if ( delta <= 0.0 ) { continue; } // Check if we have access to item CheckedItem checkedItem = new CheckedItem( itemId, equipLevel, maxPrice, priceLevel ); // We won't include unavailable items, as this just gets far too large String cmd, text; int price = 0; AdventureResult item = ItemPool.get( itemId ); cmd = "absorb \u00B6" + itemId; text = "absorb " + item.getName() + " ("; if ( checkedItem.inventory > 0 ) { } else if ( checkedItem.initial > 0 ) { String method = InventoryManager.simRetrieveItem( item, equipLevel == -1, false ); if ( !method.equals( "have" ) ) { text = method + " & " + text; } if ( method.equals( "uncloset" ) ) { cmd = "closet take 1 \u00B6" + itemId + ";" + cmd; } // Should be only hitting this after Ronin I think else if ( method.equals( "pull" ) ) { cmd = "pull 1 \u00B6" + itemId + ";" + cmd; } } else if ( checkedItem.creatable > 0 ) { text = "make & " + text; cmd = "make \u00B6" + itemId + ";" + cmd; } else if ( checkedItem.npcBuyable > 0 ) { text = "buy & " + text; cmd = "buy 1 \u00B6" + itemId + ";" + cmd; price = ConcoctionPool.get( item ).price; } else if ( checkedItem.pullable > 0 ) { text = "pull & " + text; cmd = "pull \u00B6" + itemId + ";" + cmd; } else if ( checkedItem.mallBuyable > 0 ) { text = "acquire & " + text; if ( priceLevel > 0 ) { price = StoreManager.getMallPrice( item ); } } else { continue; } if ( price > 0 ) { text = text + KoLConstants.COMMA_FORMAT.format( price ) + " meat, "; } text = text + "lasts til end of day, "; text = text + KoLConstants.MODIFIER_FORMAT.format( delta ) + ")"; text = text + " [" + absorbsLeft + " absorbs remaining"; if ( checkedItem.inventory > 0 ) { text = text + ", " + checkedItem.inventory + " in inventory"; } if ( checkedItem.initial - checkedItem.inventory > 0 ) { text = text + ", " + ( checkedItem.initial - checkedItem.inventory ) + " obtainable"; } if ( checkedItem.creatable > 0 ) { text = text + ", " + checkedItem.creatable + " createable"; } if ( checkedItem.npcBuyable > 0 ) { text = text + ", " + checkedItem.npcBuyable + " pullable"; } text = text + "]"; Maximizer.boosts.add( new Boost( cmd, text, item, delta ) ); } if ( !lookup.startsWith( "Effect:" ) ) { continue; } String name = lookup.substring( 7 ); int effectId = EffectDatabase.getEffectId( name ); if ( effectId == -1 ) { continue; } double delta; boolean isSpecial = false; MaximizerSpeculation spec = new MaximizerSpeculation(); AdventureResult effect = EffectPool.get( effectId ); name = effect.getName(); boolean hasEffect = KoLConstants.activeEffects.contains( effect ); Iterator<String> sources; String cmd, text; int price = 0; int advCost = 0; int mpCost = 0; int soulsauceCost = 0; int thunderCost = 0; int rainCost = 0; int lightningCost = 0; int duration = 0; int usesRemaining = 0; int itemsRemaining = 0; int itemsCreatable = 0; if ( !hasEffect ) { spec.addEffect( effect ); delta = spec.getScore() - current; if ( (spec.getModifiers().getRawBitmap( Modifiers.MUTEX_VIOLATIONS ) & ~KoLCharacter.currentRawBitmapModifier( Modifiers.MUTEX_VIOLATIONS )) != 0 ) { // This effect creates a mutex problem that the player // didn't already have. In the future, perhaps suggest // uneffecting the conflicting effect, but for now just skip. continue; } switch ( Maximizer.eval.checkConstraints( Modifiers.getEffectModifiers( effectId ) ) ) { case -1: continue; case 0: if ( delta <= 0.0 ) continue; break; case 1: isSpecial = true; } if ( Evaluator.checkEffectConstraints( effectId ) ) { continue; } sources = EffectDatabase.getAllActions( effectId ); cmd = MoodManager.getDefaultAction( "lose_effect", name ); if ( !sources.hasNext() ) { if ( includeAll ) { sources = Collections.singletonList( "(no known source of " + name + ")" ).iterator(); } else continue; } } else { spec.removeEffect( effect ); delta = spec.getScore() - current; switch ( Maximizer.eval.checkConstraints( Modifiers.getEffectModifiers( effectId ) ) ) { case 1: continue; case 0: if ( delta <= 0.0 ) continue; break; case -1: isSpecial = true; } cmd = MoodManager.getDefaultAction( "gain_effect", name ); if ( cmd.length() == 0 ) { if ( includeAll ) { cmd = "(find some way to remove " + name + ")"; } else continue; } sources = Collections.singletonList( cmd ).iterator(); } boolean haveVipKey = InventoryManager.getCount( ItemPool.VIP_LOUNGE_KEY ) > 0; boolean orFlag = false; while ( sources.hasNext() ) { if ( !KoLmafia.permitsContinue() ) { return; } cmd = text = sources.next(); AdventureResult item = null; if ( cmd.startsWith( "#" ) ) // usage note, no command { if ( includeAll ) { if ( cmd.contains( "BM" ) && !KoLCharacter.inBadMoon() ) { continue; // no use displaying this in non-BM } text = (orFlag ? "(...or get " : "(get ") + name + " via " + cmd.substring( 1 ) + ")"; orFlag = false; cmd = ""; } else continue; } if ( hasEffect && !cmd.toLowerCase().contains( name.toLowerCase() ) ) { text = text + " (to remove " + name + ")"; } if ( cmd.startsWith( "(" ) ) // preformatted note { cmd = ""; orFlag = false; } else if ( cmd.startsWith( "use " ) || cmd.startsWith( "chew " ) || cmd.startsWith( "drink " ) || cmd.startsWith( "eat " ) ) { // Hardcoded exception for "Trivia Master", which has a non-standard use command. if ( cmd.contains( "use 1 Trivial Avocations Card: What?, 1 Trivial Avocations Card: When?" ) && !MoodManager.canMasterTrivia() ) { continue; } // Can get Box of Sunshine in hardcore/ronin, but can't use it if ( !KoLCharacter.canInteract() && cmd.startsWith( "use 1 box of sunshine" ) ) { continue; } String iName = cmd.substring( cmd.indexOf( " " ) + 3 ).trim(); if ( cmd.startsWith( "use " ) ) { item = ItemFinder.getFirstMatchingItem( iName, false ); } else if ( cmd.startsWith( "chew " ) ) { item = ItemFinder.getFirstMatchingItem( iName, false, ItemFinder.SPLEEN_MATCH ); } else if ( cmd.startsWith( "drink " ) ) { item = ItemFinder.getFirstMatchingItem( iName, false, ItemFinder.BOOZE_MATCH ); } else if ( cmd.startsWith( "eat " ) ) { item = ItemFinder.getFirstMatchingItem( iName, false, ItemFinder.FOOD_MATCH ); } if ( item != null ) { // Resolve bang potions and slime vials int itemId = item.getItemId(); if ( itemId == -1 ) { item = item.resolveBangPotion(); itemId = item.getItemId(); } if ( itemId == -1 ) { continue; } Modifiers effMod = Modifiers.getItemModifiers( item.getItemId() ); if ( effMod != null ) { duration = (int) effMod.get( Modifiers.EFFECT_DURATION ); } } // Hot Dogs don't have items if ( item == null && ClanLoungeRequest.isHotDog( iName ) ) { if ( KoLCharacter.inBadMoon() ) { continue; } else if ( !StandardRequest.isAllowed( "Clan Item", "Clan Hot Dog Stand" ) ) { continue; } // Jarlsberg and Zombie characters can't eat hot dogs else if ( KoLCharacter.isJarlsberg() || KoLCharacter.isZombieMaster() ) { continue; } else if ( Limitmode.limitClan() ) { continue; } else if ( !haveVipKey ) { if ( includeAll ) { text = "( get access to the VIP lounge )"; cmd = ""; } else continue; } // Fullness available? int full = ClanLoungeRequest.hotdogNameToFullness( iName ); if ( full > 0 && KoLCharacter.getFullness() + full > KoLCharacter.getFullnessLimit() ) { continue; } // Is it Fancy and has one been used? if ( ClanLoungeRequest.isFancyHotDog( iName ) && Preferences.getBoolean( "_fancyHotDogEaten" ) ) { continue; } else { Modifiers effMod = Modifiers.getModifiers( "Item", iName ); if ( effMod != null ) { duration = (int) effMod.get( Modifiers.EFFECT_DURATION ); } usesRemaining = 1; } } else if ( item == null && !cmd.contains( "," ) ) { if ( includeAll ) { text = "(identify & " + cmd + ")"; cmd = ""; } else continue; } else if ( item != null ) { int itemId = item.getItemId(); usesRemaining = UseItemRequest.maximumUses( itemId ); if ( usesRemaining <= 0 ) { continue; } } } else if ( cmd.startsWith( "gong " ) ) { item = ItemPool.get( ItemPool.GONG, 1 ); advCost = 3; duration = 20; } else if ( cmd.startsWith( "cast " ) ) { String skillName = UneffectRequest.effectToSkill( name ); int skillId = SkillDatabase.getSkillId( skillName ); mpCost = SkillDatabase.getMPConsumptionById( skillId ); advCost = SkillDatabase.getAdventureCost( skillId ); soulsauceCost = SkillDatabase.getSoulsauceCost( skillId ); thunderCost = SkillDatabase.getThunderCost( skillId ); rainCost = SkillDatabase.getRainCost( skillId ); lightningCost = SkillDatabase.getLightningCost( skillId ); duration = SkillDatabase.getEffectDuration( skillId ); UseSkillRequest skill = UseSkillRequest.getUnmodifiedInstance( skillName ); if ( skill != null ) { usesRemaining = skill.getMaximumCast(); } if ( !KoLCharacter.hasSkill( skillName ) || usesRemaining == 0 ) { if ( includeAll ) { boolean isBuff = SkillDatabase.isBuff( skillId ); text = "(learn to " + cmd + (isBuff ? ", or get it from a buffbot)" : ")"); cmd = ""; } else continue; } } else if ( cmd.startsWith( "synthesize " ) ) { // You must know the skill if ( !KoLCharacter.hasSkill( "Sweet Synthesis" ) ) { if ( includeAll ) { text = "(learn the Sweet Synthesis skill)"; cmd = ""; } else continue; } // You must have a spleen available usesRemaining = KoLCharacter.getSpleenLimit() - KoLCharacter.getSpleenUse(); if ( usesRemaining < 1 ) { cmd = ""; } // You must have (or be able to get) a suitable pair of candies if ( CandyDatabase.synthesisPair( effectId ) == CandyDatabase.NO_PAIR ) { cmd = ""; } duration = 30; } else if ( cmd.startsWith( "friars " ) ) { int lfc = Preferences.getInteger( "lastFriarCeremonyAscension" ); int ka = Preferences.getInteger( "knownAscensions" ); if ( lfc < ka || Limitmode.limitZone( "Friars" ) ) { continue; } else if ( Preferences.getBoolean( "friarsBlessingReceived" ) ) { cmd = ""; } duration = 20; usesRemaining = Preferences.getBoolean( "friarsBlessingReceived" ) ? 0 : 1; } else if ( cmd.startsWith( "hatter " ) ) { boolean haveEffect = KoLConstants.activeEffects.contains( EffectPool .get( EffectPool.DOWN_THE_RABBIT_HOLE ) ); boolean havePotion = InventoryManager.hasItem( ItemPool.DRINK_ME_POTION ); if ( !havePotion && !haveEffect ) { continue; } else if ( !RabbitHoleManager.hatLengthAvailable( StringUtilities.parseInt( cmd .substring( 7 ) ) ) ) { continue; } else if ( Limitmode.limitZone( "RabbitHole" ) ) { continue; } else if ( Preferences.getBoolean( "_madTeaParty" ) ) { cmd = ""; } duration = 30; usesRemaining = Preferences.getBoolean( "_madTeaParty" ) ? 0 : 1; } else if ( cmd.startsWith( "mom " ) ) { if ( !QuestDatabase.isQuestFinished( Quest.SEA_MONKEES ) ) { continue; } else if ( Limitmode.limitZone( "The Sea" ) ) { continue; } else if ( Preferences.getBoolean( "_momFoodReceived" ) ) { cmd = ""; } duration = 50; usesRemaining = Preferences.getBoolean( "_momFoodReceived" ) ? 0 : 1; } else if ( cmd.startsWith( "summon " ) ) { if ( !QuestDatabase.isQuestFinished( Quest.MANOR ) ) { continue; } int onHand = InventoryManager.getAccessibleCount( ItemPool.EVIL_SCROLL ); int candles = InventoryManager.getAccessibleCount( ItemPool.BLACK_CANDLE ); int creatable = CreateItemRequest.getInstance( ItemPool.EVIL_SCROLL ) .getQuantityPossible(); if ( !KoLCharacter.canInteract() && ( ( onHand + creatable ) < 1 || candles < 3 ) ) { continue; } else if ( Limitmode.limitZone( "Manor0" ) ) { continue; } else if ( Preferences.getBoolean( "demonSummoned" ) ) { cmd = ""; } else { try { int num = Integer.parseInt( cmd.split( " " )[ 1 ] ); if ( Preferences.getString( "demonName" + num ).equals( "" ) ) { cmd = ""; } } catch ( Exception e ) { } } // Existential Torment is 20 turns, but won't appear here as the effects are unknown duration = 30; usesRemaining = Preferences.getBoolean( "demonSummoned" ) ? 0 : 1; } else if ( cmd.startsWith( "concert " ) ) { String side = Preferences.getString( "sidequestArenaCompleted" ); boolean available = false; if ( side.equals( "none" ) ) { continue; } else if ( Limitmode.limitZone( "Island" ) || Limitmode.limitZone( "IsleWar" ) ) { continue; } else if ( side.equals( "fratboy" ) ) { available = cmd.contains( "Elvish" ) || cmd.contains( "Winklered" ) || cmd.contains( "White-boy Angst" ); } else if ( side.equals( "hippy" ) ) { available = cmd.contains( "Moon" ) || cmd.contains( "Dilated" ) || cmd.contains( "Optimist" ); } if ( !available ) { continue; } else if ( Preferences.getBoolean( "concertVisited" ) ) { cmd = ""; } duration = 20; usesRemaining = Preferences.getBoolean( "concertVisited" ) ? 0 : 1; } else if ( cmd.startsWith( "telescope " ) ) { if ( Limitmode.limitCampground() ) { continue; } else if ( Preferences.getInteger( "telescopeUpgrades" ) == 0 ) { if ( includeAll ) { text = "( get a telescope )"; cmd = ""; } else continue; } else if ( KoLCharacter.inBadMoon() || KoLCharacter.inNuclearAutumn() ) { continue; } else if ( Preferences.getBoolean( "telescopeLookedHigh" ) ) { cmd = ""; } duration = 10; usesRemaining = Preferences.getBoolean( "telescopeLookedHigh" ) ? 0 : 1; } else if ( cmd.startsWith( "ballpit" ) ) { if ( !KoLCharacter.canInteract() ) { continue; } else if ( Limitmode.limitClan() ) { continue; } else if ( Preferences.getBoolean( "_ballpit" ) ) { cmd = ""; } duration = 20; usesRemaining = Preferences.getBoolean( "_ballpit" ) ? 0 : 1; } else if ( cmd.startsWith( "jukebox" ) ) { if ( !KoLCharacter.canInteract() ) { continue; } else if ( Limitmode.limitClan() ) { continue; } else if ( Preferences.getBoolean( "_jukebox" ) ) { cmd = ""; } duration = 10; usesRemaining = Preferences.getBoolean( "_jukebox" ) ? 0 : 1; } else if ( cmd.startsWith( "pool " ) ) { if ( KoLCharacter.inBadMoon() ) { continue; } else if ( !StandardRequest.isAllowed( "Clan Item", "Pool Table" ) ) { continue; } else if ( Limitmode.limitClan() ) { continue; } else if ( !haveVipKey ) { if ( includeAll ) { text = "( get access to the VIP lounge )"; cmd = ""; } else continue; } else if ( Preferences.getInteger( "_poolGames" ) >= 3 ) { cmd = ""; } duration = 10; usesRemaining = 3 - Preferences.getInteger( "_poolGames" ); } else if ( cmd.startsWith( "shower " ) ) { if ( KoLCharacter.inBadMoon() ) { continue; } else if ( !StandardRequest.isAllowed( "Clan Item", "April Shower" ) ) { continue; } else if ( Limitmode.limitClan() ) { continue; } else if ( !haveVipKey ) { if ( includeAll ) { text = "( get access to the VIP lounge )"; cmd = ""; } else continue; } else if ( Preferences.getBoolean( "_aprilShower" ) ) { cmd = ""; } duration = 50; usesRemaining = Preferences.getBoolean( "_aprilShower" ) ? 0 : 1; } else if ( cmd.startsWith( "swim " ) ) { if ( KoLCharacter.inBadMoon() ) { continue; } else if ( !StandardRequest.isAllowed( "Clan Item", "Clan Swimming Pool" ) ) { continue; } else if ( Limitmode.limitClan() ) { continue; } else if ( !haveVipKey ) { if ( includeAll ) { text = "( get access to the VIP lounge )"; cmd = ""; } else continue; } else if ( Preferences.getBoolean( "_olympicSwimmingPool" ) ) { cmd = ""; } duration = 50; usesRemaining = Preferences.getBoolean( "_olympicSwimmingPool" ) ? 0 : 1; } else if ( cmd.startsWith( "mayosoak" ) ) { AdventureResult workshed = CampgroundRequest.getCurrentWorkshedItem(); if ( KoLCharacter.inBadMoon() ) { continue; } else if ( !StandardRequest.isAllowed( "Items", "portable Mayo Clinic" ) ) { continue; } else if ( Limitmode.limitCampground() ) { continue; } else if ( workshed == null || workshed.getItemId() != ItemPool.MAYO_CLINIC ) { if ( includeAll ) { text = "( install portable Mayo Clinic )"; cmd = ""; } else continue; } else if ( Preferences.getBoolean( "_mayoTankSoaked" ) ) { cmd = ""; } duration = 20; usesRemaining = Preferences.getBoolean( "_mayoTankSoaked" ) ? 0 : 1; } else if ( cmd.startsWith( "barrelprayer" ) ) { if ( KoLCharacter.inBadMoon() ) { continue; } else if ( !StandardRequest.isAllowed( "Items", "shrine to the Barrel god" ) ) { continue; } else if ( Limitmode.limitZone( "Dungeon Full of Dungeons" ) ) { continue; } else if ( !Preferences.getBoolean( "barrelShrineUnlocked" ) ) { if ( includeAll ) { text = "( install shrine to the Barrel god )"; cmd = ""; } else continue; } else if ( Preferences.getBoolean( "_barrelPrayer" ) ) { cmd = ""; } duration = 50; usesRemaining = Preferences.getBoolean( "_barrelPrayer" ) ? 0 : 1; } else if ( cmd.startsWith( "styx " ) ) { if ( !KoLCharacter.inBadMoon() ) { continue; } else if ( Limitmode.limitZone( "BadMoon" ) ) { continue; } else if ( Preferences.getBoolean( "styxPixieVisited" ) ) { cmd = ""; } duration = 10; usesRemaining = Preferences.getBoolean( "styxPixieVisited" ) ? 0 : 1; } else if ( cmd.startsWith( "skate " ) ) { String status = Preferences.getString( "skateParkStatus" ); int buff = SkateParkRequest.placeToBuff( cmd.substring( 6 ) ); Object [] data = SkateParkRequest.buffToData( buff ); String buffPref = (String) data[4]; String buffStatus = (String) data[6]; if ( !status.equals( buffStatus ) ) { continue; } else if ( Limitmode.limitZone( "The Sea" ) ) { continue; } else if ( Preferences.getBoolean( buffPref ) ) { cmd = ""; } duration = 30; usesRemaining = Preferences.getBoolean( buffPref ) ? 0 : 1; } else if ( cmd.startsWith( "gap " ) ) { AdventureResult pants = EquipmentManager.getEquipment( EquipmentManager.PANTS ); if ( InventoryManager.getAccessibleCount( ItemPool.GREAT_PANTS ) == 0 ) { if ( includeAll ) { text = "(acquire and equip Greatest American Pants for " + name + ")"; cmd = ""; } else { continue; } } else if ( Preferences.getInteger( "_gapBuffs" ) >= 5 ) { cmd = ""; } else if ( pants == null || ( pants.getItemId() != ItemPool.GREAT_PANTS ) ) { text = "(equip Greatest American Pants for " + name + ")"; cmd = ""; } if ( name.equals( "Super Skill" ) ) { duration = 5; } else if ( name.equals( "Super Structure" ) || name.equals( "Super Accuracy" ) ) { duration = 10; } else if ( name.equals( "Super Vision" ) || name.equals( "Super Speed" ) ) { duration = 20; } usesRemaining = 5 - Preferences.getInteger( "_gapBuffs" ); } else if ( cmd.startsWith( "spacegate" ) ) { if ( !StandardRequest.isAllowed( "Items", "Spacegate access badge" ) ) { continue; } boolean available = Preferences.getBoolean( "spacegateAlways" ) || Preferences.getBoolean( "_spacegateToday" ); String number = cmd.substring( cmd.length() - 1 ); String setting = "spacegateVaccine" + number; boolean vaccineAvailable = Preferences.getBoolean( setting ); if ( !available || !vaccineAvailable ) { if ( includeAll ) { text = "(unlock Spacegate and vaccine " + number + " for " + name + ")"; cmd = ""; } else { continue; } } else if ( Preferences.getBoolean( "_spacegateVaccine" ) ) { cmd = ""; } } else if ( cmd.startsWith( "play" ) ) { if ( InventoryManager.getAccessibleCount( ItemPool.DECK_OF_EVERY_CARD ) == 0 ) { if ( includeAll ) { text = "(acquire Deck of Every Card for " + name + ")"; cmd = ""; } else { continue; } } else if ( Preferences.getInteger( "_deckCardsDrawn" ) > 10 ) { cmd = ""; } duration = 20; usesRemaining = ( 15 - Preferences.getInteger( "_deckCardsDrawn" ) ) / 5; } else if ( cmd.startsWith( "grim" ) ) { FamiliarData fam = KoLCharacter.findFamiliar( FamiliarPool.GRIM_BROTHER ); if ( fam == null ) { if ( Limitmode.limitFamiliars() ) { continue; } else if ( includeAll ) { text = "(get a Grim Brother familiar for " + name + ")"; cmd = ""; } else { continue; } } else if ( Preferences.getBoolean( "_grimBuff" ) ) { cmd = ""; } duration = 30; usesRemaining = Preferences.getBoolean( "_grimBuff" ) ? 0 : 1; } else if ( cmd.equals( "witchess" ) ) { if ( !KoLConstants.campground.contains( ItemPool.get( ItemPool.WITCHESS_SET, 1 ) ) ) { if ( includeAll ) { text = "(install Witchess Set for " + name + ")"; cmd = ""; } else { continue; } } else if ( Preferences.getBoolean( "_witchessBuff" ) ) { cmd = ""; } else if ( Preferences.getInteger( "puzzleChampBonus" ) != 20 ) { text = "(manually get " + name + ")"; cmd = ""; } duration = 25; usesRemaining = Preferences.getBoolean( "_witchessBuff" ) ? 0 : 1; } else if ( cmd.equals( "crossstreams" ) ) { if ( InventoryManager.getAccessibleCount( ItemPool.PROTON_ACCELERATOR ) == 0 ) { if ( includeAll ) { text = "(acquire protonic accelerator pack and crossstreams for " + name + ")"; cmd = ""; } else { continue; } } else if ( Preferences.getBoolean( "_streamsCrossed" ) ) { cmd = ""; } duration = 10; usesRemaining = Preferences.getBoolean( "_streamsCrossed" ) ? 0 : 1; } else if ( cmd.startsWith( "terminal enhance" ) ) { int limit = 1; String chips = Preferences.getString( "sourceTerminalChips" ); String files = Preferences.getString( "sourceTerminalEnhanceKnown" ); if ( chips.contains( "CRAM" ) ) limit++; if ( chips.contains( "SCRAM" ) ) limit++; boolean haveTerminal = KoLConstants.campground.contains( ItemPool.get( ItemPool.SOURCE_TERMINAL, 1 ) ) || KoLConstants.falloutShelter.contains( ItemPool.get( ItemPool.SOURCE_TERMINAL, 1 ) ); if ( !haveTerminal ) { if ( includeAll ) { text = "(install Source Terminal for " + name + ")"; cmd = ""; } else { continue; } } else if ( cmd.contains( name ) && !files.contains( name ) ) { if ( includeAll ) { text = "(install Source terminal file: " + name + " for " + name + ")"; cmd = ""; } else { continue; } } else { if ( Preferences.getInteger( "_sourceTerminalEnhanceUses" ) >= limit ) { cmd = ""; } } duration = 25 + ( chips.contains( "INGRAM" ) ? 25 : 0 ) + 5*Preferences.getInteger( "sourceTerminalPram" ); usesRemaining = limit - Preferences.getInteger( "_sourceTerminalEnhanceUses" ); } else if ( cmd.startsWith( "campground vault3" ) ) { if ( !KoLCharacter.inNuclearAutumn() ) { continue; } if ( Preferences.getInteger( "falloutShelterLevel" ) < 3 ) { continue; } else if ( Limitmode.limitCampground() ) { continue; } else if ( Preferences.getBoolean( "_falloutShelterSpaUsed" ) ) { cmd = ""; } duration = 100; usesRemaining = Preferences.getBoolean( "_falloutShelterSpaUsed" ) ? 0 : 1; } else if ( cmd.startsWith( "skeleton " ) ) { item = ItemPool.get( ItemPool.SKELETON, 1 ); duration = 30; } else if ( cmd.startsWith( "toggle" ) ) { if ( !KoLConstants.activeEffects.contains( EffectPool.get( EffectPool.INTENSELY_INTERESTED ) ) && !KoLConstants.activeEffects.contains( EffectPool.get( EffectPool.SUPERFICIALLY_INTERESTED ) ) ) { continue; } } if ( item != null ) { String iname = item.getName(); if ( KoLCharacter.inBeecore() && KoLCharacter.getBeeosity( iname ) > 0 ) { continue; } if ( !StandardRequest.isAllowed( "Items", iname ) ) { continue; } int full = ConsumablesDatabase.getFullness( iname ); if ( full > 0 && KoLCharacter.getFullness() + full > KoLCharacter.getFullnessLimit() ) { cmd = ""; } full = ConsumablesDatabase.getInebriety( iname ); if ( full > 0 && KoLCharacter.getInebriety() + full > KoLCharacter.getInebrietyLimit() ) { cmd = ""; } full = ConsumablesDatabase.getSpleenHit( iname ); if ( full > 0 && !cmd.contains( "chew" ) ) { RequestLogger.printLine( "(Note: extender for " + name + " is a spleen item that doesn't use 'chew')" ); } if ( full > 0 && KoLCharacter.getSpleenUse() + full > KoLCharacter.getSpleenLimit() ) { cmd = ""; } if ( !ConsumablesDatabase.meetsLevelRequirement( iname ) ) { if ( includeAll ) { text = "level up & " + text; cmd = ""; } else continue; } if ( cmd.length() > 0 ) { Concoction c = ConcoctionPool.get( item ); price = c.price; itemsCreatable = c.creatable; int count = Math.max( 0, item.getCount() - c.initial ); if ( count > 0 ) { int create = Math.min( count, c.creatable ); count -= create; if ( create > 0 ) { text = create > 1 ? "make " + create + " & " + text : "make & " + text; } int buy = price > 0 ? Math.min( count, KoLCharacter.getAvailableMeat() / price ) : 0; count -= buy; if ( buy > 0 && InventoryManager.canUseNPCStores( item ) ) { text = buy > 1 ? "buy " + buy + " & " + text : "buy & " + text; cmd = "buy " + buy + " \u00B6" + item.getItemId() + ";" + cmd; } if ( count > 0 ) { if ( !InventoryManager.canUseMall( item ) ) { continue; } text = count > 1 ? "acquire " + count + " & " + text : "acquire & " + text; } } if ( priceLevel == 2 || (priceLevel == 1 && count > 0) ) { if ( price <= 0 && InventoryManager.canUseMall ( item ) ) { if ( MallPriceDatabase.getPrice( item.getItemId() ) > maxPrice * 2 ) { continue; } // Depending on preference, either get historical mall price or look it up if ( Preferences.getBoolean( "maximizerCurrentMallPrices" ) ) { price = StoreManager.getMallPrice( item ); } else { price = StoreManager.getMallPrice( item, 7.0f ); } } } if ( price > maxPrice || price == -1 ) continue; } else if ( item.getCount( KoLConstants.inventory ) == 0 ) { continue; } itemsRemaining = item.getCount( KoLConstants.inventory ); } text = text + " ("; if ( advCost > 0 ) { text += advCost + " adv, "; if ( advCost > KoLCharacter.getAdventuresLeft() ) { cmd = ""; } } if ( mpCost > 0 ) { text += mpCost + " mp, "; // Don't ever grey out as we can recover MP } if ( soulsauceCost > 0 ) { text += soulsauceCost + " soulsauce, "; if ( soulsauceCost > KoLCharacter.getSoulsauce() ) { cmd = ""; } } if ( thunderCost > 0 ) { text += thunderCost + " dB of thunder, "; if ( thunderCost > KoLCharacter.getThunder() ) { cmd = ""; } } else if ( rainCost > 0 ) { text += rainCost + " drops of rain, "; if ( rainCost > KoLCharacter.getRain() ) { cmd = ""; } } else if ( lightningCost > 0 ) { text += lightningCost + " bolts of lightning, "; if ( lightningCost > KoLCharacter.getLightning() ) { cmd = ""; } } if ( price > 0 ) { text += KoLConstants.COMMA_FORMAT.format( price ) + " meat, "; if ( price > KoLCharacter.getAvailableMeat() ) { cmd = ""; } } text += KoLConstants.MODIFIER_FORMAT.format( delta ) + ")"; if ( Preferences.getBoolean( "verboseMaximizer" ) ) { boolean show = duration > 0 || ( usesRemaining > 0 && usesRemaining < Integer.MAX_VALUE ) || itemsRemaining + itemsCreatable > 0; int count = 0; if ( show ) { text += " ["; } if ( duration > 0 ) { if ( duration == 999 ) { text += "intrinsic"; } else if ( duration == 1 ) { text += "1 adv duration"; } else { text += duration + " advs duration"; } count++; } if ( usesRemaining > 0 && usesRemaining < Integer.MAX_VALUE ) { if ( count > 0 ) { text += ", "; } if ( usesRemaining == 1 ) { text += "1 use remaining"; count++; } else { text += usesRemaining + " uses remaining"; count++; } } if ( itemsRemaining > 0 ) { if ( count > 0 ) { text += ", "; } text += itemsRemaining + " in inventory"; count++; } if ( itemsCreatable > 0 ) { if ( count > 0 ) { text += ", "; } text += itemsCreatable + " creatable"; count++; } if ( show ) { text += "]"; } } if ( orFlag ) { text = "...or " + text; } Maximizer.boosts.add( new Boost( cmd, text, effect, hasEffect, item, delta, isSpecial ) ); orFlag = true; } } if ( Maximizer.boosts.size() == 0 ) { Maximizer.boosts.add( new Boost( "", "(nothing useful found)", 0, null, 0.0 ) ); } Maximizer.boosts.sort(); } private static int emitSlot( int slot, int equipLevel, int maxPrice, int priceLevel, double current ) { if ( slot == EquipmentManager.FAMILIAR ) { // Insert any familiar switch at this point FamiliarData fam = Maximizer.best.getFamiliar(); if ( !fam.equals( KoLCharacter.getFamiliar() ) ) { MaximizerSpeculation spec = new MaximizerSpeculation(); spec.setFamiliar( fam ); double delta = spec.getScore() - current; String cmd, text; cmd = "familiar " + fam.getRace(); text = cmd + " (" + KoLConstants.MODIFIER_FORMAT.format( delta ) + ")"; Boost boost = new Boost( cmd, text, fam, delta ); if ( equipLevel == -1 ) { // called from CLI boost.execute( true ); if ( !KoLmafia.permitsContinue() ) equipLevel = 1; } else { Maximizer.boosts.add( boost ); } } } String slotname = EquipmentRequest.slotNames[ slot ]; AdventureResult item = Maximizer.best.equipment[ slot ]; int itemId = -1; FamiliarData enthroned = Maximizer.best.getEnthroned(); FamiliarData bjorned = Maximizer.best.getBjorned(); String edPiece = Maximizer.best.getEdPiece(); String snowsuit = Maximizer.best.getSnowsuit(); AdventureResult curr = EquipmentManager.getEquipment( slot ); FamiliarData currEnthroned = KoLCharacter.getEnthroned(); FamiliarData currBjorned = KoLCharacter.getBjorned(); String currEdPiece = Preferences.getString( "edPiece" ); Boolean setEdPiece = false; String currSnowsuit = Preferences.getString( "snowsuit" ); Boolean setSnowsuit = false; if ( item == null ) { item = EquipmentRequest.UNEQUIP; } else { itemId = item.getItemId(); } if ( curr.equals( item ) && !( itemId == ItemPool.HATSEAT && enthroned != currEnthroned ) && !( itemId == ItemPool.BUDDY_BJORN && bjorned != currBjorned ) && !( itemId == ItemPool.CROWN_OF_ED && edPiece != null && !edPiece.equals( currEdPiece ) ) && !( itemId == ItemPool.SNOW_SUIT && snowsuit != null && !snowsuit.equals( currSnowsuit ) ) ) { if ( slot >= EquipmentManager.SLOTS || curr.equals( EquipmentRequest.UNEQUIP ) || equipLevel == -1 ) { return equipLevel; } Maximizer.boosts.add( new Boost( "", "keep " + slotname + ": " + item.getName(), -1, item, 0.0 ) ); return equipLevel; } MaximizerSpeculation spec = new MaximizerSpeculation(); spec.equip( slot, item ); if ( itemId == ItemPool.HATSEAT ) { spec.setEnthroned( enthroned ); } else if ( itemId == ItemPool.BUDDY_BJORN ) { spec.setBjorned( bjorned ); } else if ( itemId == ItemPool.CROWN_OF_ED ) { spec.setEdPiece( edPiece ); } else if ( itemId == ItemPool.SNOW_SUIT ) { spec.setSnowsuit( snowsuit ); } double delta = spec.getScore() - current; String cmd, text; if ( item.equals( EquipmentRequest.UNEQUIP ) ) { item = curr; cmd = "unequip " + slotname; text = cmd + " (" + curr.getName() + ", " + KoLConstants.MODIFIER_FORMAT.format( delta ) + ")"; } else { if ( itemId == ItemPool.HATSEAT && enthroned != currEnthroned ) { cmd = "enthrone " + enthroned.getRace(); text = cmd; } else if ( itemId == ItemPool.BUDDY_BJORN && bjorned != currBjorned ) { cmd = "bjornify " + bjorned.getRace(); text = cmd; } else if ( itemId == ItemPool.CROWN_OF_ED && edPiece != currEdPiece ) { cmd = "edpiece " + edPiece; text = cmd; setEdPiece = true; } else if ( itemId == ItemPool.SNOW_SUIT && snowsuit != currSnowsuit ) { cmd = "snowsuit " + snowsuit; text = cmd; setSnowsuit = true; } else { cmd = "equip " + slotname + " \u00B6" + item.getItemId(); text = "equip " + slotname + " " + item.getName(); } text = text + " ("; CheckedItem checkedItem = new CheckedItem( itemId, equipLevel, maxPrice, priceLevel ); int price = 0; // How many have been needed so far to make this maximization set? // We need 1 + that number to equip this item, not just 1 int count = 0; // If we're running from command line then execute them straight away, // so we have to count how much we've used in 'earlier' items if ( equipLevel == -1 ) { for ( int piece = EquipmentManager.HAT ; piece < slot ; piece++ ) { AdventureResult equipped = EquipmentManager.getEquipment( piece ); if ( equipped != null && item.getItemId() == equipped.getItemId() ) { count++; } } } else // Otherwise we iterate through the maximization set so far { Iterator i = Maximizer.boosts.iterator(); while ( i.hasNext() ) { Object boost = i.next(); if ( boost instanceof Boost ) { if ( item.equals( ((Boost) boost).getItem() ) ) { count++; } } } } // The "initial" quantity comes from InventoryManager.getAccessibleCount. // It can include inventory, closet, and storage. However, anything that // is included should also be supported by retrieveItem(), so we don't need // to take any special action here. Displaying the method that will be used // would still be useful, though. if ( curr.equals( item ) ) { } else if ( checkedItem.initial > count ) { // This may look odd, but we need an item, not a checked item // The count of a checked item includes creatable, buyable, pullable etc. String method = InventoryManager.simRetrieveItem( ItemPool.get( item.getItemId(), count + 1 ), equipLevel == -1, false ); if ( !method.equals( "have" ) ) { text = method + " & " + text; } if ( method.equals( "uncloset" ) ) { cmd = "closet take 1 \u00B6" + item.getItemId() + ";" + cmd; } else if ( method.equals( "unstash" ) ) { cmd = "stash take 1 \u00B6" + item.getItemId() + ";" + cmd; } // Should be only hitting this after Ronin I think else if ( method.equals( "pull" ) ) { cmd = "pull 1 \u00B6" + item.getItemId() + ";" + cmd; } } else if ( checkedItem.creatable + checkedItem.initial > count ) { text = "make & " + text; cmd = "make \u00B6" + item.getItemId() + ";" + cmd; } else if ( checkedItem.npcBuyable + checkedItem.initial > count ) { text = "buy & " + text; cmd = "buy 1 \u00B6" + item.getItemId() + ";" + cmd; price = ConcoctionPool.get( item ).price; } else if ( checkedItem.foldable + checkedItem.initial > count ) { // We assume that there is only one available fold item type of the right group. // Not always right, but will do for now. String method = InventoryManager.simRetrieveItem( ItemPool.get( checkedItem.foldItemId, count + 1 ) ); if ( method.equals( "have" ) || method.equals( "remove" ) ) { text = "fold & " + text; cmd = "fold \u00B6" + item.getItemId() + ";" + cmd; } else { text = method + " & fold & " + text; cmd = "acquire 1 \u00B6" + checkedItem.foldItemId + ";fold \u00B6" + item.getItemId() + ";" + cmd; } } else if ( checkedItem.pullable + checkedItem.initial > count ) { text = "pull & " + text; cmd = "pull \u00B6" + item.getItemId() + ";" + cmd; } else if ( checkedItem.pullfoldable + checkedItem.initial > count ) { // We assume that there is only one available fold item type of the right group. // Not always right, but will do for now. text = "pull & fold & " + text; cmd = "pull 1 \u00B6" + checkedItem.foldItemId + ";fold \u00B6" + item.getItemId() + ";" + cmd; } else // Mall buyable { text = "acquire & " + text; if ( priceLevel > 0 ) { price = StoreManager.getMallPrice( item ); } } if ( price > 0 ) { text = text + KoLConstants.COMMA_FORMAT.format( price ) + " meat, "; } text = text + KoLConstants.MODIFIER_FORMAT.format( delta ) + ")"; } if ( !setEdPiece ) { edPiece = null; } if ( !setSnowsuit ) { snowsuit = null; } Boost boost = new Boost( cmd, text, slot, item, delta, enthroned, bjorned, edPiece, snowsuit ); if ( equipLevel == -1 ) { // called from CLI boost.execute( true ); if ( !KoLmafia.permitsContinue() ) { equipLevel = 1; Maximizer.boosts.add( boost ); } } else { Maximizer.boosts.add( boost ); } return equipLevel; } }