/**
* 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.persistence;
import java.io.BufferedReader;
import java.io.File;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sourceforge.kolmafia.AdventureResult;
import net.sourceforge.kolmafia.KoLAdventure;
import net.sourceforge.kolmafia.KoLConstants;
import net.sourceforge.kolmafia.KoLConstants.Stat;
import net.sourceforge.kolmafia.KoLConstants.WeaponType;
import net.sourceforge.kolmafia.Modifiers;
import net.sourceforge.kolmafia.RequestLogger;
import net.sourceforge.kolmafia.SpecialOutfit;
import net.sourceforge.kolmafia.StaticEntity;
import net.sourceforge.kolmafia.objectpool.AdventurePool;
import net.sourceforge.kolmafia.objectpool.EffectPool;
import net.sourceforge.kolmafia.objectpool.IntegerPool;
import net.sourceforge.kolmafia.objectpool.ItemPool;
import net.sourceforge.kolmafia.objectpool.OutfitPool;
import net.sourceforge.kolmafia.session.EquipmentManager;
import net.sourceforge.kolmafia.utilities.FileUtilities;
import net.sourceforge.kolmafia.utilities.IntegerArray;
import net.sourceforge.kolmafia.utilities.LogStream;
import net.sourceforge.kolmafia.utilities.StringArray;
import net.sourceforge.kolmafia.utilities.StringUtilities;
public class EquipmentDatabase
{
private static final IntegerArray power = new IntegerArray();
private static final IntegerArray hands = new IntegerArray();
private static final StringArray itemTypes = new StringArray();
private static final StringArray statRequirements = new StringArray();
private static final HashMap<Integer, Integer> outfitPieces = new HashMap<Integer, Integer>();
public static final SpecialOutfitArray normalOutfits = new SpecialOutfitArray();
private static final Map<Integer, String> outfitById = new TreeMap<Integer, String>();
public static final SpecialOutfitArray weirdOutfits = new SpecialOutfitArray();
private static final IntegerArray pulverize = new IntegerArray();
// Values in pulverize are one of:
// 0 - not initialized yet
// positive - ID of special-case pulverize result (worthless powder, epic wad, etc.)
// -1 - not pulverizable (quest item, Mr. Store item, etc.)
// other negative - bitmap, some combination of PULVERIZE_BITS, YIELD_x, ELEM_x
public static final int PULVERIZE_BITS = 0x80000000; // makes value negative
public static final int YIELD_UNCERTAIN = 0x001;
public static final int YIELD_1P = 0x002;
public static final int YIELD_2P = 0x004;
public static final int YIELD_3P = 0x008;
public static final int YIELD_4P_1N = 0x010;
public static final int YIELD_1N3P_2N = 0x020;
public static final int YIELD_3N = 0x040;
public static final int YIELD_4N_1W = 0x080;
public static final int YIELD_1W3N_2W = 0x100;
public static final int YIELD_3W = 0x200;
public static final int YIELD_1C = 0x400;
public static final int MASK_YIELD = 0x7FF;
public static final int ELEM_TWINKLY = 0x01000;
public static final int ELEM_HOT = 0x02000;
public static final int ELEM_COLD = 0x04000;
public static final int ELEM_STENCH = 0x08000;
public static final int ELEM_SPOOKY = 0x10000;
public static final int ELEM_SLEAZE = 0x20000;
public static final int ELEM_OTHER = 0x40000;
public static final int MASK_ELEMENT = 0x7F000;
public static final int MALUS_UPGRADE = 0x100000;
public static final int[] IMPLICATIONS = {
Modifiers.COLD_RESISTANCE, ELEM_HOT | ELEM_SPOOKY,
Modifiers.HOT_RESISTANCE, ELEM_STENCH | ELEM_SLEAZE,
Modifiers.SLEAZE_RESISTANCE, ELEM_COLD | ELEM_SPOOKY,
Modifiers.SPOOKY_RESISTANCE, ELEM_HOT | ELEM_STENCH,
Modifiers.STENCH_RESISTANCE, ELEM_COLD | ELEM_SLEAZE,
Modifiers.COLD_DAMAGE, ELEM_COLD,
Modifiers.HOT_DAMAGE, ELEM_HOT,
Modifiers.SLEAZE_DAMAGE, ELEM_SLEAZE,
Modifiers.SPOOKY_DAMAGE, ELEM_SPOOKY,
Modifiers.STENCH_DAMAGE, ELEM_STENCH,
Modifiers.COLD_SPELL_DAMAGE, ELEM_COLD,
Modifiers.HOT_SPELL_DAMAGE, ELEM_HOT,
Modifiers.SLEAZE_SPELL_DAMAGE, ELEM_SLEAZE,
Modifiers.SPOOKY_SPELL_DAMAGE, ELEM_SPOOKY,
Modifiers.STENCH_SPELL_DAMAGE, ELEM_STENCH,
};
public static boolean newEquipment = false;
static
{
EquipmentDatabase.reset();
}
public static void reset()
{
EquipmentDatabase.newEquipment = false;
BufferedReader reader = FileUtilities.getVersionedReader( "equipment.txt", KoLConstants.EQUIPMENT_VERSION );
String[] data;
int itemId;
while ( ( data = FileUtilities.readData( reader ) ) != null )
{
if ( data.length < 3 )
{
continue;
}
itemId = ItemDatabase.getItemId( data[ 0 ] );
if ( itemId < 0 )
{
continue;
}
EquipmentDatabase.power.set( itemId, StringUtilities.parseInt( data[ 1 ] ) );
String reqs = new String( data[ 2 ] );
EquipmentDatabase.statRequirements.set( itemId, reqs );
int hval = 0;
String tval = null;
if ( data.length >= 4 )
{
String str = data[ 3 ];
int index1 = str.indexOf( "-handed" );
if ( index1 > 0 )
{
hval = StringUtilities.parseInt( str.substring( 0, index1 ) );
tval = new String( str.substring( index1 + 7 ).trim() );
}
else
{
tval = new String( str );
}
}
EquipmentDatabase.hands.set( itemId, hval );
EquipmentDatabase.itemTypes.set( itemId, tval );
}
try
{
reader.close();
}
catch ( Exception e )
{
// This should not happen. Therefore, print
// a stack trace for debug purposes.
StaticEntity.printStackTrace( e );
}
reader = FileUtilities.getVersionedReader( "outfits.txt", KoLConstants.OUTFITS_VERSION );
int outfitId, arrayIndex;
SpecialOutfitArray outfitList;
while ( ( data = FileUtilities.readData( reader ) ) != null )
{
if ( data.length == 4 )
{
outfitId = StringUtilities.parseInt( data[ 0 ] );
if ( outfitId == 0 )
{
arrayIndex = EquipmentDatabase.weirdOutfits.size();
outfitList = EquipmentDatabase.weirdOutfits;
}
else
{
arrayIndex = outfitId;
outfitList = EquipmentDatabase.normalOutfits;
}
String name = new String( data[ 1 ] );
SpecialOutfit outfit = new SpecialOutfit( outfitId, name );
outfitList.set( arrayIndex, outfit );
String image = new String( data[ 2 ] );
outfit.setImage( image );
String[] pieces = data[ 3 ].split( "\\s*,\\s*" );
Integer id = IntegerPool.get( outfitId );
EquipmentDatabase.outfitById.put( id, name );
for ( int i = 0; i < pieces.length; ++i )
{
int pieceId = ItemDatabase.getItemId( pieces[ i ] );
if ( pieceId != -1 )
{
EquipmentDatabase.outfitPieces.put( IntegerPool.get( pieceId ), id );
outfit.addPiece( ItemPool.get( pieceId ) );
}
}
}
}
try
{
reader.close();
}
catch ( Exception e )
{
// This should not happen. Therefore, print
// a stack trace for debug purposes.
StaticEntity.printStackTrace( e );
}
reader = FileUtilities.getVersionedReader( "pulverize.txt", KoLConstants.PULVERIZE_VERSION );
while ( ( data = FileUtilities.readData( reader ) ) != null )
{
if ( data.length < 2 )
{
continue;
}
itemId = ItemDatabase.getItemId( data[ 0 ] );
if ( itemId < 0 )
{
continue;
}
String spec = data[ 1 ];
int result =
spec.equals( "nosmash" ) ? -1 :
spec.equals( "upgrade" ) ? EquipmentDatabase.deriveUpgrade( data[ 0 ] ) :
StringUtilities.isNumeric( spec ) ? ( PULVERIZE_BITS | StringUtilities.parseInt( spec ) ) :
spec.endsWith( "cluster" ) ? EquipmentDatabase.deriveCluster( spec ) :
ItemDatabase.getItemId( spec );
EquipmentDatabase.pulverize.set( itemId, result );
}
try
{
reader.close();
}
catch ( Exception e )
{
// This should not happen. Therefore, print
// a stack trace for debug purposes.
StaticEntity.printStackTrace( e );
}
}
public static boolean isEquipment( final int type )
{
switch ( type )
{
case KoLConstants.EQUIP_ACCESSORY:
case KoLConstants.EQUIP_CONTAINER:
case KoLConstants.EQUIP_HAT:
case KoLConstants.EQUIP_SHIRT:
case KoLConstants.EQUIP_PANTS:
case KoLConstants.EQUIP_WEAPON:
case KoLConstants.EQUIP_OFFHAND:
return true;
}
return false;
}
public static void writeEquipment( final File output )
{
RequestLogger.printLine( "Writing data override: " + output );
// One map per equipment category
Map<String, Integer> hats = new TreeMap<String, Integer>();
Map<String, Integer> weapons = new TreeMap<String, Integer>();
Map<String, Integer> offhands = new TreeMap<String, Integer>();
Map<String, Integer> shirts = new TreeMap<String, Integer>();
Map<String, Integer> pants = new TreeMap<String, Integer>();
Map<String, Integer> accessories = new TreeMap<String, Integer>();
Map<String, Integer> containers = new TreeMap<String, Integer>();
// Iterate over all items and assign item id to category
Iterator it = ItemDatabase.dataNameEntrySet().iterator();
while ( it.hasNext() )
{
Entry entry = (Entry) it.next();
Integer key = (Integer) entry.getKey();
String name = (String) entry.getValue();
int type = ItemDatabase.getConsumptionType( key.intValue() );
switch ( type )
{
case KoLConstants.EQUIP_HAT:
hats.put( name, key );
break;
case KoLConstants.EQUIP_PANTS:
pants.put( name, key );
break;
case KoLConstants.EQUIP_SHIRT:
shirts.put( name, key );
break;
case KoLConstants.EQUIP_WEAPON:
weapons.put( name, key );
break;
case KoLConstants.EQUIP_OFFHAND:
offhands.put( name, key );
break;
case KoLConstants.EQUIP_ACCESSORY:
accessories.put( name, key );
break;
case KoLConstants.EQUIP_CONTAINER:
containers.put( name, key );
break;
default:
continue;
}
}
// Open the output file
PrintStream writer = LogStream.openStream( output, true );
writer.println( KoLConstants.EQUIPMENT_VERSION );
// For each equipment category, write the map entries
EquipmentDatabase.writeEquipmentCategory( writer, hats, "Hats" );
writer.println();
EquipmentDatabase.writeEquipmentCategory( writer, pants, "Pants" );
writer.println();
EquipmentDatabase.writeEquipmentCategory( writer, shirts, "Shirts" );
writer.println();
EquipmentDatabase.writeEquipmentCategory( writer, weapons, "Weapons" );
writer.println();
EquipmentDatabase.writeEquipmentCategory( writer, offhands, "Off-hand" );
writer.println();
EquipmentDatabase.writeEquipmentCategory( writer, accessories, "Accessories" );
writer.println();
EquipmentDatabase.writeEquipmentCategory( writer, containers, "Containers" );
writer.close();
}
private static void writeEquipmentCategory( final PrintStream writer, final Map map, final String tag )
{
writer.println( "# " + tag + " section of equipment.txt" );
writer.println();
Object[] keys = map.keySet().toArray();
for ( int i = 0; i < keys.length; ++i )
{
String name = (String) keys[ i ];
Integer val = (Integer) map.get( name );
int itemId = val.intValue();
int power = EquipmentDatabase.getPower( itemId );
String req = EquipmentDatabase.getEquipRequirement( itemId );
int usage = ItemDatabase.getConsumptionType( itemId );
boolean isWeapon = usage == KoLConstants.EQUIP_WEAPON;
String type = EquipmentDatabase.itemTypes.get( itemId );
boolean isShield = type != null && type.equals( "shield" );
String weaponType = "";
if ( isWeapon )
{
int hands = EquipmentDatabase.hands.get( itemId );
weaponType = String.valueOf( hands ) + "-handed " + type;
}
EquipmentDatabase.writeEquipmentItem( writer, name, power, req, weaponType, isWeapon, isShield );
}
}
public static void writeEquipmentItem( final PrintStream writer, final String name, final int power,
final String req, final String weaponType,
final boolean isWeapon, final boolean isShield )
{
if ( isShield && power == 0 )
{
writer.println( "# *** " + name + " is a shield of unknown power." );
}
writer.println( EquipmentDatabase.equipmentString( name, power, req, weaponType, isWeapon, isShield ) );
}
public static String equipmentString( final String name, final int power,
final String req, final String weaponType,
final boolean isWeapon, final boolean isShield )
{
if ( isWeapon )
{
return name + "\t" + power + "\t" + req + "\t" + weaponType;
}
else if ( isShield )
{
return name + "\t" + power + "\t" + req + "\tshield";
}
else
{
return name + "\t" + power + "\t" + req;
}
}
private static final Pattern WEAPON_TYPE_PATTERN = Pattern.compile( "\\(((\\d)-handed (.*?))\\)" );
public static final void registerItem( final int itemId, final String itemName, final String text )
{
int power = DebugDatabase.parsePower( text );
EquipmentDatabase.registerItem( itemId, itemName, text, power );
}
public static final void registerItem( final int itemId, final String itemName, final String text, final int power )
{
// A new item has been detected. Examine the item description
// and decide what it is.
String type = DebugDatabase.parseType( text );
String req = DebugDatabase.parseReq( text, type );
EquipmentDatabase.power.set( itemId, power );
EquipmentDatabase.statRequirements.set( itemId, req );
boolean isWeapon = false, isShield = false;
String weaponType = "";
if ( type.indexOf( "weapon" ) != -1 )
{
Matcher matcher = WEAPON_TYPE_PATTERN.matcher( type );
int hval;
String tval;
if ( matcher.find() )
{
weaponType = matcher.group(1);
hval = StringUtilities.parseInt( matcher.group(2) );
tval = matcher.group(3);
}
else
{
weaponType = type;
hval = 0;
tval = type;
}
EquipmentDatabase.hands.set( itemId, hval );
EquipmentDatabase.itemTypes.set( itemId, tval );
isWeapon = true;
}
else if ( type.indexOf( "shield" ) != -1 )
{
isShield = true;
weaponType = "shield";
EquipmentDatabase.itemTypes.set( itemId, weaponType );
}
String printMe = EquipmentDatabase.equipmentString( itemName, power, req, weaponType, isWeapon, isShield );
RequestLogger.printLine( printMe );
RequestLogger.updateSessionLog( printMe );
}
// <tr><td valign=top>Outfit: </td><td valign=top><b><span style='cursor: hand; cursor:pointer;' onClick='javascript:window.open("desc_outfit.php?whichoutfit=112","","height=200,width=300")'>Topiaria</span></b><br>(3 items)</td></tr>
private static final Pattern OUTFIT_PATTERN = Pattern.compile( "Outfit:.*?<span.*?whichoutfit=(\\d+).*?>(.*?)</span>" );
public static final void registerItemOutfit( final int itemId, final String text )
{
Matcher matcher = OUTFIT_PATTERN.matcher( text );
if ( !matcher.find() )
{
return;
}
int outfitId = StringUtilities.parseInt( matcher.group( 1 ) );
String outfitName = matcher.group( 2 );
// If this is either a new outfit or this piece is not known to
// be on an outfit, register it.
if ( EquipmentDatabase.normalOutfits.get( outfitId ) == null ||
EquipmentDatabase.outfitPieces.get( IntegerPool.get( itemId ) ) == null )
{
EquipmentDatabase.registerOutfit( outfitId, new String( outfitName ), itemId );
}
}
public static final void registerOutfit( final int outfitId, final String outfitName, final int itemId )
{
SpecialOutfit outfit = EquipmentDatabase.normalOutfits.get( outfitId );
Integer id = IntegerPool.get( outfitId );
if ( outfit == null )
{
outfit = new SpecialOutfit( outfitId, outfitName );
EquipmentDatabase.normalOutfits.set( outfitId, outfit );
EquipmentDatabase.outfitById.put( id, outfitName );
}
if ( itemId != -1 )
{
EquipmentDatabase.outfitPieces.put( IntegerPool.get( itemId ), id );
outfit.addPiece( ItemPool.get( itemId ) );
}
String rawText = DebugDatabase.rawOutfitDescriptionText( outfitId );
String outfitImage = rawText != null ? DebugDatabase.parseImage( rawText ) : "";
outfit.setImage( outfitImage );
String printMe;
printMe = "--------------------";
RequestLogger.printLine( printMe );
RequestLogger.updateSessionLog( printMe );
printMe = EquipmentDatabase.outfitString( outfitId, outfitName, outfitImage );
RequestLogger.printLine( printMe );
RequestLogger.updateSessionLog( printMe );
// Let modifiers database do what it wishes with this outfit
Modifiers.registerOutfit( outfitName, rawText );
// Done generating data
printMe = "--------------------";
RequestLogger.printLine( printMe );
RequestLogger.updateSessionLog( printMe );
}
public static final int nextEquipmentItemId( int prevId )
{
int limit = ItemDatabase.maxItemId();
while ( ++prevId <= limit )
{
String req = EquipmentDatabase.statRequirements.get( prevId );
if ( (req != null && req.length() > 0) ||
ItemDatabase.getConsumptionType( prevId ) == KoLConstants.EQUIP_FAMILIAR ||
ItemDatabase.getConsumptionType( prevId ) == KoLConstants.CONSUME_SIXGUN )
{
return prevId;
}
}
return -1;
}
public static final int getOutfitWithItem( final int itemId )
{
if ( itemId < 0 )
{
return -1;
}
Integer result = EquipmentDatabase.outfitPieces.get( IntegerPool.get( itemId ) );
return result == null ? -1 : result.intValue();
}
public static final int getOutfitCount()
{
return EquipmentDatabase.normalOutfits.size();
}
public static final String outfitString( final int outfitId, final String name, final String outfitImage )
{
StringBuilder buffer = new StringBuilder();
buffer.append( String.valueOf( outfitId ) );
buffer.append( "\t" );
buffer.append( name );
buffer.append( "\t" );
buffer.append( outfitImage );
SpecialOutfit outfit = EquipmentDatabase.getOutfit( outfitId );
if ( outfit != null )
{
AdventureResult[] pieces = outfit.getPieces();
boolean first = true;
for ( AdventureResult piece : pieces )
{
buffer.append( first ? "\t" : ", " );
first = false;
buffer.append( piece.getName() );
}
}
return buffer.toString();
}
public static final boolean contains( final int itemId )
{
return itemId > 0 && EquipmentDatabase.statRequirements.get( itemId ) != null;
}
public static final int getPower( final int itemId )
{
return EquipmentDatabase.power.get( itemId );
}
public static final void setPower( final int itemId, final int power )
{
EquipmentDatabase.power.set( itemId, power );
}
public static final int getHands( final int itemId )
{
return EquipmentDatabase.hands.get( itemId );
}
public static final String getEquipRequirement( final int itemId )
{
String req = EquipmentDatabase.statRequirements.get( itemId );
if ( req != null )
{
return req;
}
return "none";
}
public static final String getItemType( final int itemId )
{
switch ( ItemDatabase.getConsumptionType( itemId ) )
{
case KoLConstants.CONSUME_EAT:
return "food";
case KoLConstants.CONSUME_DRINK:
return "booze";
case KoLConstants.CONSUME_SPLEEN:
return "spleen item";
case KoLConstants.CONSUME_FOOD_HELPER:
return "food helper";
case KoLConstants.CONSUME_DRINK_HELPER:
return "drink helper";
case KoLConstants.CONSUME_STICKER:
return "sticker";
case KoLConstants.CONSUME_CARD:
return "card";
case KoLConstants.CONSUME_FOLDER:
return "folder";
case KoLConstants.CONSUME_BOOTSKIN:
return "bootskin";
case KoLConstants.CONSUME_BOOTSPUR:
return "bootspur";
case KoLConstants.CONSUME_SIXGUN:
return "sixgun";
case KoLConstants.CONSUME_AVATAR:
return "avatar potion";
case KoLConstants.GROW_FAMILIAR:
return "familiar larva";
case KoLConstants.CONSUME_ZAP:
return "zap wand";
case KoLConstants.EQUIP_FAMILIAR:
return "familiar equipment";
case KoLConstants.EQUIP_ACCESSORY:
return "accessory";
case KoLConstants.EQUIP_HAT:
return "hat";
case KoLConstants.EQUIP_PANTS:
return "pants";
case KoLConstants.EQUIP_SHIRT:
return "shirt";
case KoLConstants.EQUIP_WEAPON:
{
String type = EquipmentDatabase.itemTypes.get( itemId );
return type != null ? type : "weapon";
}
case KoLConstants.EQUIP_OFFHAND:
{
String type = EquipmentDatabase.itemTypes.get( itemId );
return type != null ? type : "offhand";
}
case KoLConstants.EQUIP_CONTAINER:
return "container";
case KoLConstants.CONSUME_GUARDIAN:
return "pasta guardian";
default:
return "";
}
}
public static final boolean isAccordion( final int itemId )
{
return ( EquipmentDatabase.getItemType( itemId ).contains( "accordion" ) );
}
public static final boolean isSpecialAccordion( final int itemId )
{
return ( EquipmentDatabase.isAccordion( itemId ) &&
itemId != ItemPool.TOY_ACCORDION && itemId != ItemPool.ANTIQUE_ACCORDION && itemId != ItemPool.AEROGEL_ACCORDION );
}
public static final Stat getWeaponStat( final int itemId )
{
int consumptionType = ItemDatabase.getConsumptionType( itemId );
if ( consumptionType != KoLConstants.EQUIP_WEAPON )
{
return Stat.NONE;
}
String req = EquipmentDatabase.getEquipRequirement( itemId );
if ( req.startsWith( "Mox:" ) )
{
return Stat.MOXIE;
}
if ( req.startsWith( "Mys:" ) )
{
return Stat.MYSTICALITY;
}
return Stat.MUSCLE;
}
public static final WeaponType getWeaponType( final int itemId )
{
switch ( EquipmentDatabase.getWeaponStat( itemId ) )
{
case NONE:
return WeaponType.NONE;
case MOXIE:
return WeaponType.RANGED;
default:
return WeaponType.MELEE;
}
}
public static final boolean isChefStaff( final AdventureResult item )
{
return EquipmentDatabase.isChefStaff( item.getItemId() );
}
public static final boolean isChefStaff( final int itemId )
{
return EquipmentDatabase.getItemType( itemId ).equals( "chefstaff" );
}
public static final boolean isCanOfBeans( final AdventureResult item )
{
return EquipmentDatabase.isCanOfBeans( item.getItemId() );
}
public static final boolean isCanOfBeans( final int itemId )
{
return EquipmentDatabase.getItemType( itemId ).equals( "can of beans" );
}
public static final AdventureResult IRON_PALMS = EffectPool.get( EffectPool.IRON_PALMS );
public static final boolean isClub( final int itemId )
{
String type = EquipmentDatabase.getItemType( itemId );
return type.equals( "club" ) || ( KoLConstants.activeEffects.contains( EquipmentManager.IRON_PALMS ) && type.equals( "sword" ) );
}
public static final boolean isKnife( final int itemId )
{
return EquipmentDatabase.getItemType( itemId ).equals( "knife" );
}
public static final boolean isUtensil( final int itemId )
{
return EquipmentDatabase.getItemType( itemId ).equals( "utensil" );
}
public static final boolean isShield( final int itemId )
{
return EquipmentDatabase.getItemType( itemId ).equals( "shield" );
}
public static final boolean isHat( final AdventureResult item)
{
return EquipmentDatabase.getItemType( item.getItemId() ).equals( "hat" );
}
public static final boolean isShirt( final AdventureResult item )
{
return ItemDatabase.getConsumptionType( item.getItemId() ) == KoLConstants.EQUIP_SHIRT;
}
public static final boolean isContainer( final AdventureResult item )
{
return ItemDatabase.getConsumptionType( item.getItemId() ) == KoLConstants.EQUIP_CONTAINER;
}
public static final boolean isMainhandOnly( final AdventureResult item )
{
return EquipmentDatabase.isMainhandOnly( item.getItemId() );
}
public static final boolean isMainhandOnly( final int itemId )
{
return EquipmentDatabase.isChefStaff( itemId ) || EquipmentDatabase.isSpecialAccordion( itemId ) || EquipmentDatabase.getHands( itemId ) != 1;
}
public static final int getPulverization( final int id )
{
if ( id < 0 )
{
return -1;
}
int pulver = EquipmentDatabase.pulverize.get( id );
if ( pulver == 0 )
{
pulver = EquipmentDatabase.derivePulverization( id );
EquipmentDatabase.pulverize.set( id, pulver );
}
return pulver;
}
private static final int derivePulverization( final int id )
{
switch ( ItemDatabase.getConsumptionType( id ) )
{
case KoLConstants.EQUIP_ACCESSORY:
case KoLConstants.EQUIP_HAT:
case KoLConstants.EQUIP_PANTS:
case KoLConstants.EQUIP_SHIRT:
case KoLConstants.EQUIP_WEAPON:
case KoLConstants.EQUIP_OFFHAND:
case KoLConstants.EQUIP_CONTAINER:
break;
default:
return -1;
}
if ( ItemDatabase.isQuestItem( id ) )
{ // quest item
return -1;
}
if ( ItemDatabase.isGiftable( id ) && !ItemDatabase.isTradeable( id ) )
{ // gift item
return ItemPool.USELESS_POWDER;
}
if ( NPCStoreDatabase.contains( id, false ) )
{
return ItemPool.USELESS_POWDER;
}
int pulver = PULVERIZE_BITS | ELEM_TWINKLY;
Modifiers mods = Modifiers.getItemModifiers( id );
if ( mods == null )
{ // Apparently no enchantments at all, which would imply that this
// item pulverizes to useless powder. However, there are many items
// with enchantments that don't correspond to a KoLmafia modifier
// (the "They do nothing!" enchantment of beer goggles, for example),
// so this can't safely be assumed, so for now all truly unenchanted
// items will have to be explicitly listed in pulverize.txt.
pulver |= EquipmentDatabase.ELEM_TWINKLY;
}
else
{
for ( int i = 0; i < IMPLICATIONS.length; i += 2 )
{
if ( mods.get( IMPLICATIONS[ i ] ) > 0.0f )
{
pulver |= IMPLICATIONS[ i+1 ];
}
}
}
int power = EquipmentDatabase.power.get( id );
if ( power <= 0 )
{
// power is unknown, derive from requirement (which isn't always accurate)
pulver |= YIELD_UNCERTAIN;
String req = EquipmentDatabase.statRequirements.get( id );
if ( req == null || req.equals( "none" ) )
{
power = 0;
}
else
{
int colonIndex = req.indexOf( ":" );
if ( colonIndex != -1 )
{
String reqValue = req.substring( colonIndex + 1 ).trim();
power = StringUtilities.parseInt( reqValue ) * 2 + 30;
}
}
}
if ( power >= 180 )
{
pulver |= YIELD_3W;
}
else if ( power >= 160 )
{
pulver |= YIELD_1W3N_2W;
}
else if ( power >= 140 )
{
pulver |= YIELD_4N_1W;
}
else if ( power >= 120 )
{
pulver |= YIELD_3N;
}
else if ( power >= 100 )
{
pulver |= YIELD_1N3P_2N;
}
else if ( power >= 80 )
{
pulver |= YIELD_4P_1N;
}
else if ( power >= 60 )
{
pulver |= YIELD_3P;
}
else if ( power >= 40 )
{
pulver |= YIELD_2P;
}
else
{
pulver |= YIELD_1P;
}
return pulver;
}
private static final int deriveUpgrade( final String name )
{
int pulver = PULVERIZE_BITS | MALUS_UPGRADE | YIELD_4N_1W;
if ( name.endsWith( "powder" ) )
{
pulver |= YIELD_4P_1N;
}
if ( name.startsWith( "twinkly" ) )
{
pulver |= ELEM_TWINKLY;
}
else if ( name.startsWith( "hot" ) )
{
pulver |= ELEM_HOT;
}
else if ( name.startsWith( "cold" ) )
{
pulver |= ELEM_COLD;
}
else if ( name.startsWith( "stench" ) )
{
pulver |= ELEM_STENCH;
}
else if ( name.startsWith( "spook" ) )
{
pulver |= ELEM_SPOOKY;
}
else if ( name.startsWith( "sleaz" ) )
{
pulver |= ELEM_SLEAZE;
}
else
{
pulver |= ELEM_OTHER;
}
return pulver;
}
private static final int deriveCluster( final String name )
{
int pulver = PULVERIZE_BITS | YIELD_1C;
if ( name.startsWith( "hot" ) )
{
pulver |= ELEM_HOT;
}
else if ( name.startsWith( "cold" ) )
{
pulver |= ELEM_COLD;
}
else if ( name.startsWith( "stench" ) )
{
pulver |= ELEM_STENCH;
}
else if ( name.startsWith( "spook" ) )
{
pulver |= ELEM_SPOOKY;
}
else if ( name.startsWith( "sleaz" ) )
{
pulver |= ELEM_SLEAZE;
}
else
{
pulver = ItemDatabase.getItemId( name );
}
return pulver;
}
public static final Set outfitEntrySet()
{
return EquipmentDatabase.outfitById.entrySet();
}
public static final SpecialOutfit getOutfit( final int id )
{
return EquipmentDatabase.normalOutfits.get( id );
}
public static final SpecialOutfit getAvailableOutfit( final int id )
{
SpecialOutfit outfit = EquipmentDatabase.normalOutfits.get( id );
return EquipmentManager.getOutfits().contains( outfit ) ? outfit : null;
}
public static final int getOutfitId( final KoLAdventure adventure )
{
int adventureId = Integer.parseInt( adventure.getAdventureId() );
switch ( adventureId )
{
case AdventurePool.COBB_BARRACKS:
return OutfitPool.KNOB_ELITE_OUTFIT;
case AdventurePool.COBB_HAREM:
return OutfitPool.HAREM_OUTFIT;
case AdventurePool.ITZNOTYERZITZ_MINE:
return OutfitPool.MINING_OUTFIT;
case AdventurePool.EXTREME_SLOPE:
return OutfitPool.EXTREME_COLD_WEATHER_GEAR;
case AdventurePool.HIPPY_CAMP:
case AdventurePool.HIPPY_CAMP_DISGUISED:
return OutfitPool.HIPPY_OUTFIT;
case AdventurePool.FRAT_HOUSE:
case AdventurePool.FRAT_HOUSE_DISGUISED:
return OutfitPool.FRAT_OUTFIT;
case AdventurePool.PIRATE_COVE:
return OutfitPool.SWASHBUCKLING_GETUP;
// Choose the uniform randomly
case AdventurePool.COLA_BATTLEFIELD:
return KoLConstants.RNG.nextInt( 2 ) == 0 ? OutfitPool.CLOACA_UNIFORM : OutfitPool.DYSPEPSI_UNIFORM;
case AdventurePool.CLOACA_BATTLEFIELD:
return OutfitPool.CLOACA_UNIFORM;
case AdventurePool.DYSPEPSI_BATTLEFIELD:
return OutfitPool.DYSPEPSI_UNIFORM;
// No outfit existed for this area
default:
return -1;
}
}
/**
* Internal class which functions exactly like an array of SpecialOutfits,
* except it uses "sets" and "gets" like a list. This could be done
* with generics (Java 1.5) but is done like this so that we get
* backwards compatibility.
*/
public static class SpecialOutfitArray
implements Iterable<SpecialOutfit>
{
private final ArrayList<SpecialOutfit> internalList = new ArrayList<SpecialOutfit>();
private final TreeSet<Integer> internalSet = new TreeSet<Integer>();
public Iterator<SpecialOutfit> iterator()
{
return this.internalList.iterator();
}
public SpecialOutfit get( final int index )
{
return index < 0 || index >= this.internalList.size() ? null : this.internalList.get( index );
}
public void set( final int index, final SpecialOutfit value )
{
for ( int i = this.internalList.size(); i <= index; ++i )
{
this.internalList.add( null );
}
this.internalList.set( index, value );
this.internalSet.add( new Integer( index ) );
}
public int size()
{
return this.internalList.size();
}
public List<SpecialOutfit> toList()
{
return this.internalList;
}
public Set<Integer> keySet()
{
return this.internalSet;
}
}
}