/**
* 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.textui.command;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.KoLmafiaCLI;
import net.sourceforge.kolmafia.persistence.HolidayDatabase;
import net.sourceforge.kolmafia.persistence.SkillDatabase;
import net.sourceforge.kolmafia.request.EquipmentRequest;
import net.sourceforge.kolmafia.request.HermitRequest;
import net.sourceforge.kolmafia.session.EquipmentManager;
import net.sourceforge.kolmafia.utilities.StringUtilities;
public abstract class ConditionalStatement
extends AbstractCommand
{
private static final Pattern STATDAY_PATTERN = Pattern.compile( "(today|tomorrow) is (.*?) day" );
{
this.flags = KoLmafiaCLI.FLOW_CONTROL_CMD;
}
/**
* Utility method which tests if the given condition is true. Note that this only examines level, health, mana,
* items, meat and status effects.
*/
public static final boolean test( final String parameters )
{
if ( !KoLmafia.permitsContinue() )
{
return false;
}
if ( parameters.equals( "" ) )
{
KoLmafia.updateDisplay( MafiaState.ERROR, "No condition specified." );
return false;
}
// Allow checking for moon signs for stat days
// only. Allow test for today and tomorrow.
Matcher dayMatcher = ConditionalStatement.STATDAY_PATTERN.matcher( parameters );
if ( dayMatcher.find() )
{
String statDayToday = HolidayDatabase.getMoonEffect().toLowerCase();
String statDayTest = dayMatcher.group( 2 ).substring( 0, 3 ).toLowerCase();
return statDayToday.indexOf( statDayTest ) != -1 && statDayToday.indexOf( "bonus" ) != -1 && statDayToday.indexOf( "not " + dayMatcher.group( 1 ) ) == -1;
}
// Check if the person is looking for whether or
// not they are a certain class.
if ( parameters.startsWith( "class is not " ) )
{
String className = parameters.substring( 13 ).trim().toLowerCase();
String actualClassName = KoLCharacter.getClassType().toLowerCase();
return actualClassName.indexOf( className ) == -1;
}
if ( parameters.startsWith( "class is " ) )
{
String className = parameters.substring( 9 ).trim().toLowerCase();
String actualClassName = KoLCharacter.getClassType().toLowerCase();
return actualClassName.indexOf( className ) != -1;
}
// Check if the person has a specific skill
// in their available skills list.
if ( parameters.startsWith( "skill list lacks " ) )
{
return !KoLCharacter.hasSkill( SkillDatabase.getSkillName( parameters.substring( 17 ).trim().toLowerCase() ) );
}
if ( parameters.startsWith( "skill list contains " ) )
{
return KoLCharacter.hasSkill( SkillDatabase.getSkillName( parameters.substring( 20 ).trim().toLowerCase() ) );
}
// Generic tests for numerical comparisons
// involving left and right values.
String operator =
parameters.indexOf( "==" ) != -1 ? "==" :
parameters.indexOf( "!=" ) != -1 ? "!=" :
parameters.indexOf( ">=" ) != -1 ? ">=" :
parameters.indexOf( "<=" ) != -1 ? "<=" :
parameters.indexOf( "=" ) != -1 ? "==" :
parameters.indexOf( "<>" ) != -1 ? "!=" :
parameters.indexOf( ">" ) != -1 ? ">" :
parameters.indexOf( "<" ) != -1 ? "<" :
null;
if ( operator == null )
{
KoLmafia.updateDisplay( MafiaState.ERROR, parameters + " contains no comparison operator." );
return false;
}
String[] tokens = parameters.split( "[\\!<>=]" );
String left = tokens[ 0 ].trim();
String right = tokens[ tokens.length - 1 ].trim();
int leftValue;
int rightValue;
try
{
leftValue = ConditionalStatement.lvalue( left );
rightValue = ConditionalStatement.rvalue( left, right );
}
catch ( Exception e )
{
// This should not happen. Therefore, print
// a stack trace for debug purposes.
KoLmafia.updateDisplay( MafiaState.ERROR, parameters + " is not a valid construct." );
return false;
}
return operator.equals( "==" ) ? leftValue == rightValue :
operator.equals( "!=" ) ? leftValue != rightValue :
operator.equals( ">=" ) ? leftValue >= rightValue :
operator.equals( ">" ) ? leftValue > rightValue :
operator.equals( "<=" ) ? leftValue <= rightValue :
operator.equals( "<" ) ? leftValue < rightValue :
false;
}
static final int lvalue( final String left )
{
if ( StringUtilities.isNumeric( left ) )
{
return StringUtilities.parseInt( left );
}
if ( left.equals( "level" ) )
{
return KoLCharacter.getLevel();
}
if ( left.equals( "health" ) )
{
return KoLCharacter.getCurrentHP();
}
if ( left.equals( "mana" ) )
{
return KoLCharacter.getCurrentMP();
}
if ( left.equals( "meat" ) )
{
return KoLCharacter.getAvailableMeat();
}
if ( left.equals( "adventures" ) )
{
return KoLCharacter.getAdventuresLeft();
}
if ( left.equals( "inebriety" ) || left.equals( "drunkenness" ) || left.equals( "drunkness" ) )
{
return KoLCharacter.getInebriety();
}
if ( left.equals( "muscle" ) )
{
return KoLCharacter.getBaseMuscle();
}
if ( left.equals( "mysticality" ) )
{
return KoLCharacter.getBaseMysticality();
}
if ( left.equals( "moxie" ) )
{
return KoLCharacter.getBaseMoxie();
}
if ( left.equals( "worthless item" ) )
{
return HermitRequest.getWorthlessItemCount();
}
if ( left.equals( "stickers" ) )
{
int count = 0;
for ( int i = EquipmentManager.STICKER1; i <= EquipmentManager.STICKER3; ++i )
{
AdventureResult item = EquipmentManager.getEquipment( i );
if ( !EquipmentRequest.UNEQUIP.equals( item ) )
{
++count;
}
}
return count;
}
AdventureResult item = AbstractCommand.itemParameter( left );
AdventureResult effect = AbstractCommand.effectParameter( left );
// If there is no question you're looking for one or
// the other, then return the appropriate match.
if ( item != null && effect == null )
{
return item.getCount( KoLConstants.inventory );
}
if ( item == null && effect != null )
{
return effect.getCount( KoLConstants.activeEffects );
}
// This breaks away from fuzzy matching so that a
// substring match is preferred over a fuzzy match.
// Items first for one reason: Knob Goblin perfume.
if ( item != null && item.getName().toLowerCase().indexOf( left.toLowerCase() ) != -1 )
{
return item.getCount( KoLConstants.inventory );
}
if ( effect != null && effect.getName().toLowerCase().indexOf( left.toLowerCase() ) != -1 )
{
return effect.getCount( KoLConstants.activeEffects );
}
// Now, allow fuzzy match results to return a value.
// Again, following the previous precident, items are
// preferred over effects.
if ( item != null )
{
return item.getCount( KoLConstants.inventory );
}
if ( effect != null )
{
return effect.getCount( KoLConstants.activeEffects );
}
// No match. The value is zero by default.
return 0;
}
static final int rvalue( final String left, String right )
{
if ( right.endsWith( "%" ) )
{
right = right.substring( 0, right.length() - 1 );
int value = StringUtilities.parseInt( right );
if ( left.equals( "health" ) )
{
return (int) ( (float) value * (float) KoLCharacter.getMaximumHP() / 100.0f );
}
if ( left.equals( "mana" ) )
{
return (int) ( (float) value * (float) KoLCharacter.getMaximumMP() / 100.0f );
}
return value;
}
for ( int i = 0; i < right.length(); ++i )
{
if ( !Character.isDigit( right.charAt( i ) ) )
{
// Items first for one reason: Knob Goblin perfume
// Determine which item is being matched.
AdventureResult item = AbstractCommand.itemParameter( right );
if ( item != null )
{
return item.getCount( KoLConstants.inventory );
}
AdventureResult effect = AbstractCommand.effectParameter( right );
if ( effect != null )
{
return effect.getCount( KoLConstants.activeEffects );
}
// If it is neither an item nor an effect, report
// the exception.
if ( i == 0 && right.charAt( 0 ) == '-' )
{
continue;
}
KoLmafia.updateDisplay(
MafiaState.ERROR, "Invalid operand [" + right + "] on right side of operator" );
}
}
// If it gets this far, then it must be numeric,
// so parse the number and return it.
return StringUtilities.parseInt( right );
}
}