/**
* 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.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sourceforge.kolmafia.KoLCharacter;
import net.sourceforge.kolmafia.RequestLogger;
import net.sourceforge.kolmafia.RequestThread;
import net.sourceforge.kolmafia.preferences.Preferences;
import net.sourceforge.kolmafia.utilities.StringUtilities;
public class FloristRequest
extends GenericRequest
{
private static boolean haveFlorist = true;
private static boolean floristChecked = false;
private static final Pattern FLOWER_PATTERN =
Pattern.compile( "<tr><td>([^>]*?)</td><td width.*?plant(\\d+)\\.gif.*?plant(\\d+)?\\.gif.*?plant(\\d+)?\\.gif.*?" );
private static final Pattern LOCATION_PATTERN = Pattern.compile( "Ah, <b>(.*)</b>!" );
private static String getLocation( final String responseText )
{
Matcher matcher = FloristRequest.LOCATION_PATTERN.matcher( responseText );
return matcher.find() ? matcher.group( 1 ) : null;
}
private static final Pattern OPTION_PATTERN = Pattern.compile( "option=(\\d+)" );
private static int getOption( final String urlString )
{
Matcher matcher = FloristRequest.OPTION_PATTERN.matcher( urlString );
return matcher.find() ? StringUtilities.parseInt( matcher.group( 1 ) ) : 0;
}
private static final Pattern PLANT_PATTERN = Pattern.compile( "plant=(\\d+)" );
private static int getPlant( final String urlString )
{
Matcher matcher = FloristRequest.PLANT_PATTERN.matcher( urlString );
return matcher.find() ? StringUtilities.parseInt( matcher.group( 1 ) ) : 0;
}
private static final Pattern DIG_PATTERN = Pattern.compile( "plnti=(\\d)" );
private static int getDigIndex( final String urlString )
{
Matcher matcher = FloristRequest.DIG_PATTERN.matcher( urlString );
return matcher.find() ? StringUtilities.parseInt( matcher.group( 1 ) ) : -1;
}
public static final Map<String, ArrayList<Florist>> floristPlants = new HashMap<String, ArrayList<Florist>>();
public enum Florist
{
// Outdoor Plants
RABID_DOGWOOD( 1, "Rabid Dogwood" ),
RUTABEGGAR( 2, "Rutabeggar" ),
RADISH( 3, "Rad-ish Radish" ),
ARTICHOKER( 4, "Artichoker" ),
SMOKERA( 5, "Smoke-ra" ),
SKUNK_CABBAGE( 6, "Skunk Cabbage" ),
DEADLY_CINNAMON( 7, "Deadly Cinnamon" ),
CELERY_STALKER( 8, "Celery Stalker" ),
LETTUCE_SPRAY( 9, "Lettuce Spray" ),
SELTZER_WATERCRESS( 10, "Seltzer Watercress" ),
// Indoor Plants
WAR_LILY( 11, "War Lily" ),
STEALING_MAGNOLIA( 12, "Stealing Magnolia" ),
CANNED_SPINACH( 13, "Canned Spinach" ),
IMPATIENS( 14, "Impatiens" ),
SPIDER_PLANT( 15, "Spider Plant" ),
RED_FERN( 16, "Red Fern" ),
BAMBOO( 17, "BamBOO!" ),
ARCTIC_MOSS( 18, "Arctic Moss" ),
ALOE_GUVNOR( 19, "Aloe Guv'nor" ),
PITCHER_PLANT( 20, "Pitcher Plant" ),
// Underground Plants
BLUSTERY_PUFFBALL( 21, "Blustery Puffball" ),
HORN_OF_PLENTY( 22, "Horn of Plenty" ),
WIZARD_WIG( 23, "Wizard's Wig" ),
SHUFFLE_TRUFFLE( 24, "Shuffle Truffle" ),
DIS_LICHEN( 25, "Dis Lichen" ),
LOOSE_MORELS( 26, "Loose Morels" ),
FOUL_TOADSTOOL( 27, "Foul Toadstool" ),
CHILLTERELLE( 28, "Chillterelle" ),
PORTLYBELLA( 29, "Portlybella" ),
MAX_HEADSHROOM( 30, "Max Headshroom" ),
// Underwater Plants
SPANKTON( 31, "Spankton" ),
KELPTOMANIAC( 32, "Kelptomaniac" ),
CROOKWEED( 33, "Crookweed" ),
ELECTRIC_EELGRASS( 34, "Electric Eelgrass" ),
DUCKWEED( 35, "Duckweed" ),
ORCA_ORCHID( 36, "Orca Orchid" ),
SARGASSUM( 37, "Sargassum" ),
SUBSEA_ROSE( 38, "Sub-Sea Rose" ),
SNORI( 39, "Snori" ),
UPSEA_DAISY( 40, "Up Sea Daisy" ),
;
private final int id;
private final String name;
private Florist( int id, String name )
{
this.id = id;
this.name = name;
}
@Override
public String toString()
{
return this.name;
}
public int id()
{
return this.id;
}
public static Florist getFlower( int id )
{
if ( id == 0 )
{
return null;
}
for ( Florist flower : Florist.values() )
{
if ( id == flower.id )
{
return flower;
}
}
return null;
}
public static Florist getFlower( String name )
{
if ( name == null )
{
return null;
}
for ( Florist flower : Florist.values() )
{
if ( name.equalsIgnoreCase( flower.name ) )
{
return flower;
}
}
return null;
}
public boolean isTerritorial()
{
return this.id % 10 == 1 || this.id % 10 == 2 || this.id % 10 == 3;
}
}
public static void reset()
{
FloristRequest.haveFlorist = true;
FloristRequest.floristChecked = false;
FloristRequest.floristPlants.clear();
}
// forestvillage.php?action=floristfriar
// choice.php?option=4&whichchoice=720&pwd
public FloristRequest()
{
super( "choice.php" );
this.addFormField( "whichchoice", "720" );
this.addFormField( "option", "4" );
}
public FloristRequest( int plant )
{
super( "choice.php" );
this.addFormField( "whichchoice", "720" );
this.addFormField( "option", "1" );
this.addFormField( "plant", String.valueOf( plant ) );
}
@Override
public void run()
{
if ( GenericRequest.abortIfInFightOrChoice() )
{
return;
}
if ( KoLCharacter.getLevel() < 2 )
{
return;
}
if ( FloristRequest.floristChecked && !FloristRequest.haveFlorist() )
{
return;
}
FloristRequest.floristChecked = true;
PlaceRequest forestVisit = new PlaceRequest( "forestvillage", "fv_friar", true );
RequestThread.postRequest( forestVisit );
if ( forestVisit.responseText != null && !forestVisit.responseText.contains( "The Florist Friar's Cottage" ) )
{
FloristRequest.setHaveFlorist( false );
return;
}
super.run();
}
public static boolean haveFlorist()
{
if ( !FloristRequest.floristChecked )
{
return false;
}
return FloristRequest.haveFlorist;
}
private static final void setHaveFlorist( final boolean haveFlorist )
{
FloristRequest.floristChecked = true;
FloristRequest.haveFlorist = haveFlorist;
}
public static final ArrayList<Florist> getPlants( String location )
{
if ( floristPlants.containsKey( location ) )
{
return floristPlants.get( location );
}
return null;
}
public static void parseResponse( final String urlString, final String responseText )
{
if ( !urlString.startsWith( "choice.php" ) || !urlString.contains( "whichchoice=720" ) )
{
return;
}
switch ( FloristRequest.getOption( urlString ) )
{
case 1:
{
int plant = FloristRequest.getPlant( urlString );
if ( plant == 0 )
{
return;
}
// The location is already full of plants
if ( responseText.contains( "You need to dig up a space." ) )
{
return;
}
// It's the wrong location type for that plant
if ( responseText.contains( "Invalid plant" ) )
{
return;
}
String location = FloristRequest.getLocation( responseText );
if ( location == null )
{
// Something went wrong and somehow wasn't caught by the previous cases
return;
}
FloristRequest.addPlant( location, plant );
return;
}
case 2:
if ( responseText.contains( "You dig up a plant." ) )
{
String location = FloristRequest.getLocation( responseText );
int digIndex = FloristRequest.getDigIndex( urlString );
FloristRequest.digPlant( location, digIndex );
}
return;
case 4:
if ( responseText.contains( "The Florist Friar's Cottage" ) )
{
FloristRequest.setHaveFlorist( true );
}
FloristRequest.floristPlants.clear();
Matcher matcher = FloristRequest.FLOWER_PATTERN.matcher( responseText );
while ( matcher.find() )
{
ArrayList<Florist> plantList = new ArrayList<Florist>();
String location = matcher.group( 1 );
int flower1 = StringUtilities.parseInt( matcher.group( 2 ) );
int flower2 = StringUtilities.parseInt( matcher.group( 3 ) );
int flower3 = StringUtilities.parseInt( matcher.group( 4 ) );
if ( flower1 != 0 )
{
plantList.add( Florist.getFlower( flower1 ) );
}
if ( flower2 != 0 )
{
plantList.add( Florist.getFlower( flower2 ) );
}
if ( flower3 != 0 )
{
plantList.add( Florist.getFlower( flower3 ) );
}
FloristRequest.floristPlants.put( location, plantList );
}
return;
}
}
private static final void addPlant( final String location, final int plantId )
{
Florist plant = Florist.getFlower( plantId );
if ( plant.isTerritorial() )
{
FloristRequest.clearTerritorial( location );
}
ArrayList<Florist> plants = FloristRequest.getPlants( location );
if ( plants == null )
{
plants = new ArrayList<Florist>();
}
plants.add( plant );
FloristRequest.floristPlants.put( location, plants );
StringBuilder floristUsed = new StringBuilder();
floristUsed.append( Preferences.getString( "_floristPlantsUsed" ) );
if ( floristUsed.length() > 0 )
{
floristUsed.append( "," );
}
floristUsed.append( plant );
Preferences.setString( "_floristPlantsUsed", floristUsed.toString() );
}
private static final void clearTerritorial( final String location )
{
ArrayList<Florist> plants = FloristRequest.getPlants( location );
if ( plants == null )
{
return;
}
for ( Florist plant : plants )
{
if ( plant.isTerritorial() )
{
plants.remove( plant );
FloristRequest.floristPlants.put( location, plants );
// There can only be 1 territorial plant, so once we find it we are done
return;
}
}
}
private static final void digPlant( final String location, final int digIndex )
{
ArrayList<Florist> plants = FloristRequest.getPlants( location );
if ( plants == null )
{
return;
}
if ( digIndex >= plants.size() )
{
// This should only happen when KoL and KoLmafia use different names for a location
// KoLmafia's tracking will be wrong, but that can't be helped
return;
}
plants.remove( digIndex );
FloristRequest.floristPlants.put( location, plants );
}
public static boolean registerRequest( final String urlString )
{
if ( !urlString.startsWith( "choice.php" ) || !urlString.contains( "whichchoice=720" ) )
{
return false;
}
int option = FloristRequest.getOption( urlString );
String message = null;
switch (option )
{
case 1:
{
int plantId = FloristRequest.getPlant( urlString );
if ( plantId > 0 )
{
Florist plant = Florist.getFlower( plantId );
message = "Planting a " + plant;
}
break;
}
case 2:
{
int digIndex = FloristRequest.getDigIndex( urlString );
if ( digIndex >= 0 )
{
message = "Digging up plant # " + ( digIndex + 1 );
}
break;
}
case 4:
// Visiting the Florist Friar
return true;
}
if ( message != null )
{
RequestLogger.printLine();
RequestLogger.printLine( message );
RequestLogger.updateSessionLog();
RequestLogger.updateSessionLog( message );
return true;
}
// Unknown. Log it.
return false;
}
}