/** * 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.request; import java.util.Map; import java.util.regex.Pattern; import java.util.regex.Matcher; import net.java.dev.spellcast.utilities.LockableListModel; import net.sourceforge.kolmafia.KoLmafia; import net.sourceforge.kolmafia.AdventureResult; import net.sourceforge.kolmafia.CoinmasterData; import net.sourceforge.kolmafia.KoLCharacter; import net.sourceforge.kolmafia.KoLConstants.MafiaState; import net.sourceforge.kolmafia.objectpool.ItemPool; import net.sourceforge.kolmafia.persistence.CoinmastersDatabase; import net.sourceforge.kolmafia.persistence.ItemDatabase; import net.sourceforge.kolmafia.preferences.Preferences; import net.sourceforge.kolmafia.utilities.StringUtilities; public class SwaggerShopRequest extends CoinMasterRequest { public static final String master = "The Swagger Shop"; private static final LockableListModel<AdventureResult> buyItems = CoinmastersDatabase.getBuyItems( SwaggerShopRequest.master ); private static final Map<Integer, Integer> buyPrices = CoinmastersDatabase.getBuyPrices( SwaggerShopRequest.master ); private static final Pattern TOKEN_PATTERN = Pattern.compile( "You have ([\\d,]+) swagger" ); public static final CoinmasterData SWAGGER_SHOP = new CoinmasterData( SwaggerShopRequest.master, "swagger", SwaggerShopRequest.class, "swagger", "You have 0 swagger", false, SwaggerShopRequest.TOKEN_PATTERN, null, "availableSwagger", null, "peevpee.php?place=shop", "buy", SwaggerShopRequest.buyItems, SwaggerShopRequest.buyPrices, null, null, null, null, "whichitem", GenericRequest.WHICHITEM_PATTERN, null, null, null, null, true ) { @Override public final int getBuyPrice( final int itemId ) { switch ( itemId ) { case ItemPool.BLACK_BARTS_BOOTY: return Preferences.getInteger( "blackBartsBootyCost" ); case ItemPool.HOLIDAY_FUN_BOOK: return Preferences.getInteger( "holidayHalsBookCost" ); case ItemPool.ANTAGONISTIC_SNOWMAN_KIT: return Preferences.getInteger( "antagonisticSnowmanKitCost" ); case ItemPool.MAP_TO_KOKOMO: return Preferences.getInteger( "mapToKokomoCost" ); case ItemPool.ESSENCE_OF_BEAR: return Preferences.getInteger( "essenceOfBearCost" ); case ItemPool.MANUAL_OF_NUMBEROLOGY: return Preferences.getInteger( "manualOfNumberologyCost" ); case ItemPool.ROM_OF_OPTIMALITY: return Preferences.getInteger( "ROMOfOptimalityCost" ); case ItemPool.SCHOOL_OF_HARD_KNOCKS_DIPLOMA: return Preferences.getInteger( "schoolOfHardKnocksDiplomaCost" ); case ItemPool.ESSENCE_OF_ANNOYANCE: return Preferences.getInteger( "essenceOfAnnoyanceCost" ); } return super.getBuyPrice( itemId ); } @Override public final boolean canBuyItem( final int itemId ) { switch ( itemId ) { case ItemPool.BLACK_BARTS_BOOTY: return Preferences.getBoolean( "blackBartsBootyAvailable" ); case ItemPool.HOLIDAY_FUN_BOOK: return Preferences.getBoolean( "holidayHalsBookAvailable" ); case ItemPool.ANTAGONISTIC_SNOWMAN_KIT: return Preferences.getBoolean( "antagonisticSnowmanKitAvailable" ); case ItemPool.MAP_TO_KOKOMO: return Preferences.getBoolean( "mapToKokomoAvailable" ); case ItemPool.ESSENCE_OF_BEAR: return Preferences.getBoolean( "essenceOfBearAvailable" ); case ItemPool.MANUAL_OF_NUMBEROLOGY: return Preferences.getBoolean( "manualOfNumberologyAvailable" ); case ItemPool.ROM_OF_OPTIMALITY: return Preferences.getBoolean( "ROMOfOptimalityAvailable" ); case ItemPool.SCHOOL_OF_HARD_KNOCKS_DIPLOMA: return Preferences.getBoolean( "schoolOfHardKnocksDiplomaAvailable" ); case ItemPool.ESSENCE_OF_ANNOYANCE: return Preferences.getBoolean( "essenceOfAnnoyanceAvailable" ); } return super.canBuyItem( itemId ); } }; static { SWAGGER_SHOP.plural = "swagger"; } public SwaggerShopRequest() { super( SwaggerShopRequest.SWAGGER_SHOP ); } public SwaggerShopRequest( final boolean buying, final AdventureResult [] attachments ) { super( SwaggerShopRequest.SWAGGER_SHOP, buying, attachments ); } public SwaggerShopRequest( final boolean buying, final AdventureResult attachment ) { super( SwaggerShopRequest.SWAGGER_SHOP, buying, attachment ); } public SwaggerShopRequest( final boolean buying, final int itemId, final int quantity ) { super( SwaggerShopRequest.SWAGGER_SHOP, buying, itemId, quantity ); } @Override public void run() { if ( this.action != null ) { if ( KoLCharacter.isHardcore() ) { KoLmafia.updateDisplay( MafiaState.ERROR, "You can't spend your swagger in Hardcore." ); return; } if ( KoLCharacter.inRonin() ) { KoLmafia.updateDisplay( MafiaState.ERROR, "You can't spend your swagger until you get out of Ronin." ); return; } } super.run(); } @Override public void processResults() { SwaggerShopRequest.parseResponse( this.getURLString(), this.responseText ); } // You've earned 600 swagger during a pirate season, yarrr. // You've earned 2 swagger during a holiday season, fun! // You've earned 0 swagger during an ice season, brrrr! // You've earned 152 swagger during a drunken season! // You've earned 0 swagger during bear season! // You've earned 0 swagger during a numeric season! // You've earned 37 swagger during an optimal season. // You've earned 0 swagger during a school season! private static final Pattern SEASON_PATTERN = Pattern.compile( "You've earned ([\\d,]+) swagger during (?:a |an |)(pirate|holiday|ice|drunken|bear|numeric|optimal|school) season" ); // <tr><td><img style='vertical-align: middle' class=hand src='http://images.kingdomofloathing.com/itemimages/radio.gif' onclick='descitem(475026869)'></td><td valign=center><b><span onclick='descitem(475026869)'>Huggler Radio<span>    </b></td><td><form style="padding:0;margin:0;"><input type="hidden" name="action" value="buy" /><input type="hidden" name="place" value="shop" /><input type="hidden" name="pwd" value="0c6efe5fe0c70235b340073785255041" /><input type="hidden" name="whichitem" value="5656" /><input type="submit" class="button" value="Buy (50 swagger)" /></form></td></tr> private static final Pattern ITEM_PATTERN = Pattern.compile( "<tr><td><img.*?onclick='descitem\\((.*?)\\)'.*?<b>(?:<[^>]*>)?([^<]*).*?</b>.*?name=\"whichitem\" value=\"(.*?)\".*?\\((.*?) swagger\\).*?</td></tr>", Pattern.DOTALL ); private static final AdventureResult BLACK_BARTS_BOOTY = ItemPool.get( ItemPool.BLACK_BARTS_BOOTY, 1 ); private static final AdventureResult HOLIDAY_FUN_BOOK = ItemPool.get( ItemPool.HOLIDAY_FUN_BOOK, 1 ); private static final AdventureResult ANTAGONISTIC_SNOWMAN_KIT = ItemPool.get( ItemPool.ANTAGONISTIC_SNOWMAN_KIT, 1 ); private static final AdventureResult MAP_TO_KOKOMO = ItemPool.get( ItemPool.MAP_TO_KOKOMO, 1 ); private static final AdventureResult ESSENCE_OF_BEAR = ItemPool.get( ItemPool.ESSENCE_OF_BEAR, 1 ); private static final AdventureResult MANUAL_OF_NUMBEROLOGY = ItemPool.get( ItemPool.MANUAL_OF_NUMBEROLOGY, 1 ); private static final AdventureResult ROM_OF_OPTIMALITY = ItemPool.get( ItemPool.ROM_OF_OPTIMALITY, 1 ); private static final AdventureResult SCHOOL_OF_HARD_KNOCKS_DIPLOMA = ItemPool.get( ItemPool.SCHOOL_OF_HARD_KNOCKS_DIPLOMA, 1 ); private static final AdventureResult ESSENCE_OF_ANNOYANCE = ItemPool.get( ItemPool.ESSENCE_OF_ANNOYANCE, 1 ); public static void parseResponse( final String urlString, final String responseText ) { CoinmasterData data = SwaggerShopRequest.SWAGGER_SHOP; String action = GenericRequest.getAction( urlString ); if ( action != null ) { CoinMasterRequest.parseResponse( data, urlString, responseText ); return; } // Learn new items by simply visiting the Swagger Shop // Refresh the Coin Master inventory every time we visit. LockableListModel<AdventureResult> items = SwaggerShopRequest.buyItems; Map prices = SwaggerShopRequest.buyPrices; items.clear(); prices.clear(); Matcher matcher = ITEM_PATTERN.matcher( responseText ); while ( matcher.find() ) { String descId = matcher.group(1); String itemName = matcher.group(2); int itemId = StringUtilities.parseInt( matcher.group(3) ); int price = StringUtilities.parseInt( matcher.group(4) ); String match = ItemDatabase.getItemDataName( itemId ); if ( match == null || !match.equals( itemName ) ) { ItemDatabase.registerItem( itemId, itemName, descId ); } // Add it to the Swagger Shop inventory AdventureResult item = ItemPool.get( itemId, PurchaseRequest.MAX_QUANTITY ); items.add( item ); prices.put( itemId, price ); switch ( itemId ) { case ItemPool.BLACK_BARTS_BOOTY: Preferences.setInteger( "blackBartsBootyCost", price ); break; case ItemPool.HOLIDAY_FUN_BOOK: Preferences.setInteger( "holidayHalsBookCost", price ); break; case ItemPool.ANTAGONISTIC_SNOWMAN_KIT: Preferences.setInteger( "antagonisticSnowmanKitCost", price ); break; case ItemPool.MAP_TO_KOKOMO: Preferences.setInteger( "mapToKokomoCost", price ); break; case ItemPool.ESSENCE_OF_BEAR: Preferences.setInteger( "essenceOfBearCost", price ); break; case ItemPool.MANUAL_OF_NUMBEROLOGY: Preferences.setInteger( "manualOfNumberologyCost", price ); break; case ItemPool.ROM_OF_OPTIMALITY: Preferences.setInteger( "ROMOfOptimalityCost", price ); break; case ItemPool.SCHOOL_OF_HARD_KNOCKS_DIPLOMA: Preferences.setInteger( "schoolOfHardKnocksDiplomaCost", price ); break; case ItemPool.ESSENCE_OF_ANNOYANCE: Preferences.setInteger( "essenceOfAnnoyanceCost", price ); break; } } // Find availability/cost of conditional items Preferences.setBoolean( "blackBartsBootyAvailable", items.contains( SwaggerShopRequest.BLACK_BARTS_BOOTY ) ); Preferences.setBoolean( "holidayHalsBookAvailable", items.contains( SwaggerShopRequest.HOLIDAY_FUN_BOOK ) ); Preferences.setBoolean( "antagonisticSnowmanKitAvailable", items.contains( SwaggerShopRequest.ANTAGONISTIC_SNOWMAN_KIT ) ); Preferences.setBoolean( "mapToKokomoAvailable", items.contains( SwaggerShopRequest.MAP_TO_KOKOMO ) ); Preferences.setBoolean( "essenceOfBearAvailable", items.contains( SwaggerShopRequest.ESSENCE_OF_BEAR ) ); Preferences.setBoolean( "manualOfNumberologyAvailable", items.contains( SwaggerShopRequest.MANUAL_OF_NUMBEROLOGY ) ); Preferences.setBoolean( "ROMOfOptimalityAvailable", items.contains( SwaggerShopRequest.ROM_OF_OPTIMALITY ) ); Preferences.setBoolean( "schoolOfHardKnocksDiplomaAvailable", items.contains( SwaggerShopRequest.SCHOOL_OF_HARD_KNOCKS_DIPLOMA ) ); Preferences.setBoolean( "essenceOfAnnoyanceAvailable", items.contains( SwaggerShopRequest.ESSENCE_OF_ANNOYANCE ) ); // Register the purchase requests, now that we know what is available data.registerPurchaseRequests(); // Parse current swagger CoinMasterRequest.parseBalance( data, responseText ); // If this is a special season, determine how much swagger has been found Matcher seasonMatcher = SwaggerShopRequest.SEASON_PATTERN.matcher( responseText ); if ( seasonMatcher.find() ) { int seasonSwagger = StringUtilities.parseInt( seasonMatcher.group( 1 ) ); String season = seasonMatcher.group( 2 ); if ( season.equals( "pirate" ) ) { Preferences.setInteger( "pirateSwagger", seasonSwagger ); } else if ( season.equals( "holiday" ) ) { Preferences.setInteger( "holidaySwagger", seasonSwagger ); } else if ( season.equals( "ice" ) ) { Preferences.setInteger( "iceSwagger", seasonSwagger ); } else if ( season.equals( "drunken" ) ) { Preferences.setInteger( "drunkenSwagger", seasonSwagger ); } else if ( season.equals( "bear" ) ) { Preferences.setInteger( "bearSwagger", seasonSwagger ); } else if ( season.equals( "numeric" ) ) { Preferences.setInteger( "numericSwagger", seasonSwagger ); } else if ( season.equals( "optimal" ) ) { Preferences.setInteger( "optimalSwagger", seasonSwagger ); } else if ( season.equals( "school" ) ) { Preferences.setInteger( "schoolSwagger", seasonSwagger ); } } } public static final boolean registerRequest( final String urlString ) { // We only claim peevpee.php?place=shop&action=buy if ( !urlString.startsWith( "peevpee.php" ) ) { return false; } if ( !urlString.contains( "place=shop" ) && !urlString.contains( "action=buy" ) ) { return false; } CoinmasterData data = SwaggerShopRequest.SWAGGER_SHOP; return CoinMasterRequest.registerRequest( data, urlString, true ); } public static String accessible() { if ( KoLCharacter.isHardcore() || KoLCharacter.inRonin() ) { return "Characters in Hardcore or Ronin cannot redeem Swagger"; } return null; } }