/**
* 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.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import net.sourceforge.kolmafia.AdventureResult;
import net.sourceforge.kolmafia.KoLCharacter;
import net.sourceforge.kolmafia.KoLConstants;
import net.sourceforge.kolmafia.PastaThrallData;
import net.sourceforge.kolmafia.RequestLogger;
import net.sourceforge.kolmafia.StaticEntity;
import net.sourceforge.kolmafia.objectpool.EffectPool;
import net.sourceforge.kolmafia.objectpool.IntegerPool;
import net.sourceforge.kolmafia.objectpool.ItemPool;
import net.sourceforge.kolmafia.objectpool.SkillPool;
import net.sourceforge.kolmafia.preferences.Preferences;
import net.sourceforge.kolmafia.request.UseSkillRequest;
import net.sourceforge.kolmafia.request.UseSkillRequest.BuffTool;
import net.sourceforge.kolmafia.session.EquipmentManager;
import net.sourceforge.kolmafia.utilities.FileUtilities;
import net.sourceforge.kolmafia.utilities.LockableListFactory;
import net.sourceforge.kolmafia.utilities.StringUtilities;
public class SkillDatabase
{
private static String [] canonicalNames = new String[0];
private static final Map<Integer, String> skillById = new TreeMap<Integer, String>();
private static final Map<Integer, String> imageById = new TreeMap<Integer, String>();
private static final Map<Integer, String> dataNameById = new TreeMap<Integer, String>();
private static final Map<String, Integer> skillByName = new TreeMap<String, Integer>();
private static final Map<Integer, Integer> mpConsumptionById = new HashMap<Integer, Integer>();
private static final Map<Integer, Integer> skillTypeById = new TreeMap<Integer, Integer>();
private static final Map<Integer, Integer> durationById = new HashMap<Integer, Integer>();
private static final Map<Integer, Integer> levelById = new HashMap<Integer, Integer>();
private static final Map<Integer, Integer> castsById = new HashMap<Integer, Integer>();
private static final Map<String, ArrayList<String>> skillsByCategory = new HashMap<String, ArrayList<String>>();
private static final Map<Integer, String> skillCategoryById = new HashMap<Integer, String>();
public static final int ALL = -2;
public static final int CASTABLE = -1;
public static final int PASSIVE = 0;
public static final int SUMMON = 1;
public static final int REMEDY = 2;
public static final int SELF_ONLY = 3;
public static final int BUFF = 4;
public static final int COMBAT = 5;
public static final int SONG = 6;
public static final int COMBAT_NONCOMBAT_REMEDY = 7;
public static final int COMBAT_PASSIVE = 8;
public static final int EXPRESSION = 9;
public static final int WALK = 10;
private static final String UNCATEGORIZED = "uncategorized";
private static final String CONDITIONAL = "conditional";
private static final String MR_SKILLS = "mr. skills";
private static final String GNOME_SKILLS = "gnome trainer";
private static final String BAD_MOON = "bad moon";
private static final String AVATAR_OF_BORIS = "avatar of Boris";
private static final String ZOMBIE_MASTER = "zombie master";
private static final String AVATAR_OF_JARLSBERG = "Avatar of Jarlsberg";
private static final String AVATAR_OF_SNEAKY_PETE = "Avatar of Sneaky Pete";
private static final String HEAVY_RAINS = "Heavy Rains";
private static final String ED = "Ed";
private static final String COWPUNCHER = "Cow Puncher";
private static final String BEANSLINGER = "Beanslinger";
private static final String SNAKE_OILER = "Snake Oiler";
private static final String SOURCE = "The Source";
private static final String NUCLEAR_AUTUMN = "Nuclear Autumn";
private static final String GELATINOUS_NOOB = "Gelatinous Noob";
private static final String[] CATEGORIES = new String[]
{
SkillDatabase.UNCATEGORIZED,
"seal clubber", // 1xxx
"turtle tamer", // 2xxx
"pastamancer", // 3xxx
"sauceror", // 4xxx
"disco bandit", // 5xxx
"accordion thief", // 6xxx
SkillDatabase.CONDITIONAL, // 7xxx
SkillDatabase.MR_SKILLS, // 8xxx
"9XXX", // 9xxx
"10XXX", // 10xxx
SkillDatabase.AVATAR_OF_BORIS, // 11xxx
SkillDatabase.ZOMBIE_MASTER, // 12xxx
"13XXX", // 13xxx
SkillDatabase.AVATAR_OF_JARLSBERG, // 14xxx
SkillDatabase.AVATAR_OF_SNEAKY_PETE, // 15xxx
SkillDatabase.HEAVY_RAINS, // 16xxx
SkillDatabase.ED, // 17xxx
SkillDatabase.COWPUNCHER, // 18xxx
SkillDatabase.BEANSLINGER, // 19xxx
SkillDatabase.SNAKE_OILER, // 20xxx
SkillDatabase.SOURCE, // 21xxx
SkillDatabase.NUCLEAR_AUTUMN, // 22xxx
SkillDatabase.GELATINOUS_NOOB, // 23xxx
// The following are convenience categories, not implied by skill id
SkillDatabase.GNOME_SKILLS,
SkillDatabase.BAD_MOON
};
static
{
// This begins by opening up the data file and preparing
// a buffered reader; once this is done, every line is
// examined and float-referenced: once in the name-lookup,
// and again in the Id lookup.
for ( int i = 0; i < SkillDatabase.CATEGORIES.length; ++i )
{
String category = SkillDatabase.CATEGORIES[ i ];
SkillDatabase.skillsByCategory.put( category, new ArrayList<String>() );
}
BufferedReader reader = FileUtilities.getVersionedReader( "classskills.txt", KoLConstants.CLASSSKILLS_VERSION );
String[] data;
while ( ( data = FileUtilities.readData( reader ) ) != null )
{
if ( data.length < 6 )
{
continue;
}
Integer id = Integer.valueOf( data[ 0 ] );
String name = data[ 1 ];
String image = data[ 2 ];
Integer type = Integer.valueOf( data[ 3 ] );
Integer mp = Integer.valueOf( data[ 4 ] );
Integer duration = Integer.valueOf( data[ 5 ] );
Integer level = ( data.length > 6 ) ? Integer.valueOf( data[ 6 ] ) : null;
SkillDatabase.addSkill( id, name, image, type, mp, duration, level );
}
try
{
reader.close();
}
catch ( Exception e )
{
// This should not happen. Therefore, print
// a stack trace for debug purposes.
StaticEntity.printStackTrace( e );
}
SkillDatabase.canonicalNames = new String[ SkillDatabase.skillByName.size() ];
SkillDatabase.skillByName.keySet().toArray( SkillDatabase.canonicalNames );
}
private static final void addSkill( final Integer skillId, final String name, final String image, final Integer skillType, final Integer mpConsumption, final Integer duration, final Integer level )
{
String canonicalName = StringUtilities.getCanonicalName( name );
String displayName = StringUtilities.getDisplayName( name );
SkillDatabase.skillById.put( skillId, displayName );
SkillDatabase.dataNameById.put( skillId, name );
SkillDatabase.skillByName.put( canonicalName, skillId );
if ( image != null )
{
SkillDatabase.imageById.put( skillId, image );
}
SkillDatabase.skillTypeById.put( skillId, skillType );
SkillDatabase.mpConsumptionById.put( skillId, mpConsumption );
SkillDatabase.durationById.put( skillId, duration );
if ( level != null )
{
SkillDatabase.levelById.put( skillId, level );
}
String category;
int categoryId = skillId.intValue() / 1000;
switch ( skillId.intValue() )
{
case SkillPool.SMILE_OF_MR_A:
case SkillPool.SNOWCONE:
case SkillPool.STICKER:
case SkillPool.SUGAR:
case SkillPool.CLIP_ART:
case SkillPool.RAD_LIB:
case SkillPool.SMITHSNESS:
case SkillPool.CANDY_HEART:
case SkillPool.PARTY_FAVOR:
case SkillPool.LOVE_SONG:
case SkillPool.BRICKOS:
case SkillPool.DICE:
case SkillPool.RESOLUTIONS:
case SkillPool.TAFFY:
case SkillPool.HILARIOUS:
case SkillPool.TASTEFUL:
case SkillPool.CARDS:
case SkillPool.GEEKY:
case SkillPool.CONFISCATOR:
category = SkillDatabase.MR_SKILLS;
break;
case SkillPool.OBSERVATIOGN:
case SkillPool.GNEFARIOUS_PICKPOCKETING:
case SkillPool.TORSO:
case SkillPool.GNOMISH_HARDINESS:
case SkillPool.COSMIC_UNDERSTANDING:
category = SkillDatabase.GNOME_SKILLS;
break;
case SkillPool.LUST: // Lust
case SkillPool.GLUTTONY: // Gluttony
case SkillPool.GREED: // Greed
case SkillPool.SLOTH: // Sloth
case SkillPool.WRATH: // Wrath
case SkillPool.ENVY: // Envy
case SkillPool.PRIDE: // Pride
category = SkillDatabase.BAD_MOON;
break;
default:
// Moxious maneuver has a 7000 id, but
// it's not gained by equipment.
category = SkillDatabase.CATEGORIES[ categoryId ];
}
SkillDatabase.skillCategoryById.put( skillId, category );
( SkillDatabase.skillsByCategory.get( category ) ).add( displayName );
SkillDatabase.castsById.put( skillId, IntegerPool.get(0) );
}
public static final List getSkillsByCategory( String category )
{
if ( category == null )
{
return new ArrayList();
}
List categoryMatches = StringUtilities.getMatchingNames( SkillDatabase.CATEGORIES, category );
if ( categoryMatches.size() != 1 )
{
return new ArrayList();
}
category = (String) categoryMatches.get( 0 );
List skills = (List) SkillDatabase.skillsByCategory.get( category );
if ( skills == null )
{
return new ArrayList();
}
return skills;
}
/**
* Returns a list of all skills which contain the given substring. This is useful for people who are doing lookups
* on skills.
*/
public static final List<String> getMatchingNames( final String substring )
{
return StringUtilities.getMatchingNames( SkillDatabase.canonicalNames, substring );
}
/**
* Returns the name for an skill, given its Id.
*
* @param skillId The Id of the skill to lookup
* @return The name of the corresponding skill
*/
public static final String getSkillName( final int skillId )
{
return (String) SkillDatabase.skillById.get( IntegerPool.get( skillId ) );
}
public static final String getSkillDataName( final int skillId )
{
return skillId == -1 ?
null:
(String) SkillDatabase.dataNameById.get( IntegerPool.get( skillId ) );
}
/**
* Returns the level for an skill, given its Id.
*
* @param skillId The Id of the skill to lookup
* @return The level of the corresponding skill
*/
public static final int getSkillLevel( final int skillId )
{
Object level = SkillDatabase.levelById.get( IntegerPool.get( skillId ) );
return level == null ? -1 : ( (Integer) level ).intValue();
}
public static final int getSkillPurchaseCost( final int skillId )
{
if ( ( skillId / 1000 == 11 ) || ( skillId / 1000 == 12 ) )
{
return 0;
}
switch ( SkillDatabase.getSkillLevel( skillId ) )
{
default:
return 0;
case 1:
return 125;
case 2:
return 250;
case 3:
return 500;
case 4:
return 750;
case 5:
return 1250;
case 6:
return 1750;
case 7:
return 2500;
case 8:
return 3250;
case 9:
return 4000;
case 10:
return 5000;
case 11:
return 6250;
case 12:
return 7500;
case 13:
return 10000;
case 14:
return 12500;
case 15:
return 15000;
}
}
public static final int classSkillsBase()
{
String name = KoLCharacter.getClassType();
if ( name == KoLCharacter.SEAL_CLUBBER )
{
return 1000;
}
if ( name == KoLCharacter.TURTLE_TAMER )
{
return 2000;
}
if ( name == KoLCharacter.PASTAMANCER )
{
return 3000;
}
if ( name == KoLCharacter.SAUCEROR )
{
return 4000;
}
if ( name == KoLCharacter.DISCO_BANDIT )
{
return 5000;
}
if ( name == KoLCharacter.ACCORDION_THIEF )
{
return 6000;
}
if ( name == KoLCharacter.AVATAR_OF_BORIS )
{
return 11000;
}
if ( name == KoLCharacter.ZOMBIE_SLAYER )
{
return 12000;
}
if ( name == KoLCharacter.AVATAR_OF_JARLSBERG )
{
return 14000;
}
if ( name == KoLCharacter.AVATAR_OF_SNEAKY_PETE )
{
return 15000;
}
if ( name == KoLCharacter.ED )
{
return 17000;
}
if ( name == KoLCharacter.COWPUNCHER )
{
return 18000;
}
if ( name == KoLCharacter.BEANSLINGER )
{
return 19000;
}
if ( name == KoLCharacter.SNAKE_OILER )
{
return 20000;
}
if ( name == KoLCharacter.GELATINOUS_NOOB )
{
return 23000;
}
return 0;
}
/**
* Returns the type for an skill, given its Id.
*
* @param skillId The Id of the skill to lookup
* @return The type of the corresponding skill
*/
public static final int getSkillType( final int skillId )
{
Object skillType = SkillDatabase.skillTypeById.get( IntegerPool.get( skillId ) );
return skillType == null ? -1 : ( (Integer) skillType ).intValue();
}
public static final String getSkillCategory( final int skillId )
{
Object cat = SkillDatabase.skillCategoryById.get( IntegerPool.get( skillId ) );
return cat == null ? "" : (String) cat;
}
/**
* Returns the image for an skill, given its Id.
*
* @param skillId The Id of the skill to lookup
* @return The type of the corresponding skill
*/
public static final String getSkillImage( final int skillId )
{
return (String) SkillDatabase.imageById.get( IntegerPool.get( skillId ) );
}
/**
* Returns the Id number for an skill, given its name.
*
* @param skillName The name of the skill to lookup
* @return The Id number of the corresponding skill
*/
public static final int getSkillId( final String skillName )
{
if ( skillName == null )
{
return -1;
}
Object skillId = SkillDatabase.skillByName.get( StringUtilities.getCanonicalName( skillName ) );
return skillId == null ? -1 : ( (Integer) skillId ).intValue();
}
/**
* Returns how much MP is consumed by using the skill with the given Id.
*
* @param skillId The id of the skill to lookup
* @return The MP consumed by the skill, or 0 if unknown
*/
private static final AdventureResult SUPER_SKILL = EffectPool.get( EffectPool.SUPER_SKILL );
public static final int getMPConsumptionById( final int skillId )
{
if ( isLibramSkill( skillId ) )
{
return libramSkillMPConsumption();
}
String classType = null;
boolean thrallReduced = false;
boolean isCombat = SkillDatabase.isCombat( skillId );
boolean terminal = false;
switch ( skillId )
{
case SkillPool.CLOBBER:
classType = KoLCharacter.SEAL_CLUBBER;
break;
case SkillPool.TOSS:
classType = KoLCharacter.TURTLE_TAMER;
break;
case SkillPool.SPAGHETTI_SPEAR:
classType = KoLCharacter.PASTAMANCER;
break;
case SkillPool.SALSABALL:
classType = KoLCharacter.SAUCEROR;
break;
case SkillPool.SUCKERPUNCH:
classType = KoLCharacter.DISCO_BANDIT;
break;
case SkillPool.SING:
classType = KoLCharacter.ACCORDION_THIEF;
break;
case SkillPool.MILD_CURSE:
classType = KoLCharacter.ED;
break;
case SkillPool.MAGIC_MISSILE:
return Math.max(
Math.min( ( KoLCharacter.getLevel() + 3 ) / 2, 6 ) + KoLCharacter.getManaCostAdjustment(), 1 );
case SkillPool.STRINGOZZI:
case SkillPool.RAVIOLI_SHURIKENS:
case SkillPool.CANNELLONI_CANNON:
case SkillPool.STUFFED_MORTAR_SHELL:
case SkillPool.WEAPON_PASTALORD:
if ( KoLCharacter.currentPastaThrall() != PastaThrallData.NO_THRALL && KoLCharacter.hasSkill( "Thrall Unit Tactics" ) )
{
thrallReduced = true;
}
break;
case SkillPool.EXTRACT:
case SkillPool.DIGITIZE:
case SkillPool.COMPRESS:
case SkillPool.DUPLICATE:
case SkillPool.PORTSCAN:
case SkillPool.TURBO:
terminal = true;
break;
case SkillPool.STACK_LUMPS:
return SkillDatabase.stackLumpsCost();
}
if ( classType != null )
{
return KoLCharacter.getClassType() == classType ? 0 :
Math.max( 1 + KoLCharacter.getManaCostAdjustment(), 1 );
}
if ( SkillDatabase.getSkillType( skillId ) == SkillDatabase.PASSIVE )
{
return 0;
}
if ( isCombat && KoLConstants.activeEffects.contains( SkillDatabase.SUPER_SKILL ) )
{
return 0;
}
Object mpConsumption = SkillDatabase.mpConsumptionById.get( IntegerPool.get( skillId ) );
if ( mpConsumption == null )
{
return 0;
}
int cost = ( (Integer) mpConsumption ).intValue();
if ( cost == 0 )
{
return 0;
}
if ( thrallReduced )
{
cost = cost / 2;
}
if ( terminal )
{
cost -= Preferences.getInteger( "sourceTerminalSpam" );
if ( Preferences.getString( "sourceTerminalChips" ).contains( "ASHRAM" ) )
{
cost -= 5;
}
}
int adjustment = KoLCharacter.getManaCostAdjustment( isCombat );
return Math.max( cost + adjustment, 1 );
}
/**
* Determines if a skill comes from a Libram
*
* @param skillId The Id of the skill to lookup
* @return true if it comes from a Libram
*/
public static final boolean isLibramSkill( final int skillId )
{
return
skillId == SkillPool.CANDY_HEART ||
skillId == SkillPool.PARTY_FAVOR ||
skillId == SkillPool.LOVE_SONG ||
skillId == SkillPool.BRICKOS ||
skillId == SkillPool.DICE ||
skillId == SkillPool.RESOLUTIONS ||
skillId == SkillPool.TAFFY;
}
/**
* Determines the cost for next casting of a libram skill
*
* @return the MP cost to cast it
*/
public static final int libramSkillMPConsumption()
{
int cast = Preferences.getInteger( "libramSummons" );
return libramSkillMPConsumption( cast + 1 );
}
public static final void setLibramSkillCasts( int cost )
{
// With sufficient mana cost reduction, the first, second, and
// third libram summons all cost 1 MP. Therefore, we can't
// necessarily tell how many times librams have been used today
// by looking at the summoning cost.
// Heuristic: if the mana cost shown by the bookcase agrees
// with our current calculated mana cost, assume we have it
// right. Otherwise, assume that summons have been made outside
// of KoLmafia and back-calculate from the bookshelf's cost.
// Get KoLmafia's idea of number of casts
int casts = Preferences.getInteger( "libramSummons" );
// If the next cast costs what the bookshelf says it costs,
// assume we're correct.
if ( libramSkillMPConsumption( casts + 1 ) == cost )
{
return;
}
// Otherwise, derive number of casts from unadjusted mana cost
// Make sure we have updated modifiers - otherwise, the initial
// cost setting done at login may ignore our MP cost adjustments.
KoLCharacter.recalculateAdjustments();
cost -= KoLCharacter.getManaCostAdjustment();
// cost = 1 + (n * (n-1) / 2)
//
// n^2 - n + (2 - 2cost) = 0
//
// Use the quadratic formula
//
// a = 1, b = -1, c = 2-2*cost
//
// x = ( 1 + sqrt(8*cost - 7))/2
int count = ( 1 + (int)Math.sqrt( 8 * cost - 7 ) ) / 2;
Preferences.setInteger( "libramSummons", count - 1 );
LockableListFactory.sort(KoLConstants.summoningSkills);
LockableListFactory.sort(KoLConstants.usableSkills);
}
/**
* Determines the cost for a specific casting of a libram skill
*
* @param count which casting
* @return the MP cost to cast it
*/
public static final int libramSkillMPConsumption( final int cast )
{
// Old formula: n * (n+1) / 2
// return Math.max( (cast * ( cast + 1 ) / 2 + KoLCharacter.getManaCostAdjustment(), 1 );
// New formula: 1 + (n * (n-1) / 2)
return Math.max( 1 + cast * ( cast - 1 ) / 2 + KoLCharacter.getManaCostAdjustment(), 1 );
}
/**
* Determines the cost for casting a libram skill multiple times
*
* @param cast which casting
* @param count how many casts
* @return the MP cost to cast it
*/
public static final int libramSkillMPConsumption( int cast, int count )
{
int total = 0;
while ( count-- > 0 )
{
total += libramSkillMPConsumption( cast++ );
}
return total;
}
/**
* Determines how many times you can cast libram skills with the
* specified amount of MP
*
* @param availableMP how much MP is available
* @return the number of casts
*/
public static final int libramSkillCasts( int availableMP )
{
int cast = Preferences.getInteger( "libramSummons" );
return Math.min( 200, libramSkillCasts( cast + 1, availableMP ) );
}
/**
* Determines how many times you can cast libram skills with the
* specified amount of MP starting with specified casting
*
* @param cast which casting
* @param availableMP how much MP is available
* @return the number of casts
*/
public static final int libramSkillCasts( int cast, int availableMP )
{
int mpCost = SkillDatabase.libramSkillMPConsumption( cast );
int count = 0;
while ( mpCost <= availableMP )
{
count++;
availableMP -= mpCost;
mpCost = SkillDatabase.libramSkillMPConsumption( ++cast );
}
return count;
}
public static final int stackLumpsCost()
{
int mpCost = 1;
int casts = Preferences.getInteger( "_stackLumpsUses" );
if ( casts < 0 ) return mpCost;
for ( int i = 0; i <= casts; i++ )
{
mpCost += 10*Math.pow( 10, i );
}
return mpCost;
}
/**
* Returns how many rounds of buff are gained by using the skill with the given Id.
*
* @param skillId The id of the skill to lookup
* @return The duration of effect the cast gives
*/
public static final int getEffectDuration( final int skillId )
{
Object duration = SkillDatabase.durationById.get( IntegerPool.get( skillId ) );
if ( duration == null )
{
return 0;
}
int actualDuration = ( (Integer) duration ).intValue();
if ( actualDuration == 0 )
{
return 0;
}
int type = SkillDatabase.getSkillType( skillId );
if ( type == SkillDatabase.SONG )
{
int multiplier = KoLCharacter.hasSkill( SkillPool.GOOD_SINGING_VOICE ) ? 2 : 1;
return actualDuration * multiplier;
}
if ( type != SkillDatabase.BUFF )
{
switch ( skillId )
{
case SkillPool.SPIRIT_BOON:
return KoLCharacter.getBlessingLevel() * 5;
case SkillPool.WAR_BLESSING:
case SkillPool.SHE_WHO_WAS_BLESSING:
case SkillPool.STORM_BLESSING:
if ( KoLCharacter.getClassType() != KoLCharacter.TURTLE_TAMER )
{
return 10;
}
break;
case SkillPool.BIND_VAMPIEROGHI:
case SkillPool.BIND_VERMINCELLI:
case SkillPool.BIND_ANGEL_HAIR_WISP:
case SkillPool.BIND_UNDEAD_ELBOW_MACARONI:
case SkillPool.BIND_PENNE_DREADFUL:
case SkillPool.BIND_LASAGMBIE:
case SkillPool.BIND_SPICE_GHOST:
if ( KoLCharacter.getClassType() != KoLCharacter.PASTAMANCER )
{
return 10;
}
break;
case SkillPool.REV_ENGINE:
return Math.max( Math.abs( KoLCharacter.getAudience() ), 5 );
case SkillPool.BIKER_SWAGGER:
return Math.max( Math.abs( KoLCharacter.getAudience() ), 10 );
}
return actualDuration;
}
if ( KoLConstants.inventory.contains( UseSkillRequest.WIZARD_HAT ) ||
KoLCharacter.hasEquipped( UseSkillRequest.WIZARD_HAT, EquipmentManager.HAT ) )
{
actualDuration += 5;
}
BuffTool [] tools =
( SkillDatabase.isTurtleTamerBuff( skillId ) ) ? UseSkillRequest.TAMER_TOOLS :
( SkillDatabase.isSaucerorBuff( skillId ) ) ? UseSkillRequest.SAUCE_TOOLS :
( SkillDatabase.isAccordionThiefSong( skillId ) ) ? UseSkillRequest.THIEF_TOOLS :
null;
if ( tools == null )
{
return actualDuration;
}
int inventoryDuration = 0;
for ( int i = 0; i < tools.length; ++ i )
{
BuffTool tool = tools[ i ];
int current = actualDuration + tool.getBonusTurns();
if ( current <= inventoryDuration )
{
continue;
}
if ( ( tool.hasEquipped() || KoLConstants.inventory.contains( tool.getItem() ) ) &&
( !tool.isClassLimited() || KoLCharacter.getClassType() == tool.getClassType() ) )
{
inventoryDuration = current;
}
}
return inventoryDuration;
}
/**
* Returns whether or not this is a normal skill that can only be used on the player.
*
* @return <code>true</code> if the skill is a normal skill
*/
public static final boolean isNormal( final int skillId )
{
Object skillType = SkillDatabase.skillTypeById.get( IntegerPool.get( skillId ) );
if ( skillType == null )
return false;
int type = ( (Integer) skillType ).intValue();
return type == SUMMON || type == REMEDY || type == SELF_ONLY ||
type == SONG || type == COMBAT_NONCOMBAT_REMEDY || type == EXPRESSION;
}
/**
* Returns whether or not the skill is a passive.
*
* @return <code>true</code> if the skill is passive
*/
public static final boolean isPassive( final int skillId )
{
// Shake it off is a passive as well as a non-combat heal
return SkillDatabase.isType( skillId, SkillDatabase.PASSIVE ) ||
SkillDatabase.isType( skillId, SkillDatabase.COMBAT_PASSIVE );
}
/**
* Returns whether or not the skill is a buff (ie: can be used on others).
*
* @return <code>true</code> if the skill can target other players
*/
public static final boolean isBuff( final int skillId )
{
return SkillDatabase.isType( skillId, SkillDatabase.BUFF );
}
public static final boolean isTurtleTamerBuff( final int skillId )
{
return ( skillId > 2000 && skillId < 3000 && SkillDatabase.isBuff( skillId ) );
}
public static final boolean isSaucerorBuff( final int skillId )
{
return ( skillId > 4000 && skillId < 5000 && SkillDatabase.isBuff( skillId ) );
}
public static final boolean isAccordionThiefSong( final int skillId )
{
return ( skillId > 6000 && skillId < 7000 && SkillDatabase.isBuff( skillId ) );
}
/**
* Returns whether or not the skill is a combat skill (ie: can be used while fighting).
*
* @return <code>true</code> if the skill can be used in combat
*/
public static final boolean isCombat( final int skillId )
{
return SkillDatabase.isType( skillId, SkillDatabase.COMBAT ) ||
SkillDatabase.isType( skillId, SkillDatabase.COMBAT_NONCOMBAT_REMEDY ) ||
SkillDatabase.isType( skillId, SkillDatabase.COMBAT_PASSIVE );
}
/**
* Returns whether or not the skill is a song
*
* @return <code>true</code> if the skill is a song
*/
public static final boolean isSong( final int skillId )
{
return SkillDatabase.isType( skillId, SkillDatabase.SONG );
}
/**
* Returns whether or not the skill is an expression
*
* @return <code>true</code> if the skill is an expression
*/
public static final boolean isExpression( final int skillId )
{
return SkillDatabase.isType( skillId, SkillDatabase.EXPRESSION );
}
/**
* Returns whether or not the skill is a walk
*
* @return <code>true</code> if the skill is a walk
*/
public static final boolean isWalk( final int skillId )
{
return SkillDatabase.isType( skillId, SkillDatabase.WALK );
}
/**
* Returns whether or not the skill is a summon
*
* @return <code>true</code> if the skill is a summon
*/
public static final boolean isSummon( final int skillId )
{
return SkillDatabase.isType( skillId, SkillDatabase.SUMMON );
}
/**
* Utility method used to determine if the given skill is of the appropriate type.
*/
private static final boolean isType( final int skillId, final int type )
{
Object skillType = SkillDatabase.skillTypeById.get( IntegerPool.get( skillId ) );
return skillType == null ? false : ( (Integer) skillType ).intValue() == type;
}
public static final boolean isSoulsauceSkill( final int skillId )
{
return SkillDatabase.getSoulsauceCost( skillId ) > 0;
}
public static final int getSoulsauceCost( final int skillId )
{
switch ( skillId )
{
case SkillPool.SOUL_BUBBLE:
return 5;
case SkillPool.SOUL_FINGER:
return 40;
case SkillPool.SOUL_BLAZE:
return 100;
case SkillPool.SOUL_FOOD:
return 5;
case SkillPool.SOUL_ROTATION:
return 25;
case SkillPool.SOUL_FUNK:
return 50;
default:
return 0;
}
}
public static final boolean isThunderSkill( final int skillId )
{
return SkillDatabase.getThunderCost( skillId ) > 0;
}
public static final int getThunderCost( final int skillId )
{
switch ( skillId )
{
case SkillPool.THUNDER_CLAP:
return 40;
case SkillPool.THUNDERCLOUD:
return 20;
case SkillPool.THUNDER_BIRD:
return 1;
case SkillPool.THUNDERHEART:
return 20;
case SkillPool.THUNDERSTRIKE:
return 5;
case SkillPool.THUNDER_DOWN_UNDERWEAR:
return 60;
default:
return 0;
}
}
public static final boolean isRainSkill( final int skillId )
{
return SkillDatabase.getRainCost( skillId ) > 0;
}
public static final int getRainCost( final int skillId )
{
switch ( skillId )
{
case SkillPool.RAIN_MAN:
return 50;
case SkillPool.RAINY_DAY:
return 20;
case SkillPool.MAKE_IT_RAIN:
return 10;
case SkillPool.RAIN_DANCE:
return 10;
case SkillPool.RAINBOW:
return 3;
case SkillPool.RAINCOAT:
return 40;
default:
return 0;
}
}
public static final boolean isLightningSkill( final int skillId )
{
return SkillDatabase.getLightningCost( skillId ) > 0;
}
public static final int getLightningCost( final int skillId )
{
switch ( skillId )
{
case SkillPool.LIGHTNING_STRIKE:
return 20;
case SkillPool.CLEAN_HAIR_LIGHTNING:
return 10;
case SkillPool.BALL_LIGHTNING:
return 5;
case SkillPool.SHEET_LIGHTNING:
return 10;
case SkillPool.LIGHTNING_BOLT_RAIN:
return 1;
case SkillPool.LIGHTNING_ROD:
return 20;
default:
return 0;
}
}
public static final AdventureResult getManaItemCost( final int skillId )
{
switch ( skillId )
{
case SkillPool.DARK_RITUAL:
return ItemPool.get( ItemPool.BLACK_MANA, 1 );
case SkillPool.ANCESTRAL_RECALL:
return ItemPool.get( ItemPool.BLUE_MANA, 1 );
case SkillPool.GIANT_GROWTH:
return ItemPool.get( ItemPool.GREEN_MANA, 1 );
case SkillPool.LIGHTNING_BOLT_CARD:
return ItemPool.get( ItemPool.RED_MANA, 1 );
case SkillPool.HEALING_SALVE:
return ItemPool.get( ItemPool.WHITE_MANA, 1 );
default:
return null;
}
}
public static final int getBlackManaCost( final int skillId )
{
return skillId == SkillPool.DARK_RITUAL ? 1 : 0;
}
public static final int getBlueManaCost( final int skillId )
{
return skillId == SkillPool.ANCESTRAL_RECALL ? 1 : 0;
}
public static final int getGreenManaCost( final int skillId )
{
return skillId == SkillPool.GIANT_GROWTH ? 1 : 0;
}
public static final int getRedManaCost( final int skillId )
{
return skillId == SkillPool.LIGHTNING_BOLT_CARD ? 1 : 0;
}
public static final int getWhiteManaCost( final int skillId )
{
return skillId == SkillPool.HEALING_SALVE ? 1 : 0;
}
public static final int getAdventureCost( final int skillId )
{
switch ( skillId )
{
case SkillPool.HIBERNATE:
case SkillPool.SPIRIT_VACATION:
case SkillPool.TRANSCENDENTAL_DENTE:
case SkillPool.SIMMER:
case SkillPool.RECRUIT_ZOMBIE:
case SkillPool.CHECK_MIRROR:
case SkillPool.RAIN_MAN:
case SkillPool.EVOKE_ELDRITCH_HORROR:
return 1;
default:
return 0;
}
}
/**
* Utility method used to determine if the given skill can be made permanent
*/
public static final boolean isPermable( final int skillId )
{
switch ( skillId )
{
case SkillPool.OLD_OLD_SMILE:
case SkillPool.SMILE_OF_MR_A:
case SkillPool.ARSE_SHOOT:
// Item granted skills
return false;
case SkillPool.STEEL_LIVER:
case SkillPool.STEEL_STOMACH:
case SkillPool.STEEL_SPLEEN:
// Steel Organs
return false;
case SkillPool.LUST: // Lust
case SkillPool.GLUTTONY: // Gluttony
case SkillPool.GREED: // Greed
case SkillPool.SLOTH: // Sloth
case SkillPool.WRATH: // Wrath
case SkillPool.ENVY: // Envy
case SkillPool.PRIDE: // Pride
// Bad Moon skills
return false;
case SkillPool.DOG_TIRED:
case SkillPool.HOLLOW_LEG:
// VIP lounge skills
return false;
case SkillPool.GOTHY_HANDWAVE:
case SkillPool.BREAK_IT_ON_DOWN:
case SkillPool.POP_AND_LOCK:
case SkillPool.RUN_LIKE_THE_WIND:
case SkillPool.CARBOLOADING:
// Nemesis skills
return false;
case SkillPool.MIYAGI_MASSAGE:
case SkillPool.SALAMANDER_KATA:
case SkillPool.FLYING_FIRE_FIST:
case SkillPool.STINKPALM:
case SkillPool.SEVEN_FINGER_STRIKE:
case SkillPool.KNUCKLE_SANDWICH:
case SkillPool.CHILLED_MONKEY_BRAIN:
case SkillPool.DRUNKEN_BABY_STYLE:
case SkillPool.WORLDPUNCH:
case SkillPool.ZENDO_KOBUSHI_KANCHO:
// Way of the Surprising Fist skills
return false;
case SkillPool.OLFACTION:
case SkillPool.THICK_SKINNED:
case SkillPool.CHIP_ON_YOUR_SHOULDER:
case SkillPool.REQUEST_SANDWICH:
case SkillPool.PIRATE_BELLOW:
// Auto-HP-Permed
return false;
case SkillPool.SPIRIT_CAYENNE:
case SkillPool.SPIRIT_PEPPERMINT:
case SkillPool.SPIRIT_GARLIC:
case SkillPool.SPIRIT_WORMWOOD:
case SkillPool.SPIRIT_BACON:
case SkillPool.SPIRIT_NOTHING:
// Derived skills
return false;
case SkillPool.GEMELLIS_MARCH_OF_TESTERY:
// Skills players can't get
return false;
case SkillPool.MILD_CURSE:
// Other skills from this class are not permable
return true;
case SkillPool.SHOOT:
// Avatar of West of Loathing skills
return false;
}
switch ( skillId / 1000 )
{
case 7: // Skills granted by items
case 8: // Mystical Bookshelf Skills
case 11: // Avatar of Boris skills
case 12: // Zombie Slayer skills
case 14: // Avatar of Jarlsberg skills
case 15: // Avatar of Sneaky Pete skills
case 16: // Heavy Rains skills
case 17: // Ed skills
case 18: // Cow Puncher skills
case 19: // Bean Slinger skills
case 20: // Snake Oiler skills
case 21: // The Source skills
case 22: // Nuclear Autumn skills
case 23: // Gelatinous Noob skills
return false;
}
return true;
}
public static final boolean isBookshelfSkill( final int skillId )
{
return skillId >= SkillPool.SNOWCONE && skillId <= SkillPool.CONFISCATOR;
}
public static final boolean isBookshelfSkill( final String skillName )
{
return isBookshelfSkill( SkillDatabase.getSkillId( skillName ) );
}
public static final int skillToBook( final String skillName )
{
switch ( SkillDatabase.getSkillId( skillName ) )
{
case SkillPool.SNOWCONE:
return ItemPool.SNOWCONE_BOOK;
case SkillPool.STICKER:
return ItemPool.STICKER_BOOK;
case SkillPool.SUGAR:
return ItemPool.SUGAR_BOOK;
case SkillPool.CLIP_ART:
return ItemPool.CLIP_ART_BOOK;
case SkillPool.RAD_LIB:
return ItemPool.RAD_LIB_BOOK;
case SkillPool.SMITHSNESS:
return ItemPool.SMITH_BOOK;
case SkillPool.CANDY_HEART:
return ItemPool.CANDY_BOOK;
case SkillPool.PARTY_FAVOR:
return ItemPool.DIVINE_BOOK;
case SkillPool.LOVE_SONG:
return ItemPool.LOVE_BOOK;
case SkillPool.BRICKOS:
return ItemPool.BRICKO_BOOK;
case SkillPool.DICE:
return ItemPool.DICE_BOOK;
case SkillPool.RESOLUTIONS:
return ItemPool.RESOLUTION_BOOK;
case SkillPool.TAFFY:
return ItemPool.TAFFY_BOOK;
case SkillPool.HILARIOUS:
return ItemPool.HILARIOUS_BOOK;
case SkillPool.TASTEFUL:
return ItemPool.TASTEFUL_BOOK;
case SkillPool.CARDS:
return ItemPool.CARD_GAME_BOOK;
case SkillPool.GEEKY:
return ItemPool.GEEKY_BOOK;
case SkillPool.CONFISCATOR:
return ItemPool.CONFISCATOR_BOOK;
}
return -1;
}
/**
* Returns all skills in the database of the given type.
*/
public static final List<UseSkillRequest> getSkillsByType( final int type )
{
return SkillDatabase.getSkillsByType( type, false );
}
public static final List<UseSkillRequest> getSkillsByType( final int type, final boolean onlyKnown )
{
ArrayList<UseSkillRequest> list = new ArrayList<UseSkillRequest>();
Object[] keys = SkillDatabase.skillTypeById.keySet().toArray();
for ( int i = 0; i < keys.length; ++i )
{
boolean shouldAdd = false;
int skillId = ( (Integer) keys[ i ] ).intValue();
Integer value = SkillDatabase.skillTypeById.get( skillId );
if ( value == null )
continue;
int skillType = value.intValue();
if ( type == SkillDatabase.ALL )
{
shouldAdd = true;
}
else if ( type == SkillDatabase.CASTABLE )
{
shouldAdd = skillType == SUMMON || skillType == REMEDY || skillType == SELF_ONLY ||
skillType == BUFF || skillType == SONG || skillType == COMBAT_NONCOMBAT_REMEDY ||
skillType == EXPRESSION || skillType == WALK;
}
else if ( type == SkillDatabase.COMBAT )
{
shouldAdd = skillType == COMBAT || skillType == COMBAT_NONCOMBAT_REMEDY || skillType == COMBAT_PASSIVE;
}
else if ( type == SkillDatabase.REMEDY )
{
shouldAdd = skillType == REMEDY || skillType == COMBAT_NONCOMBAT_REMEDY;
}
else if ( type == SkillDatabase.PASSIVE )
{
shouldAdd = skillType == PASSIVE || skillType == COMBAT_PASSIVE;
}
else
{
shouldAdd = skillType == type;
}
if ( !shouldAdd ||
onlyKnown && !KoLCharacter.hasSkill( skillId ) )
{
continue;
}
list.add( UseSkillRequest.getUnmodifiedInstance( skillId ) );
}
return list;
}
public static final String toTitleCase( final String s )
{
boolean found = false;
char[] chars = s.toLowerCase().toCharArray();
for ( int i = 0; i < chars.length; ++i )
{
if ( !found && Character.isLetter( chars[ i ] ) )
{
chars[ i ] = Character.toUpperCase( chars[ i ] );
found = true;
}
else if ( Character.isWhitespace( chars[ i ] ) )
{
found = false;
}
}
return String.valueOf( chars );
}
/**
* Returns whether or not an item with a given name exists in the database; this is useful in the event that an item
* is encountered which is not tradeable (and hence, should not be displayed).
*
* @return <code>true</code> if the item is in the database
*/
public static final boolean contains( final String skillName )
{
if ( skillName == null )
{
return false;
}
return Arrays.binarySearch( SkillDatabase.canonicalNames, StringUtilities.getCanonicalName( skillName ) ) >= 0;
}
/**
* Returns the set of skills keyed by name
*
* @return The set of skills keyed by name
*/
public static final Set entrySet()
{
return SkillDatabase.skillById.entrySet();
}
private static final ArrayList<String> skillNames = new ArrayList<String>();
public static final void generateSkillList( final StringBuffer buffer, final boolean appendHTML )
{
ArrayList<String>[] categories = new ArrayList[ SkillDatabase.CATEGORIES.length ];
if ( SkillDatabase.skillNames.isEmpty() )
{
SkillDatabase.skillNames.addAll( SkillDatabase.skillByName.keySet() );
}
for ( int i = 0; i < categories.length; ++i )
{
categories[ i ] = new ArrayList<String>();
categories[ i ].addAll( SkillDatabase.skillsByCategory.get( SkillDatabase.CATEGORIES[ i ] ) );
for ( int j = 0; j < categories[ i ].size(); ++j )
{
if ( !KoLConstants.availableSkills.contains( UseSkillRequest.getUnmodifiedInstance( (String) categories[ i ].get( j ) ) ) )
{
categories[ i ].remove( j-- );
}
}
}
boolean printedList = false;
for ( int i = 0; i < categories.length; ++i )
{
if ( categories[ i ].isEmpty() )
{
continue;
}
if ( printedList )
{
if ( appendHTML )
{
buffer.append( "<br>" );
}
else
{
buffer.append( KoLConstants.LINE_BREAK );
}
}
SkillDatabase.appendSkillList(
buffer, appendHTML, SkillDatabase.toTitleCase( SkillDatabase.CATEGORIES[ i ] ),
categories[ i ] );
printedList = true;
}
}
private static final void appendSkillList( final StringBuffer buffer, final boolean appendHTML,
final String listName, final ArrayList<String> list )
{
if ( list.isEmpty() )
{
return;
}
Collections.sort( list );
if ( appendHTML )
{
buffer.append( "<u><b>" );
}
buffer.append( SkillDatabase.toTitleCase( listName ) );
if ( appendHTML )
{
buffer.append( "</b></u><br>" );
}
else
{
buffer.append( KoLConstants.LINE_BREAK );
}
String currentSkill;
for ( int j = 0; j < list.size(); ++j )
{
currentSkill = (String) list.get( j );
if ( appendHTML )
{
buffer.append( "<a onClick=\"javascript:skill(" );
buffer.append( SkillDatabase.getSkillId( currentSkill ) );
buffer.append( ");\">" );
}
else
{
buffer.append( " - " );
}
buffer.append( currentSkill );
if ( appendHTML )
{
buffer.append( "</a><br>" );
}
else
{
buffer.append( KoLConstants.LINE_BREAK );
}
}
}
/**
* Utility method used to retrieve the full name of a skill, given a substring representing it.
*/
public static final String getSkillName( final String substring, final List<UseSkillRequest> list )
{
UseSkillRequest[] skills = new UseSkillRequest[ list.size() ];
list.toArray( skills );
String name = substring.toLowerCase();
int skillIndex = -1;
boolean ambiguous = false;
for ( int i = 0; i < skills.length; ++i )
{
String skill = skills[ i ].getSkillName();
if ( skill.toLowerCase().equals( name ) )
{
return skill;
}
}
for ( int i = 0; i < skills.length; ++i )
{
String skill = skills[ i ].getSkillName();
if ( skill.toLowerCase().contains( name ) )
{
if ( ambiguous )
{
RequestLogger.printLine( skill );
}
else if ( skillIndex != -1 )
{
RequestLogger.printLine( "Possible matches:" );
RequestLogger.printLine( skills[ skillIndex ].getSkillName() );
RequestLogger.printLine( skill );
ambiguous = true;
}
else
{
skillIndex = i;
}
}
}
return (ambiguous || skillIndex == -1) ? null
: skills[ skillIndex ].getSkillName();
}
/**
* Utility method used to retrieve the full name of a skill, given a substring representing it.
*/
public static final String getSkillName( final String substring )
{
return getSkillName( substring, getSkillsByType( ALL ) );
}
/**
* Utility method used to retrieve the full name of a castable skill,
* given a substring representing it.
*/
public static final String getUsableSkillName( final String substring )
{
return getSkillName( substring, getSkillsByType( CASTABLE ) );
}
/**
* Utility method used to retrieve the full name of a known castable
* skill, given a substring representing it.
*/
public static final String getUsableKnownSkillName( final String substring )
{
return getSkillName( substring, getSkillsByType( CASTABLE, true ) );
}
/**
* Utility method used to retrieve the full name of a combat skill, given a substring representing it.
*/
public static final String getCombatSkillName( final String substring )
{
return getSkillName( substring, getSkillsByType( COMBAT ) );
}
/**
* Utility method used to retrieve the maximum daily casts of a skill. Returns -1 if no limit.
*/
public static int getMaxCasts( int skillId )
{
UseSkillRequest skill = UseSkillRequest.getUnmodifiedInstance( skillId );
if ( skill == null )
{
return -1;
}
int max = skill.getMaximumCast();
return ( max == Integer.MAX_VALUE ? -1 : max );
}
/**
* Method that is called when we need to update the number of casts for a given skill.
*/
public static void registerCasts( int skillId, int count )
{
Object oldCasts = SkillDatabase.castsById.get( IntegerPool.get( skillId ) );
if ( oldCasts == null )
{
return;
}
int newCasts = ( (Integer) oldCasts ).intValue() + count;
SkillDatabase.castsById.put( IntegerPool.get( skillId ), IntegerPool.get( newCasts ) );
}
public static String skillString( final int skillId, final String skillName, final String image, final int type, final int mp, final int duration, final int level )
{
StringBuilder buffer = new StringBuilder();
buffer.append( String.valueOf( skillId ) );
buffer.append( "\t" );
buffer.append( skillName );
buffer.append( "\t" );
buffer.append( image );
buffer.append( "\t" );
buffer.append( String.valueOf( type ) );
buffer.append( "\t" );
buffer.append( String.valueOf( mp) );
buffer.append( "\t" );
buffer.append( String.valueOf( duration ) );
if ( level != 0 )
{
buffer.append( "\t" );
buffer.append( String.valueOf( level ) );
}
return buffer.toString();
}
public static final void registerSkill( final int skillId, String skillName )
{
// Load the description text for this skill
String text = DebugDatabase.readSkillDescriptionText( skillId );
if ( text == null )
{
return;
}
if ( skillName == null )
{
skillName = DebugDatabase.parseName( text );
}
String image = DebugDatabase.parseImage( text );
// Detach name and image from being substrings
skillName = new String( skillName );
image = new String( image );
String typeString = DebugDatabase.parseSkillType( text );
int type =
typeString.equals( "Passive" ) ? 0 :
typeString.equals( "Noncombat" ) ? 3 :
typeString.equals( "Combat" ) ? 5 :
-1;
int mp = DebugDatabase.parseSkillMPCost( text );
int duration = DebugDatabase.parseSkillEffectDuration( text );
int level = 0;
SkillDatabase.addSkill( skillId, skillName, image, type, mp, duration, level );
String printMe;
// Print what goes in classkills.txt
printMe = "--------------------";
RequestLogger.printLine( printMe );
RequestLogger.updateSessionLog( printMe );
printMe = SkillDatabase.skillString( skillId, skillName, image, type, mp, duration, level );
RequestLogger.printLine( printMe );
RequestLogger.updateSessionLog( printMe );
printMe = "--------------------";
RequestLogger.printLine( printMe );
RequestLogger.updateSessionLog( printMe );
String effectName = DebugDatabase.parseSkillEffectName( text );
if ( !effectName.equals( "" ) && EffectDatabase.getEffectId( effectName, true ) == -1 )
{
String effectDescid = DebugDatabase.parseSkillEffectId( text );
EffectDatabase.registerEffect( effectName, effectDescid, "cast 1 " + skillName );
}
}
/**
* Utility method used to get the number of times a skill has been cast in the current session.
*/
public static int getCasts( int skillId )
{
Object casts = (Object) SkillDatabase.castsById.get( IntegerPool.get( skillId ) );
if ( casts == null )
{
return 0;
}
return ( (Integer) casts ).intValue();
}
public static boolean sourceAgentSkill( int skillId )
{
// Return true if this skill is usable against a source agent
// All class 21 skills can be used
if ( ( skillId / 1000 ) == 21 )
{
return true;
}
// Some Source Terminal skills are usable. Turbo for sure.
// List all until we learn which ones are not usable
switch ( skillId )
{
case SkillPool.EXTRACT:
case SkillPool.DIGITIZE:
case SkillPool.COMPRESS:
case SkillPool.DUPLICATE:
case SkillPool.PORTSCAN:
case SkillPool.TURBO:
return true;
}
return false;
}
public static boolean summonsMonster( int skillId )
{
switch (skillId )
{
case SkillPool.RAIN_MAN:
case SkillPool.EVOKE_ELDRITCH_HORROR:
return true;
}
return false;
}
}