/**
* 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.Collections;
import java.util.List;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sourceforge.kolmafia.KoLCharacter;
import net.sourceforge.kolmafia.KoLConstants.MafiaState;
import net.sourceforge.kolmafia.KoLmafia;
import net.sourceforge.kolmafia.RequestThread;
import net.sourceforge.kolmafia.preferences.Preferences;
import net.sourceforge.kolmafia.request.GenericRequest;
import net.sourceforge.kolmafia.request.ProfileRequest;
import net.sourceforge.kolmafia.request.PeeVPeeRequest;
import net.sourceforge.kolmafia.utilities.InputFieldUtilities;
import net.sourceforge.kolmafia.utilities.StringUtilities;
public class PvpManager
{
// The current mapping of stances
public static final TreeMap<Integer,String> optionToStance = new TreeMap<Integer,String>();
public static final TreeMap<String,Integer> stanceToOption = new TreeMap<String,Integer>();
public static boolean stancesKnown = false;
// Support for fuzzy mapping of stance names
public static String [] canonicalStances = null;
public static final TreeMap<String,Integer> canonicalStanceToOption = new TreeMap<String,Integer>();
// <select name="stance"><option value="0" >Bear Hugs All Around</option><option value="1" selected>Beary Famous</option><option value="2" >Barely Dressed</option><option value="3" >Basket Reaver</option><option value="4" >Polar Envy</option><option value="5" >Maul Power</option><option value="6" >Grave Robbery</option><option value="7" >Most Things Eaten</option><option value="8" >Hibernation Ready</option><option value="9" >Visiting the Cousins</option><option value="10" >Northern Digestion</option><option value="11" >Most Murderous</option></select>
private static final Pattern STANCE_DROPDOWN_PATTERN = Pattern.compile( "<select name=\"stance\">.*?</select>", Pattern.DOTALL );
private static final Pattern STANCE_OPTION_PATTERN = Pattern.compile( "<option value=\"([\\d]*)\" (?:selected)?>(.*?)</option>" );
public static final boolean checkStances()
{
if ( !PvpManager.stancesKnown )
{
PeeVPeeRequest request = new PeeVPeeRequest( "fight" );
RequestThread.postRequest( request );
}
return PvpManager.stancesKnown;
}
public static final void parseStances( final String responseText )
{
Matcher stanceMatcher = PvpManager.STANCE_DROPDOWN_PATTERN.matcher( responseText );
if ( !stanceMatcher.find() )
{
return;
}
String stances = stanceMatcher.group( 0 );
PvpManager.optionToStance.clear();
PvpManager.stanceToOption.clear();
ArrayList<String> canonical = new ArrayList<String>();
Matcher optionsMatcher = PvpManager.STANCE_OPTION_PATTERN.matcher( stances );
while ( optionsMatcher.find() )
{
int option = StringUtilities.parseInt( optionsMatcher.group( 1 ) );
String stance = optionsMatcher.group( 2 );
PvpManager.optionToStance.put( option, stance );
PvpManager.stanceToOption.put( stance, option );
String canonicalStance = StringUtilities.getCanonicalName( stance );
PvpManager.canonicalStanceToOption.put( canonicalStance, option );
canonical.add( canonicalStance );
}
Collections.sort( canonical );
PvpManager.canonicalStances = new String[ canonical.size() ];
PvpManager.canonicalStances = canonical.toArray( PvpManager.canonicalStances );
PvpManager.stancesKnown = true;
}
public static final int findStance( final String stanceName )
{
List<String> matchingNames = StringUtilities.getMatchingNames( PvpManager.canonicalStances, stanceName );
if ( matchingNames.size() != 1 )
{
return -1;
}
String name = matchingNames.get( 0 );
Integer stance = PvpManager.canonicalStanceToOption.get( name );
return stance == null ? -1 : stance.intValue();
}
public static final String findStance( final int stance )
{
return PvpManager.optionToStance.get( stance );
}
private static boolean checkHippyStone()
{
if ( !KoLCharacter.getHippyStoneBroken() )
{
if ( !InputFieldUtilities.confirm( "Would you like to break your hippy stone?" ) )
{
KoLmafia.updateDisplay( MafiaState.ABORT, "This feature is not available to hippies." );
return false;
}
new GenericRequest( "peevpee.php?action=smashstone&confirm=on" ).run();
return KoLCharacter.getHippyStoneBroken();
}
return true;
}
public static void executePvpRequest( final int attacks, final String mission, final int stance )//
{
if ( !PvpManager.checkHippyStone() )
{
return;
}
PeeVPeeRequest request = new PeeVPeeRequest( "", stance, mission );
int availableFights = KoLCharacter.getAttacksLeft();
int totalFights = ( attacks > availableFights || attacks == 0 ) ? availableFights : attacks;
int fightsCompleted = 0;
while ( fightsCompleted++ < totalFights )
{
// Execute the beforePVPScript to change equipment, get
// buffs, whatever.
KoLmafia.executeBeforePVPScript();
// If the beforePVPScript aborts, stop before initiating a fight
if ( KoLmafia.refusesContinue() )
{
break;
}
KoLmafia.updateDisplay( "Attack " + fightsCompleted + " of " + totalFights );
RequestThread.postRequest( request );
// If he wants to abort the command, honor it
if ( KoLmafia.refusesContinue() )
{
break;
}
KoLmafia.forceContinue();
}
if ( KoLmafia.permitsContinue() )
{
KoLmafia.updateDisplay( "You have " + KoLCharacter.getAttacksLeft() + " attacks remaining." );
}
}
public static final void executePvpRequest( final ProfileRequest[] targets, final PeeVPeeRequest request, final int stance )
{
if ( !PvpManager.checkHippyStone() )
{
return;
}
for ( int i = 0; i < targets.length && KoLmafia.permitsContinue() && KoLCharacter.getAttacksLeft() > 0; ++i )
{
if ( targets[ i ] == null )
{
continue;
}
if ( Preferences.getString( "currentPvpVictories" ).contains( targets[ i ].getPlayerName() ) )
{
continue;
}
if ( targets[ i ].getPlayerName().toLowerCase().startsWith( "devster" ) )
{
continue;
}
// Execute the beforePVPScript to change equipment, get buffs, whatever.
KoLmafia.executeBeforePVPScript();
// Choose current "best" stance
// *** this is broken, as of Season 19
request.addFormField( "stance", String.valueOf( stance ) );
KoLmafia.updateDisplay( "Attacking " + targets[ i ].getPlayerName() + "..." );
request.setTarget( targets[ i ].getPlayerName() );
request.setTargetType( "0" );
RequestThread.postRequest( request );
if ( request.responseText.contains( "lost some dignity in the attempt" ) )
{
KoLmafia.updateDisplay( MafiaState.ERROR, "You lost to " + targets[ i ].getPlayerName() + "." );
}
}
}
}