/**
* 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.combat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.swing.tree.DefaultMutableTreeNode;
import net.sourceforge.kolmafia.KoLmafia;
import net.sourceforge.kolmafia.MonsterData;
import net.sourceforge.kolmafia.persistence.MonsterDatabase;
import net.sourceforge.kolmafia.preferences.Preferences;
import net.sourceforge.kolmafia.utilities.StringUtilities;
public class CustomCombatLookup
extends DefaultMutableTreeNode
{
private List childKeys = new LinkedList();
private Map childLookup = new TreeMap();
public CustomCombatLookup()
{
super( "", true );
}
public CustomCombatStrategy getStrategy( final String encounterKey )
{
return (CustomCombatStrategy) childLookup.get( encounterKey );
}
public String getBestEncounterKey( final String encounter )
{
String encounterKey = CombatActionManager.encounterKey( encounter );
MonsterData monsterData = MonsterDatabase.findMonster( encounterKey, false );
encounterKey = getLongestMatch( encounterKey, monsterData );
if ( encounterKey != null )
{
return encounterKey;
}
// If no matches were found, then see if there is a match
// against the adventure location.
String location = Preferences.getString( "lastAdventure" ).toLowerCase();
if ( monsterData == null )
{
// An unrecognized monster is likely to be:
// * something new that the player may want to see personally,
// so allow an [unrecognized] section to match them.
// * something fundamentally different from the known monsters
// in the current zone, so don't try to use a [zone name] match.
location = "unrecognized";
}
encounterKey = getLongestMatch( location, monsterData );
if ( encounterKey != null )
{
return encounterKey;
}
return "default";
}
private String getLongestMatch( final String encounter, MonsterData monsterData )
{
String longestMatch = null;
int longestMatchLength = 0;
for ( int i = 0; i < childKeys.size(); ++i )
{
CombatEncounterKey childKey = (CombatEncounterKey) childKeys.get( i );
if ( childKey.matches( encounter, monsterData ) )
{
String childName = childKey.toString();
if ( childName.length() > longestMatchLength )
{
longestMatch = childKey.toString();
longestMatchLength = childName.length();
}
}
}
return longestMatch;
}
public void clearEncounterKey( final String encounterKey )
{
Iterator strategyIterator = childLookup.values().iterator();
while ( strategyIterator.hasNext() )
{
CustomCombatStrategy strategy = (CustomCombatStrategy) strategyIterator.next();
if ( strategy.getName().equals( encounterKey ) )
{
strategy.removeAllChildren();
}
else
{
strategy.resetActionCount();
}
}
}
public void addEncounterKey( String encounterKey )
{
if ( childLookup.containsKey( encounterKey ) )
{
CustomCombatStrategy strategy = (CustomCombatStrategy) childLookup.get( encounterKey );
strategy.removeAllChildren();
}
else
{
CombatEncounterKey combatEncounterKey = new CombatEncounterKey( encounterKey );
encounterKey = combatEncounterKey.toString();
CustomCombatStrategy strategy = new CustomCombatStrategy( encounterKey );
childKeys.add( combatEncounterKey );
childLookup.put( encounterKey, strategy );
super.add( strategy );
}
}
public void addEncounterAction( final String encounterKey, final int roundIndex, final String indent,
final String combatAction, boolean isMacro )
{
CustomCombatStrategy strategy = (CustomCombatStrategy) childLookup.get( encounterKey );
if ( roundIndex < 0 )
{
strategy.addCombatAction( strategy.getChildCount() + 1, indent, combatAction, isMacro );
}
else
{
strategy.addCombatAction( roundIndex, indent, combatAction, isMacro );
}
}
@Override
public void removeAllChildren()
{
childKeys.clear();
childLookup.clear();
super.removeAllChildren();
}
@Override
public String toString()
{
return "";
}
public void load( BufferedReader reader )
throws IOException
{
StringBuffer indent = new StringBuffer();
String line = null;
int lineNumber = 0;
String encounterKey = "default";
while ( ( line = reader.readLine() ) != null )
{
// Count line for use in error messages
++lineNumber;
// Skip over any lines with no content.
line = line.trim();
if ( line.length() == 0 )
{
continue;
}
// If we've reached a new encounter key, close out the previous action.
if ( line.startsWith( "[" ) )
{
CustomCombatStrategy strategy = getStrategy( encounterKey );
if ( strategy.getChildCount() == 0 )
{
strategy.addCombatAction( 1, "attack", indent.toString(), false );
}
indent.setLength( 0 );
// Skip malformed lines
int close = line.indexOf( "]" );
if ( close == -1 )
{
KoLmafia.updateDisplay( "Malformed encounter key in CCS at line " + lineNumber );
encounterKey = "ignore";
}
else
{
encounterKey = CombatActionManager.encounterKey( line.substring( 1, close ).trim() );
}
addEncounterKey( encounterKey );
continue;
}
// Check to see if it's a macro action, and create a different kind of node if it is.
if ( CombatActionManager.isMacroAction( line ) )
{
// Strip out leading and trailing quotes.
if ( line.charAt( 0 ) == '"' )
{
line = line.substring( 1 ).trim();
if ( line.length() == 0 )
{
continue;
}
if ( line.charAt( line.length() - 1 ) == '"' )
{
line = line.substring( 0, line.length() - 1 );
}
}
// Update indentation.
if ( line.startsWith( "end" ) && indent.length() > 0 )
{
indent.delete( 0, 4 );
}
addEncounterAction( encounterKey, -1, indent.toString(), line, true );
// Update indentation again.
if ( line.startsWith( "if" ) || line.startsWith( "while" ) || line.startsWith( "sub" ) )
{
indent.append( "\u0020\u0020\u0020\u0020" );
}
continue;
}
// If we're currently building a macro, just append the current data to that macro.
int roundIndex = -1;
// If it looks like this is a KoLmafia-created settings file,
// then strip out the round index information.
if ( Character.isDigit( line.charAt( 0 ) ) )
{
int colonIndex = line.indexOf( ":" );
if ( colonIndex != -1 )
{
roundIndex = StringUtilities.parseInt( line.substring( 0, colonIndex ) );
line = line.substring( colonIndex + 1 ).trim();
}
}
addEncounterAction( encounterKey, roundIndex, indent.toString(), line, false );
}
// Make sure that the action is properly closed out.
CustomCombatStrategy strategy = getStrategy( encounterKey );
if ( strategy.getChildCount() == 0 )
{
strategy.addCombatAction( 1, "attack", indent.toString(), false );
}
}
public void store( PrintStream writer )
{
Iterator strategyIterator = childLookup.values().iterator();
while ( strategyIterator.hasNext() )
{
CustomCombatStrategy strategy = (CustomCombatStrategy) strategyIterator.next();
strategy.store( writer );
}
}
}