/** * 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.io.BufferedReader; import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.java.dev.spellcast.utilities.LockableListModel; import net.java.dev.spellcast.utilities.SortedListModel; import net.sourceforge.kolmafia.AdventureResult; import net.sourceforge.kolmafia.KoLCharacter; import net.sourceforge.kolmafia.KoLConstants; import net.sourceforge.kolmafia.KoLConstants.MafiaState; import net.sourceforge.kolmafia.KoLmafia; import net.sourceforge.kolmafia.RequestLogger; import net.sourceforge.kolmafia.objectpool.IntegerPool; import net.sourceforge.kolmafia.objectpool.ItemPool; import net.sourceforge.kolmafia.persistence.ItemDatabase; import net.sourceforge.kolmafia.preferences.Preferences; import net.sourceforge.kolmafia.session.InventoryManager; import net.sourceforge.kolmafia.session.ResultProcessor; import net.sourceforge.kolmafia.utilities.BooleanArray; import net.sourceforge.kolmafia.utilities.FileUtilities; import net.sourceforge.kolmafia.utilities.StringUtilities; public class ZapRequest extends GenericRequest { private static final Pattern ZAP_PATTERN = Pattern.compile( "whichitem=(\\d+)" ); private static final Pattern OPTION_PATTERN = Pattern.compile( "<option value=(\\d+) descid='.*?'>.*?</option>" ); private static final BooleanArray isZappable = new BooleanArray(); private static final SortedListModel<AdventureResult> zappableItems = new SortedListModel<AdventureResult>(); private static final HashMap zapGroups = new HashMap(); private AdventureResult item; public ZapRequest( final AdventureResult item ) { super( "wand.php" ); this.item = null; if ( KoLCharacter.getZapper() == null ) { return; } this.item = item; this.addFormField( "action", "zap" ); this.addFormField( "whichwand", String.valueOf( KoLCharacter.getZapper().getItemId() ) ); this.addFormField( "whichitem", String.valueOf( item.getItemId() ) ); } private static final void initializeList() { if ( !ZapRequest.zappableItems.isEmpty() ) { return; } try { String line; BufferedReader reader = FileUtilities.getVersionedReader( "zapgroups.txt", KoLConstants.ZAPGROUPS_VERSION ); while ( ( line = FileUtilities.readLine( reader ) ) != null ) { String[] list = line.split( "\\s*,\\s*" ); for ( int i = 0; i < list.length; ++i ) { String name = list[ i ]; int itemId = ItemDatabase.getItemId( name, 1, false ); if ( itemId < 0 ) { RequestLogger.printLine( "Unknown item in zap group: " + name ); continue; } ZapRequest.zappableItems.add( ItemPool.get( itemId ) ); ZapRequest.isZappable.set( itemId, true ); ZapRequest.zapGroups.put( IntegerPool.get( itemId ), list ); } } } catch ( Exception e ) { e.printStackTrace(); } } public static final LockableListModel<AdventureResult> getZappableItems() { ZapRequest.initializeList(); SortedListModel<AdventureResult> matchingItems = new SortedListModel<AdventureResult>(); matchingItems.addAll( KoLConstants.inventory ); if ( Preferences.getBoolean( "relayTrimsZapList" ) ) { matchingItems.retainAll( ZapRequest.zappableItems ); } return matchingItems; } public static final String[] getZapGroup( int itemId ) { ZapRequest.initializeList(); String[] rv = (String[]) ZapRequest.zapGroups.get( IntegerPool.get( itemId ) ); if ( rv == null ) return new String[ 0 ]; return rv; } @Override public void run() { if ( this.item == null ) { return; } if ( KoLCharacter.getZapper() == null ) { KoLmafia.updateDisplay( MafiaState.ERROR, "You don't have a wand." ); return; } if ( InventoryManager.hasItem( this.item, true ) ) { InventoryManager.retrieveItem( this.item ); } if ( !KoLConstants.inventory.contains( this.item ) ) { KoLmafia.updateDisplay( MafiaState.ERROR, "You don't have a " + this.item.getName() + "." ); return; } KoLmafia.updateDisplay( "Zapping " + this.item.getName() + "..." ); super.run(); } @Override public void processResults() { // Remove item if zap succeeded. Remove wand if it blew up. ZapRequest.parseResponse( this.getURLString(), this.responseText ); // "The Crown of the Goblin King shudders for a moment, but // nothing happens." if ( this.responseText.indexOf( "nothing happens" ) != -1 ) { KoLmafia.updateDisplay( MafiaState.ERROR, "The " + this.item.getName() + " is not zappable." ); return; } // Notify the user of success. KoLmafia.updateDisplay( this.item.getName() + " has been transformed." ); } public static final void parseResponse( final String urlString, final String responseText ) { if ( !urlString.startsWith( "wand.php" ) ) { return; } if ( responseText.indexOf( "nothing happens" ) != -1 ) { return; } // If it blew up, remove wand and zero usages if ( responseText.indexOf( "abruptly explodes" ) != -1 ) { ResultProcessor.processResult( KoLCharacter.getZapper().getNegation() ); // set to -1 because will be incremented below Preferences.setInteger( "_zapCount", -1 ); } Matcher itemMatcher = ZapRequest.ZAP_PATTERN.matcher( urlString ); if ( !itemMatcher.find() ) { return; } // Remove the item which was transformed. int itemId = StringUtilities.parseInt( itemMatcher.group( 1 ) ); ResultProcessor.removeItem( itemId ); // increment zap count Preferences.increment( "_zapCount" ); } public static final void decorate( final StringBuffer buffer ) { // Don't trim the list if user wants to see all items if ( !Preferences.getBoolean( "relayTrimsZapList" ) ) return; ZapRequest.initializeList(); int selectIndex = buffer.indexOf( "<select" ); if ( selectIndex == -1 ) return; selectIndex = buffer.indexOf( ">", selectIndex ) + 1; int endSelectIndex = buffer.indexOf( "</select>", selectIndex ); Matcher optionMatcher = ZapRequest.OPTION_PATTERN.matcher( buffer.substring( selectIndex, endSelectIndex ) ); buffer.delete( selectIndex, endSelectIndex ); int itemId; StringBuffer zappableOptions = new StringBuffer(); while ( optionMatcher.find() ) { itemId = Integer.parseInt( optionMatcher.group( 1 ) ); if ( itemId == 0 || ZapRequest.isZappable.get( itemId ) ) { zappableOptions.append( optionMatcher.group() ); } } buffer.insert( selectIndex, zappableOptions.toString() ); int pos = buffer.lastIndexOf( "</center>" ); buffer.insert( pos, "KoLmafia trimmed this list to the items it knows to be zappable, which may not include recently discovered or modified items. <a href=\"wand.php?whichwand=" + KoLCharacter.getZapper().getItemId() + "¬rim=1\">Click here</a> for the full list." ); } public static final boolean registerRequest( final String urlString ) { if ( !urlString.startsWith( "wand.php" ) ) { return false; } Matcher itemMatcher = ZapRequest.ZAP_PATTERN.matcher( urlString ); if ( !itemMatcher.find() ) { return true; } int itemId = StringUtilities.parseInt( itemMatcher.group( 1 ) ); AdventureResult item = ItemPool.get( itemId ); RequestLogger.updateSessionLog(); RequestLogger.updateSessionLog( "zap " + item.getName() ); return true; } }