WeaponToken.java

Index Score
pcgen.io.exporttoken
PCGen

View: Reasons, Metrics, Source Code

These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.

MetricDescription
COMPARISONSNumber of comparison operators
CYCLOMATICCyclomatic complexity
EXEC_COMMENTSComments in executable code
PARAMSNumber of formal parameter declarations
LOCLines of code
LINE_COMMENTNumber of line comments
LINESNumber of lines in the source file
BLOCKSNumber of blocks
OPERATORSNumber of operators
PROGRAM_LENGTHHalstead program length
OPERANDSNumber of operands
INTERFACE_COMPLEXITYInterface complexity
SIZESize of the file in bytes
ELOCEffective lines of code
DECL_COMMENTSComments in declarations
COMMENTSComment lines
LOGICAL_LINESNumber of statements
EXITSProcedure exits
DOC_COMMENTNumber of javadoc comment lines
JAVA0145JAVA0145 Tab character used in source file
UNIQUE_OPERANDSNumber of unique operands
RETURNSNumber of return points from functions
PROGRAM_VOCABHalstead program vocabulary
FUNCTIONSNumber of function declarations
JAVA0177JAVA0177 Variable declaration missing initializer
WHITESPACENumber of whitespace lines
JAVA0138JAVA0138 N parameters defined for method (maximum: M)
LOOPSNumber of loops
JAVA0076JAVA0076 Use of magic number
JAVA0034JAVA0034 Missing braces in if statement
JAVA0173JAVA0173 Unused method parameter
UNIQUE_OPERATORSNumber of unique operators
BLOCK_COMMENTNumber of block comment lines
JAVA0117JAVA0117 Missing javadoc: method 'method'
PROGRAM_VOLUMEHalstead program volume
JAVA0136JAVA0136 N methods defined in class (maximum: M)
JAVA0126JAVA0126 Method declares unchecked exception in throws
NEST_DEPTHMaximum nesting depth
JAVA0110JAVA0110 Incorrect javadoc: no @return tag
/* * WeaponToken.java * Copyright 2003 (C) Devon Jones <soulcatcher@evilsoft.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Created on December 15, 2003, 12:21 PM * * Current Ver: $Revision: 6984 $ * Last Editor: $Author: thpr $ * Last Edited: $Date: 2008-07-01 21:22:58 -0400 (Tue, 01 Jul 2008) $ * */ package pcgen.io.exporttoken; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import pcgen.cdom.base.Constants; import pcgen.cdom.enumeration.FormulaKey; import pcgen.cdom.enumeration.ObjectKey; import pcgen.cdom.enumeration.StringKey; import pcgen.cdom.reference.CDOMSingleRef; import pcgen.core.Equipment; import pcgen.core.Globals; import pcgen.core.PlayerCharacter; import pcgen.core.RuleConstants; import pcgen.core.SettingsHandler; import pcgen.core.SizeAdjustment; import pcgen.core.WeaponProf; import pcgen.core.bonus.BonusObj; import pcgen.core.bonus.BonusUtilities; import pcgen.io.ExportHandler; import pcgen.util.Delta; import pcgen.util.Logging; import pcgen.util.enumeration.AttackType; /** * Deal with the WEAPON Token */ public class WeaponToken extends Token { /** Token Name */ public static final String TOKENNAME = "WEAPON"; /** PC Bonus = 0 */ public static final int WPTYPEBONUS_PC = 0; /** Equipment Bonus = 1 */ public static final int WPTYPEBONUS_EQ = 1; /** Feat Bonus = 2 */ public static final int WPTYPEBONUS_FEAT = 2; /** Template Bonus = 3 */ public static final int WPTYPEBONUS_TEMPLATE = 3; /** Damage Mode normal = 0 */ public static final int DAMAGEMODE_NORMAL = 0; /** Damage Mode basic = 1 */ public static final int DAMAGEMODE_BASIC = 1; /** Damage Mode offhand = 2 */ public static final int DAMAGEMODE_OFFHAND = 2; /** Damage Mode twohands = 3 */ public static final int DAMAGEMODE_TWOHANDS = 3; /** Damage Mode double = 4 */ public static final int DAMAGEMODE_DOUBLE = 4; // This defines if I should return the values // based on weapon's location or not. // 1,2,3 and 4 overrides the actual location // of the weapon and calculates all data // with that setting /** total hit = 0 */ public static final int HITMODE_TOTALHIT = 0; /** One weapon = 1 */ public static final int HITMODE_BASEHIT = 1; /** Two weapons, this is primary, off-hand heavy = 2 */ public static final int HITMODE_TWPHITH = 2; /** Two weapons, this is primary, off-hand light = 3 */ public static final int HITMODE_TWPHITL = 3; /** Two weapons, this is off-hand (heavy) = 4 */ public static final int HITMODE_TWOHIT = 4; /** Two weapons, this is off-hand (heavy) = 4 */ public static final int HITMODE_TWFOHH = 4; /** Two weapons, this is off-hand (light) = 5 */ public static final int HITMODE_TWFOHL = 5; /** One weapon, off-hand = 6 */ public static final int HITMODE_OHHIT = 6; /** One weapon, both-hands = 7 */ public static final int HITMODE_THHIT = 7; /** * @see pcgen.io.exporttoken.Token#getTokenName() */ @Override public String getTokenName() { return TOKENNAME; } /** * @see pcgen.io.exporttoken.Token#getToken(java.lang.String, pcgen.core.PlayerCharacter, pcgen.io.ExportHandler) */ @Override public String getToken(String tokenSource, PlayerCharacter pc, ExportHandler eh) { StringTokenizer aTok = new StringTokenizer(tokenSource, ".", false); //Weapon Token aTok.nextToken(); int merge = Constants.MERGE_ALL; int weapon = 0; Equipment eq; // First check to see if there is a MERGE token String token = aTok.nextToken(); if (token.equals("MERGENONE")) { merge = Constants.MERGE_NONE; token = aTok.nextToken(); } else if (token.equals("MERGELOC")) { merge = Constants.MERGE_LOCATION; token = aTok.nextToken(); } else if (token.equals("MERGEALL")) { merge = Constants.MERGE_ALL; token = aTok.nextToken(); } List<Equipment> weaponList = pc.getExpandedWeapons(merge); if (token.equals("ALL")) { token = aTok.nextToken(); } else if (token.equals("EQUIPPED")) { // remove all weapons which are not equipped from list for (Iterator<Equipment> it = weaponList.iterator(); it.hasNext();) { if (!it.next().isEquipped()) { it.remove(); } } token = aTok.nextToken(); } else if (token.equals("NOT_EQUIPPED")) { // remove all weapons which are equipped from list for (Iterator<Equipment> it = weaponList.iterator(); it.hasNext();) { if (it.next().isEquipped()) { it.remove(); } } token = aTok.nextToken(); } else if (token.equals("CARRIED")) { // remove all weapons which are not carried from list for (Iterator<Equipment> it = weaponList.iterator(); it.hasNext();) { if (it.next().numberCarried().intValue() == 0) { it.remove(); } } token = aTok.nextToken(); } else if (token.equals("NOT_CARRIED")) { // remove all weapons which are carried from list for (Iterator<Equipment> it = weaponList.iterator(); it.hasNext();) { if (it.next().numberCarried().intValue() > 0) { it.remove(); } } token = aTok.nextToken(); } weapon = getIntToken(token, 0); if (weapon < weaponList.size()) { eq = weaponList.get(weapon); if (weapon == weaponList.size() - 1 && eh != null && eh.getExistsOnly()) { eh.setNoMoreItems(true); } return getWeaponToken(pc, eq, aTok); } else if (eh != null && eh.getExistsOnly()) { eh.setNoMoreItems(true); if (eh.getCheckBefore()) { eh.setCanWrite(false); } } return ""; } /** * Get the Weapon Token * @param pc * @param eq * @param aTok * @return Weapon Token */ public String getWeaponToken(PlayerCharacter pc, Equipment eq, StringTokenizer aTok) { String token = ""; if (aTok.hasMoreTokens()) { token = aTok.nextToken(); } int range = -1; int content = -1; int ammo = -1; if (token.equals("RANGELIST")) { range = getIntToken(aTok, -1); if (aTok.hasMoreTokens()) { token = aTok.nextToken(); } else { token = "RANGELIST"; } } if (token.equals("CONTENTS")) { if (aTok.hasMoreTokens()) { content = getIntToken(aTok, -1); if (aTok.hasMoreTokens()) { token = aTok.nextToken(); } else { token = "CONTENTS"; } } else { token = "CONTENTSCOUNT"; } } if (token.equals("AMMUNITION")) { if (aTok.hasMoreTokens()) { ammo = getIntToken(aTok, -1); if (aTok.hasMoreTokens()) { token = aTok.nextToken(); } else { token = "AMMUNITION"; } } else { token = "AMMUNITIONCOUNT"; } } if (token.equals("NAME")) { boolean star = true; if (aTok.hasMoreTokens()) { if ("NOSTAR".equals(aTok.nextToken())) { star = false; } } return getNameToken(eq, pc, star); } else if (token.equals("OUTPUTNAME")) { return getOutputNameToken(eq, pc); } else if (token.equals("LONGNAME")) { return getLongNameToken(eq); } else if (token.equals("ATTACKS")) { return getAttacksToken(pc, eq) + ""; } else if (token.equals("AMMUNITIONCOUNT")) { return getAmmunitionCountToken(pc, eq) + ""; } else if (token.equals("AMMUNITION")) { return getAmmunitionToken(pc, eq, ammo); } else if (token.equals("CONTENTSCOUNT")) { return getContentsCountToken(eq) + ""; } else if (token.equals("CONTENTS")) { return getContentsToken(eq, content); } else if (token.equals("NUMATTACKS")) { return getNumAttacksToken(pc, eq) + ""; } else if (token.equals("HEFT")) { return getHeft(pc, eq); } else if (token.equals("ISTYPE")) { if (aTok.hasMoreTokens()) { return getIsTypeToken(eq, aTok.nextToken()); } return ""; } else if (token.equals("CRIT")) { return getCritToken(pc, eq); } else if (token.equals("MULT")) { return getMultToken(pc, eq); } else if (token.equals("RANGELIST")) { return getRangeListToken(eq, range, pc); } else if (token.equals("RANGE")) { boolean units = true; if (aTok.hasMoreTokens()) { if ("NOUNITS".equals(aTok.nextToken())) { units = false; } } return getRangeToken(eq, pc, units); } else if (token.equals("SIZEMOD")) { return Delta.toString(getSizeModToken(pc)); } else if (token.equals("TYPE")) { return getTypeToken(eq); } else if (token.equals("HIT") || token.equals("TOTALHIT")) { int attack = getIntToken(aTok, -1); return getTotalHitToken(pc, eq, range, content, ammo, attack); } else if (token.equals("BASEHIT")) { int attack = getIntToken(aTok, -1); return getBaseHitToken(pc, eq, range, content, ammo, attack); } else if (token.equals("TWPHITH")) { int attack = getIntToken(aTok, -1); return getTwpHitHToken(pc, eq, range, content, ammo, attack); } else if (token.equals("TWPHITL")) { int attack = getIntToken(aTok, -1); return getTwpHitLToken(pc, eq, range, content, ammo, attack); } else if (token.equals("TWOHIT")) { int attack = getIntToken(aTok, -1); return getTwoHitToken(pc, eq, range, content, ammo, attack); } else if (token.equals("OHHIT")) { int attack = getIntToken(aTok, -1); return getOHHitToken(pc, eq, range, content, ammo, attack); } else if (token.equals("THHIT")) { int attack = getIntToken(aTok, -1); return getTHHitToken(pc, eq, range, content, ammo, attack); } else if (token.equals("CATEGORY")) { return getCategoryToken(eq); } else if (token.equals("HAND")) { return getHandToken(eq); } else if (token.equals("MAGICDAMAGE")) { return Delta.toString(getMagicDamageToken(pc, eq)); } else if (token.equals("MAGICHIT")) { return Delta.toString(getMagicHitToken(pc, eq)); } else if (token.equals("MISC")) { return Delta.toString(getMiscToken(pc, eq)); } else if (token.equals("FEATDAMAGE")) { Delta.toString(getFeatDamageToken(pc, eq)); } else if (token.equals("FEATHIT")) { Delta.toString(getFeatHitToken(pc, eq)); } else if (token.equals("TEMPLATEDAMAGE")) { Delta.toString(getTemplateDamageToken(pc, eq)); } else if (token.equals("TEMPLATEHIT")) { Delta.toString(getTemplateHitToken(pc, eq)); } else if (token.equals("DAMAGE")) { return getDamageToken(pc, eq, range, content, ammo, false, false); } else if (token.equals("BASEDAMAGE")) { return getDamageToken(pc, eq, range, content, ammo, false, true); } else if (token.equals("BASICDAMAGE")) { return getBasicDamageToken(pc, eq, range, content, ammo, false); } else if (token.equals("THDAMAGE")) { return getTHDamageToken(pc, eq, range, content, ammo, false); } else if (token.equals("OHDAMAGE")) { return getOHDamageToken(pc, eq, range, content, ammo, false); } else if (token.equals("DAMAGEBONUS") || token.equals("BONUSDAMAGE")) { return getDamageToken(pc, eq, range, content, ammo, true, false); } else if (token.equals("BASEDAMAGEBONUS")) { return getDamageToken(pc, eq, range, content, ammo, true, true); } else if (token.equals("THDAMAGEBONUS")) { return getTHDamageToken(pc, eq, range, content, ammo, true); } else if (token.equals("OHDAMAGEBONUS")) { return getOHDamageToken(pc, eq, range, content, ammo, true); } else if (token.equals("SIZE")) { return getSizeToken(eq); } else if (token.equals("SPROP")) { return getSpropToken(pc, eq, content, ammo); } else if (token.equals("REACH")) { return getReachToken(pc, eq) + ""; } else if (token.equals("WT")) { return getWTToken(pc, eq); } else if (token.equals("RATEOFFIRE")) { return getRateOfFireToken(eq); } else if (token.equals("ISLIGHT")) { return getIsLightToken(pc, eq); } return ""; } /** * Get the is light sub token * @param pc * @param eq * @return is light sub token */ public static String getIsLightToken(PlayerCharacter pc, Equipment eq) { return eq.isWeaponLightForPC(pc) ? "TRUE" : "FALSE"; } /** * Get the name sub token * @param eq * @param pc * @param star * @return name sub token */ public static String getNameToken(Equipment eq, PlayerCharacter pc, boolean star) { StringBuffer sb = new StringBuffer(); if (eq.isEquipped() && star) { sb.append("*"); } sb.append(eq.parseOutputName(eq.getOutputName(), pc)); sb.append(eq.getAppliedName()); return sb.toString(); } /** * Get output name token * @param eq * @param pc * @return out put name token */ public static String getOutputNameToken(Equipment eq, PlayerCharacter pc) { StringBuffer sb = new StringBuffer(); if (eq.isEquipped()) { sb.append("*"); } sb.append(eq.parseOutputName(eq.getOutputName(), pc)); sb.append(eq.getAppliedName()); return sb.toString(); } /** * Get the long name sub token * @param eq * @return long name sub token */ public static String getLongNameToken(Equipment eq) { StringBuffer sb = new StringBuffer(); if (eq.isEquipped()) { sb.append("*"); } sb.append(eq.longName()); sb.append(eq.getAppliedName()); return sb.toString(); } /** * Get Attacks sub token * @param pc * @param eq * @return Attacks sub token */ public static int getAttacksToken(PlayerCharacter pc, Equipment eq) { return (int) eq.bonusTo(pc, "WEAPON", "ATTACKS", true); } /** * Get ammunition count sub token * @param pc * @param eq * @return ammunition count sub token */ public static int getAmmunitionCountToken(PlayerCharacter pc, Equipment eq) { int ammoCount = 0; String containerCapacity = eq.getContainerCapacityString(); for (Equipment equip : pc.getEquipmentListInOutputOrder()) { for (String type : equip.typeList()) { if (containerCapacity.indexOf(type) >= 0) { ++ammoCount; break; } } } return ammoCount; } /** * Get the ammunition token * @param pc * @param eq * @param ammo * @return the ammunition token */ public static String getAmmunitionToken(PlayerCharacter pc, Equipment eq, int ammo) { Equipment ammoUser = getAmmoUser(pc, eq, ammo); if (ammoUser != null) { return ammoUser.getName(); } return ""; } /** * Get the contents count sub token * @param eq * @return contents count sub token */ public static int getContentsCountToken(Equipment eq) { return eq.getContainedEquipmentCount(); } /** * Get Contents token * @param eq * @param content * @return Get Contents token */ public static String getContentsToken(Equipment eq, int content) { if (content > -1) { if (content < eq.getContainedEquipmentCount()) { return eq.getContainedEquipment(content).getName(); } } return ""; } /** * Get the Heft token * @param pc * @param eq * @return heft token */ public static String getHeft(PlayerCharacter pc, Equipment eq) { String retString = ""; if (pc.sizeInt() > Globals.sizeInt(eq.getSize())) { retString = "LIGHT"; } else if (pc.sizeInt() == Globals.sizeInt(eq.getSize())) { retString = "MEDIUM"; } else { retString = "HEAVY"; } return retString; } /** * Get the is type token * @param eq * @param type * @return is type token */ public static String getIsTypeToken(Equipment eq, String type) { return isTypeToken(eq, type) ? "TRUE" : "FALSE"; } /** * Get the istype token * @param eq * @param type * @return is type token */ public static boolean isTypeToken(Equipment eq, String type) { return eq.isType(type); } /** * Get the MULT token * @param pc * @param eq * @return MULT token */ public static String getMultToken(PlayerCharacter pc, Equipment eq) { CDOMSingleRef<WeaponProf> ref = eq.get(ObjectKey.WEAPON_PROF); String profName; if (ref == null) { profName = ""; } else { profName = ref.resolvesTo().getKeyName(); } StringBuffer sb = new StringBuffer(); boolean isDouble = (eq.isDouble() && (eq.getLocation() == Equipment.EQUIPPED_TWO_HANDS)); int mult = (int) pc.getTotalBonusTo("WEAPONPROF=" + profName, "CRITMULTADD") + getWeaponProfTypeBonuses(pc, eq, "CRITMULTADD", WPTYPEBONUS_PC); int critMult = eq.getCritMultiplier(); if (critMult <= 0) { sb.append(mult); } else { sb.append(critMult + mult); } int altCrit = eq.getAltCritMultiplier(); if (isDouble && (altCrit > 0)) { sb.append("/").append(altCrit + mult); } return sb.toString(); } /** * Get the range list token * @param eq * @param range * @param aPC * @return range list token */ public static String getRangeListToken(Equipment eq, int range, PlayerCharacter aPC) { List<String> rangeList = getRangeList(eq, true, aPC); if (range < rangeList.size()) { return Globals.getGameModeUnitSet().displayDistanceInUnitSet( Integer.parseInt(rangeList.get(range))) + Globals.getGameModeUnitSet().getDistanceUnit(); } return ""; } /** * Get the range token * @param eq * @param pc * @param units * @return range token */ public static String getRangeToken(Equipment eq, PlayerCharacter pc, boolean units) { StringBuffer sb = new StringBuffer(); sb.append(Globals.getGameModeUnitSet().displayDistanceInUnitSet( eq.getRange(pc).intValue())); if (units) { sb.append(Globals.getGameModeUnitSet().getDistanceUnit()); } return sb.toString(); } /** * Get the size mod token * @param pc * @return the size mod token */ public static int getSizeModToken(PlayerCharacter pc) { return (int) pc.getSizeAdjustmentBonusTo("TOHIT", "TOHIT"); } /** * Get the category token * @param eq * @return category token */ public static String getCategoryToken(Equipment eq) { StringBuffer sb = new StringBuffer(); sb.append(weaponCategories(eq)); sb.append("-"); if (eq.isNatural()) { sb.append("Natural"); } // If we're going to add another type then seperate with a ',' // and set non standard to false if (appendSeperator(eq)) { sb.append(","); } // Check if Both or Melee or Ranged if (eq.isType("Both")) { if (eq.isMelee()) { sb.append("Both (Melee)"); } else if (eq.isRanged()) { sb.append("Both (Ranged)"); } } else if (eq.isMelee()) { sb.append("Melee"); } else if (eq.isRanged()) { sb.append("Ranged"); } if (isNonStandard(eq)) { sb.append("Non-Standard"); } return sb.toString(); } /** * Get the type token * @param eq * @return type token */ public static String getTypeToken(Equipment eq) { String types = weaponTypes(eq, true); if (eq.isDouble()) { types += ('/' + weaponTypes(eq, false)); } return types; } /** * Get hand token * @param eq * @return hand token */ public static String getHandToken(Equipment eq) { String location = Equipment.getLocationName(eq.getLocation()); return location.replaceAll(".*\\(", "").replaceAll("\\(.*", "") .replaceAll("\\).*", ""); } /** * Get Magic damage token * @param pc * @param eq * @return Magic damage token */ public static int getMagicDamageToken(PlayerCharacter pc, Equipment eq) { CDOMSingleRef<WeaponProf> ref = eq.get(ObjectKey.WEAPON_PROF); String profName; if (ref == null) { profName = ""; } else { profName = ref.resolvesTo().getKeyName(); } int magicdamage = eq.getBonusToDamage(pc, true) + (int) eq.bonusTo("WEAPONPROF=" + profName, "DAMAGE", pc, pc) + getWeaponProfTypeBonuses(pc, eq, "DAMAGE", WPTYPEBONUS_EQ); return magicdamage; } /** * Get the magic to hit token * @param pc * @param eq * @return magic to hit token */ public static int getMagicHitToken(PlayerCharacter pc, Equipment eq) { CDOMSingleRef<WeaponProf> ref = eq.get(ObjectKey.WEAPON_PROF); String profName; if (ref == null) { profName = ""; } else { profName = ref.resolvesTo().getKeyName(); } int magichit = eq.getBonusToHit(pc, true) + (int) eq.bonusTo("WEAPONPROF=" + profName, "TOHIT", pc, pc) + getWeaponProfTypeBonuses(pc, eq, "TOHIT", WPTYPEBONUS_EQ); return magichit; } /** * Get the misc token * @param pc * @param eq * @return misc token */ public static int getMiscToken(PlayerCharacter pc, Equipment eq) { CDOMSingleRef<WeaponProf> ref = eq.get(ObjectKey.WEAPON_PROF); String profName; if (ref == null) { profName = ""; } else { profName = ref.resolvesTo().getKeyName(); } int miscBonus = ((int) pc.getTotalBonusTo("WEAPONPROF=" + profName, "TOHIT") + getWeaponProfTypeBonuses(pc, eq, "TOHIT", WPTYPEBONUS_PC)) - (int) pc.getStatBonusTo("TOHIT", "TYPE.MELEE") - (int) pc.getSizeAdjustmentBonusTo("TOHIT", "TOHIT"); return miscBonus; } /** * Get the feat damage token * @param pc * @param eq * @return feat damage token */ public static int getFeatDamageToken(PlayerCharacter pc, Equipment eq) { CDOMSingleRef<WeaponProf> ref = eq.get(ObjectKey.WEAPON_PROF); String profName; if (ref == null) { profName = ""; } else { profName = ref.resolvesTo().getKeyName(); } int featBonus = (int) pc.getFeatBonusTo("WEAPON", "DAMAGE") - (int) pc.getFeatBonusTo("WEAPON", "DAMAGE-SHORTRANGE") + (int) pc.getFeatBonusTo("WEAPONPROF=" + profName, "DAMAGE") + getWeaponProfTypeBonuses(pc, eq, "DAMAGE", WPTYPEBONUS_FEAT); return featBonus; } /** * Get feat to hit token * @param pc * @param eq * @return Get feat to hit token */ public static int getFeatHitToken(PlayerCharacter pc, Equipment eq) { CDOMSingleRef<WeaponProf> ref = eq.get(ObjectKey.WEAPON_PROF); String profName; if (ref == null) { profName = ""; } else { profName = ref.resolvesTo().getKeyName(); } int featBonus = (int) pc.getFeatBonusTo("WEAPON", "TOHIT") + (int) pc.getFeatBonusTo("WEAPONPROF=" + profName, "TOHIT") + getWeaponProfTypeBonuses(pc, eq, "TOHIT", WPTYPEBONUS_FEAT); return featBonus; } /** * Get the template damage token * @param pc * @param eq * @return template damage token */ public static int getTemplateDamageToken(PlayerCharacter pc, Equipment eq) { CDOMSingleRef<WeaponProf> ref = eq.get(ObjectKey.WEAPON_PROF); String profName; if (ref == null) { profName = ""; } else { profName = ref.resolvesTo().getKeyName(); } int templateBonus = (int) pc.getTemplateBonusTo("WEAPON", "DAMAGE") + (int) pc.getTemplateBonusTo("WEAPONPROF=" + profName, "DAMAGE") + getWeaponProfTypeBonuses(pc, eq, "DAMAGE", WPTYPEBONUS_TEMPLATE); return templateBonus; } /** * Get the template to hit token * @param pc * @param eq * @return to hit token */ public static int getTemplateHitToken(PlayerCharacter pc, Equipment eq) { CDOMSingleRef<WeaponProf> ref = eq.get(ObjectKey.WEAPON_PROF); String profName; if (ref == null) { profName = ""; } else { profName = ref.resolvesTo().getKeyName(); } int templateBonus = (int) pc.getTemplateBonusTo("WEAPON", "TOHIT") + (int) pc.getTemplateBonusTo("WEAPONPROF=" + profName, "TOHIT") + getWeaponProfTypeBonuses(pc, eq, "TOHIT", WPTYPEBONUS_TEMPLATE); return templateBonus; } /** * Get the size token * @param eq * @return size token */ public static String getSizeToken(Equipment eq) { return eq.getSize(); } /** * Get the SPROP token * @param pc * @param eq * @return SPROP token */ public static String getSpropToken(PlayerCharacter pc, Equipment eq) { return getSpropToken(pc, eq, -1, -1); } /** * Get SPROP token * @param pc * @param eq * @param content * @param ammo * @return SPROP token */ public static String getSpropToken(PlayerCharacter pc, Equipment eq, int content, int ammo) { String sprop = eq.getSpecialProperties(pc); //Ammunition & Contents Modifier if (content > -1) { sprop = Constants.EMPTY_STRING; if ((content < eq.getContainedEquipmentCount()) && !Constants.EMPTY_STRING.equals(eq.getContainedEquipment( content).getSpecialProperties(pc))) { sprop = eq.getContainedEquipment(content).getSpecialProperties( pc); } } int ammoCount = 0; Equipment anEquip = null; if (ammo > -1) { final String containerCapacity = eq.getContainerCapacityString(); for (Equipment equip : pc.getEquipmentListInOutputOrder()) { sprop = Constants.EMPTY_STRING; for (String type : equip.typeList()) { if (containerCapacity.indexOf(type) >= 0) { ++ammoCount; anEquip = equip; break; } } if (ammoCount == (ammo + 1)) { break; } } } if ((anEquip != null) && (ammoCount > 0) && !Constants.EMPTY_STRING.equals(anEquip.getSpecialProperties(pc))) { sprop = anEquip.getSpecialProperties(pc); } if (sprop.startsWith(", ")) { sprop = sprop.substring(2); } return sprop; } /** * Get reach token * Formula is as follows: * REACH:(RACEREACH+(max(0,EQUIPREACH-5)))*EQUIPREACHMULT * @param pc the player * @param eq the equipment * @return reach token */ public static int getReachToken(PlayerCharacter pc, Equipment eq) { return eq.getVariableValue( SettingsHandler.getGame().getWeaponReachFormula(), "", pc) .intValue(); } /** * Get weight in set token * @param pc * @param eq * @return weight in set token */ public static String getWTToken(PlayerCharacter pc, Equipment eq) { return Globals.getGameModeUnitSet().displayWeightInUnitSet( eq.getWeight(pc).doubleValue()); } /** * Get rate of fire token * @param eq * @return rate of fire toke */ public static String getRateOfFireToken(Equipment eq) { String rof = eq.get(StringKey.RATE_OF_FIRE); return rof == null ? "" : rof; } /** * Get the number of attacks token * @param pc * @param eq * @return number of attacks token */ public static int getNumAttacksToken(PlayerCharacter pc, Equipment eq) { String melee = getMeleeAttackString(pc); String unarmed = getUnarmedAttackString(pc); String ranged = getRangedAttackString(pc); String weaponString = melee; if (eq.isRanged()) { weaponString = ranged; } if (eq.isMonk()) { if (unarmed.length() > melee.length()) { weaponString = unarmed; } else if ((unarmed.length() == melee.length()) && !melee.equals(unarmed)) { StringTokenizer mTok = new StringTokenizer(melee, "+/", false); StringTokenizer uTok = new StringTokenizer(unarmed, "+/", false); String msString = mTok.nextToken(); String usString = uTok.nextToken(); if (Integer.parseInt(usString) >= Integer.parseInt(msString)) { weaponString = unarmed; } } } StringTokenizer bTok = new StringTokenizer(weaponString, "/"); int extra_attacks = (int) eq.bonusTo(pc, "WEAPON", "ATTACKS", true); return (bTok.countTokens() + extra_attacks); } /** * Get critical token * @param pc * @param eq * @return critical token */ public static String getCritToken(PlayerCharacter pc, Equipment eq) { StringBuffer sb = new StringBuffer(); boolean isDouble = (eq.isDouble() && (eq.getLocation() == Equipment.EQUIPPED_TWO_HANDS)); int rawCritRange = eq.getRawCritRange(true); // see if the weapon has any crit range if (rawCritRange == 0) { // no crit range! return "none"; } CDOMSingleRef<WeaponProf> ref = eq.get(ObjectKey.WEAPON_PROF); String profName; if (ref == null) { profName = ""; } else { profName = ref.resolvesTo().getKeyName(); } final List<BonusObj> bonuses = new ArrayList<BonusObj>(); bonuses.addAll(BonusUtilities.getBonusFromList(pc.getActiveBonusList(), "WEAPONPROF=" + profName, "CRITRANGEDOUBLE")); int dbl = (int) pc.getTotalBonusTo("WEAPONPROF=" + profName, "CRITRANGEDOUBLE") + getWeaponProfTypeBonuses(pc, eq, "CRITRANGEDOUBLE", WPTYPEBONUS_PC); int iAdd = (int) pc.getTotalBonusTo("WEAPONPROF=" + profName, "CRITRANGEADD") + getWeaponProfTypeBonuses(pc, eq, "CRITRANGEADD", WPTYPEBONUS_PC); int eqDbl = dbl + (int) eq.bonusTo(pc, "EQMWEAPON", "CRITRANGEDOUBLE", true); int critrange = eq.getRawCritRange(true) * (eqDbl + 1); critrange = 21 - (critrange + iAdd + (int) eq.bonusTo(pc, "EQMWEAPON", "CRITRANGEADD", true)); sb.append(critrange + ""); if (critrange < 20) { sb.append("-20"); } if (isDouble && (pc.getCritRange(eq, false) > 0)) { eqDbl = dbl + (int) eq.bonusTo(pc, "EQMWEAPON", "CRITRANGEDOUBLE", false); int altCritRange = eq.getRawCritRange(false) * (eqDbl + 1); altCritRange = 21 - (altCritRange + iAdd + (int) eq.bonusTo(pc, "EQMWEAPON", "CRITRANGEADD", false)); if (altCritRange != critrange) { sb.append("/" + altCritRange); if (altCritRange < 20) { sb.append("-20"); } } } return sb.toString(); } /** * Get damage token * @param pc * @param eq * @param bonusOnly * @param base * @return damage token */ public static String getDamageToken(PlayerCharacter pc, Equipment eq, boolean bonusOnly, boolean base) { return getDamageToken(pc, eq, -1, -1, -1, bonusOnly, base); } /** * Get damage token * @param pc * @param eq * @param range * @param content * @param ammo * @param bonusOnly * @param base * @return damage token */ public static String getDamageToken(PlayerCharacter pc, Equipment eq, int range, int content, int ammo, boolean bonusOnly, boolean base) { boolean isDouble = (eq.isDouble() && (eq.getLocation() == Equipment.EQUIPPED_TWO_HANDS)); boolean isDoubleSplit = (eq.isType("Head1") || eq.isType("Head2")); int damageMode = DAMAGEMODE_NORMAL; int hands = 1; if (eq.isNatural() && (eq.getLocation() == Equipment.EQUIPPED_SECONDARY)) { damageMode = DAMAGEMODE_OFFHAND; hands = 0; } else if (eq.isUnarmed()) { damageMode = DAMAGEMODE_BASIC; } else if (isDouble && !isDoubleSplit) { damageMode = DAMAGEMODE_DOUBLE; hands = 1; } else if ((isDoubleSplit) && (eq.isWeaponTwoHanded(pc))) { damageMode = DAMAGEMODE_TWOHANDS; hands = 2; } else if (pc.isSecondaryWeapon(eq)) { damageMode = DAMAGEMODE_OFFHAND; hands = 0; } else if (pc.isPrimaryWeapon(eq)) { if (eq.getLocation() == Equipment.EQUIPPED_BOTH) { damageMode = DAMAGEMODE_TWOHANDS; hands = 2; } else { damageMode = DAMAGEMODE_BASIC; } } else { // Not wielded, probably just carried if (eq.isWeaponTwoHanded(pc)) { damageMode = DAMAGEMODE_TWOHANDS; hands = 2; } else { damageMode = DAMAGEMODE_BASIC; } } return getDamage(pc, eq, range, content, ammo, bonusOnly, hands, damageMode, base); } /** * Get basic damage token * @param pc * @param eq * @param bonusOnly * @return basic damage token */ public static String getBasicDamageToken(PlayerCharacter pc, Equipment eq, boolean bonusOnly) { return getBasicDamageToken(pc, eq, -1, -1, -1, bonusOnly); } /** * Get basic damage token * @param pc * @param eq * @param range * @param content * @param ammo * @param bonusOnly * @return basic damage token */ public static String getBasicDamageToken(PlayerCharacter pc, Equipment eq, int range, int content, int ammo, boolean bonusOnly) { int damageMode = DAMAGEMODE_BASIC; int hands = 1; return getDamage(pc, eq, range, content, ammo, bonusOnly, hands, damageMode, false); } /** * Get two handed damage token * @param pc * @param eq * @param bonusOnly * @return two handed damage token */ public static String getTHDamageToken(PlayerCharacter pc, Equipment eq, boolean bonusOnly) { return getTHDamageToken(pc, eq, -1, -1, -1, bonusOnly); } /** * Get two handed damage token * @param pc * @param eq * @param range * @param content * @param ammo * @param bonusOnly * @return two handed damage token */ public static String getTHDamageToken(PlayerCharacter pc, Equipment eq, int range, int content, int ammo, boolean bonusOnly) { int damageMode = DAMAGEMODE_TWOHANDS; int hands = 2; return getDamage(pc, eq, range, content, ammo, bonusOnly, hands, damageMode, false); } /** * Get Off hand damage token * @param pc * @param eq * @param bonusOnly * @return Off hand damage token */ public static String getOHDamageToken(PlayerCharacter pc, Equipment eq, boolean bonusOnly) { return getOHDamageToken(pc, eq, -1, -1, -1, bonusOnly); } /** * Get Off hand damage token * @param pc * @param eq * @param range * @param content * @param ammo * @param bonusOnly * @return Off hand damage token */ public static String getOHDamageToken(PlayerCharacter pc, Equipment eq, int range, int content, int ammo, boolean bonusOnly) { int damageMode = DAMAGEMODE_OFFHAND; int hands = 0; return getDamage(pc, eq, range, content, ammo, bonusOnly, hands, damageMode, false); } /** * Get total hit token * @param pc * @param eq * @return total hit token */ public static String getTotalHitToken(PlayerCharacter pc, Equipment eq) { return getTotalHitToken(pc, eq, -1, -1, -1, -1); } /** * Get total hit token * @param pc * @param eq * @param range * @param content * @param ammo * @param attackNum * @return total hit token */ public static String getTotalHitToken(PlayerCharacter pc, Equipment eq, int range, int content, int ammo, int attackNum) { boolean isDouble = (eq.isDouble() && (eq.getLocation() == Equipment.EQUIPPED_TWO_HANDS)); boolean isDoubleSplit = (eq.isType("Head1") || eq.isType("Head2")); int hitModeHands = 1; int hitMode = HITMODE_TOTALHIT; // First do unarmed. if (eq.isUnarmed()) { hitMode = HITMODE_BASEHIT; } // next do Double weapons else if (isDouble && !isDoubleSplit) { hitMode = HITMODE_TWOHIT; } else if (!isDouble && isDoubleSplit) { hitMode = HITMODE_THHIT; hitModeHands = 2; } // Both Primary and Secondary weapons else if (!pc.getPrimaryWeapons().isEmpty() && !pc.getSecondaryWeapons().isEmpty()) { // eq is Primary if (pc.isPrimaryWeapon(eq)) { Equipment sEq = pc.getSecondaryWeapons().get(0); if (sEq == null) { // Hmm, weird // default to off-hand light hitMode = HITMODE_TWPHITL; } else if (sEq.isWeaponLightForPC(pc)) { // offhand light hitMode = HITMODE_TWPHITL; } else { // offhand heavy hitMode = HITMODE_TWPHITH; } } // eq is Secondary else if (pc.isSecondaryWeapon(eq)) { if (eq.isWeaponLightForPC(pc)) { // offhand light hitMode = HITMODE_TWFOHL; } else { // offhand heavy hitMode = HITMODE_TWFOHH; } } } // Just a single off-hand weapon else if (pc.isSecondaryWeapon(eq) && pc.getPrimaryWeapons().isEmpty()) { hitMode = HITMODE_OHHIT; } // Just a single primary weapon else if (pc.isPrimaryWeapon(eq) && pc.getSecondaryWeapons().isEmpty()) { if (eq.getLocation() == Equipment.EQUIPPED_BOTH) { // both hands hitMode = HITMODE_THHIT; hitModeHands = 2; } else { // single hand hitMode = HITMODE_BASEHIT; } } else { // Not double or single // Not primary or Secondary // probably just carried if (eq.isWeaponTwoHanded(pc)) { // Two Handed weapon hitMode = HITMODE_THHIT; hitModeHands = 2; } else { // one handed weapon hitMode = HITMODE_BASEHIT; } } return getToHit(pc, eq, range, content, ammo, hitModeHands, hitMode, attackNum, true); } /** * Get base hit token * @param pc * @param eq * @return base hit token */ public static String getBaseHitToken(PlayerCharacter pc, Equipment eq) { return getBaseHitToken(pc, eq, -1, -1, -1, -1); } /** * Get base hit token * @param pc * @param eq * @param range * @param content * @param ammo * @param attackNum * @return base hit token */ public static String getBaseHitToken(PlayerCharacter pc, Equipment eq, int range, int content, int ammo, int attackNum) { int hitModeHands = 1; int hitMode = HITMODE_BASEHIT; return getToHit(pc, eq, range, content, ammo, hitModeHands, hitMode, attackNum, false); } /** * Get two weapon heavy off hand token * @param pc * @param eq * @return two weapon heavy off hand token */ public static String getTwpHitHToken(PlayerCharacter pc, Equipment eq) { return getTwpHitHToken(pc, eq, -1, -1, -1, -1); } /** * Get two weapon heavy off hand token * @param pc * @param eq * @param range * @param content * @param ammo * @param attackNum * @return two weapon heavy off hand token */ public static String getTwpHitHToken(PlayerCharacter pc, Equipment eq, int range, int content, int ammo, int attackNum) { int hitModeHands = 1; int hitMode = HITMODE_TWPHITH; return getToHit(pc, eq, range, content, ammo, hitModeHands, hitMode, attackNum, false); } /** * Get two weapon light off hand token * @param pc * @param eq * @return two weapon light off hand token */ public static String getTwpHitLToken(PlayerCharacter pc, Equipment eq) { return getTwpHitLToken(pc, eq, -1, -1, -1, -1); } /** * Get two weapon light off hand token * @param pc * @param eq * @param range * @param content * @param ammo * @param attackNum * @return two weapon light off hand token */ public static String getTwpHitLToken(PlayerCharacter pc, Equipment eq, int range, int content, int ammo, int attackNum) { int hitModeHands = 1; int hitMode = HITMODE_TWPHITL; return getToHit(pc, eq, range, content, ammo, hitModeHands, hitMode, attackNum, false); } /** * Get two hit token * @param pc * @param eq * @return two hit token */ public static String getTwoHitToken(PlayerCharacter pc, Equipment eq) { return getTwoHitToken(pc, eq, -1, -1, -1, -1); } /** * Get two hit token * @param pc * @param eq * @param range * @param content * @param ammo * @param attackNum * @return two hit token */ public static String getTwoHitToken(PlayerCharacter pc, Equipment eq, int range, int content, int ammo, int attackNum) { int hitModeHands = 1; int hitMode = HITMODE_TWOHIT; return getToHit(pc, eq, range, content, ammo, hitModeHands, hitMode, attackNum, false); } /** * Get Off Hand Hit Token * @param pc * @param eq * @return Off Hand Hit Token */ public static String getOHHitToken(PlayerCharacter pc, Equipment eq) { return getOHHitToken(pc, eq, -1, -1, -1, -1); } /** * Get Off Hand Hit Token * @param pc * @param eq * @param range * @param content * @param ammo * @param attackNum * @return Off Hand Hit Toke */ public static String getOHHitToken(PlayerCharacter pc, Equipment eq, int range, int content, int ammo, int attackNum) { int hitModeHands = 1; int hitMode = HITMODE_OHHIT; return getToHit(pc, eq, range, content, ammo, hitModeHands, hitMode, attackNum, false); } /** * Get the TH Hit Token * @param pc * @param eq * @return the TH Hit Token */ public static String getTHHitToken(PlayerCharacter pc, Equipment eq) { return getTHHitToken(pc, eq, -1, -1, -1, -1); } /** * Get the TH Hit Token * @param pc * @param eq * @param range * @param content * @param ammo * @param attackNum * @return the TH Hit Token */ public static String getTHHitToken(PlayerCharacter pc, Equipment eq, int range, int content, int ammo, int attackNum) { int hitModeHands = 2; int hitMode = HITMODE_THHIT; return getToHit(pc, eq, range, content, ammo, hitModeHands, hitMode, attackNum, false); } private static String getToHit(PlayerCharacter pc, Equipment eq, int range, int content, int ammo, int hands, int hitMode, int attackNum, boolean totalHit) { boolean isDouble = (eq.isDouble() && (eq.getLocation() == Equipment.EQUIPPED_TWO_HANDS)); boolean isDoubleSplit = (eq.isType("Head1") || eq.isType("Head2")); // If it's a two handed weapon, but is not // wielded as two handed, just punt now! if (eq.isMelee() && (eq.isWeaponTwoHanded(pc))) { if ((!isDouble && !isDoubleSplit && (hitMode != HITMODE_THHIT)) || (isDoubleSplit && (hitMode == HITMODE_BASEHIT || hitMode == HITMODE_OHHIT || hitMode == HITMODE_TWPHITH))) { return SettingsHandler.getInvalidToHitText(); } } if (eq.isMelee() && eq.isWeaponOutsizedForPC(pc) && !eq.isNatural()) { return SettingsHandler.getInvalidToHitText(); } int weaponBaseBonus = (int) eq.bonusTo(pc, "WEAPON", "WEAPONBAB", true); CDOMSingleRef<WeaponProf> ref = eq.get(ObjectKey.WEAPON_PROF); String profKey; if (ref == null) { profKey = ""; } else { profKey = ref.resolvesTo().getKeyName(); } weaponBaseBonus += (int) pc.getTotalBonusTo("WEAPONPROF=" + profKey, "WEAPONBAB"); weaponBaseBonus += getWeaponProfTypeBonuses(pc, eq, "WEAPONBAB", WPTYPEBONUS_PC); // The Melee, Ranged and Unarmed attack sequence String melee = getMeleeAttackString(pc, 0, weaponBaseBonus); String ranged = getRangedAttackString(pc, 0, weaponBaseBonus); String unarmed = getUnarmedAttackString(pc, 0, weaponBaseBonus); // Must leave this for 3.0 compatibility // 3.0 Monk uses special attack progression if (eq.isMonk()) { if (unarmed.length() > melee.length()) { melee = unarmed; } else if ((unarmed.length() == melee.length()) && !melee.equals(unarmed)) { StringTokenizer mTok = new StringTokenizer(melee, "+/", false); StringTokenizer m1Tok = new StringTokenizer(melee, "+/", false); String msString = mTok.nextToken(); String m1sString = m1Tok.nextToken(); if (Integer.parseInt(m1sString) >= Integer.parseInt(msString)) { melee = unarmed; } } } // // Now do all the calculations // int baseBonus = 0; int secondaryBonus = 0; int primaryBonus = 0; // Natural weapons are different if (eq.isNatural()) { if (eq.getLocation() == Equipment.EQUIPPED_PRIMARY) { /* Primary Natural Weapons have no bonus or penalty * associated with secondary weapons/attacks */ baseBonus = 0; } else if (eq.getLocation() == Equipment.EQUIPPED_SECONDARY) { /* all secondary natural weapons attack at -5 */ baseBonus = -5; /* Unless the creature has bonuses to improve * secondary attacks, such as MultiAttack */ baseBonus += pc.getTotalBonusTo("COMBAT", "TOHIT-SECONDARY"); } } else { if ((hitMode == HITMODE_TOTALHIT && eq.isRanged()) || hitMode == HITMODE_BASEHIT || hitMode == HITMODE_THHIT) { baseBonus = 0; } else if (hitMode == HITMODE_TWPHITH || hitMode == HITMODE_TWPHITL) { // TWF Primary hand baseBonus = -6; } else if (hitMode == HITMODE_OHHIT) { baseBonus = -4; } else { // TWF off-hand baseBonus = -10; } // TWF with off hand light gets a bonus if ((hitMode == HITMODE_TWPHITL) || (hitMode == HITMODE_TWFOHL)) { baseBonus += pc.getOffHandLightBonus(); } if ((hitMode == HITMODE_TWOHIT) && (isDouble || isDoubleSplit || eq.isWeaponLightForPC(pc))) { baseBonus += pc.getOffHandLightBonus(); } if ((hitMode == HITMODE_TWOHIT) || (hitMode == HITMODE_OHHIT) || (hitMode == HITMODE_TWFOHL) || (hitMode == HITMODE_TWFOHH)) { secondaryBonus = (int) pc.getTotalBonusTo("COMBAT", "TOHIT-SECONDARY"); if (eq.isRanged()) { secondaryBonus -= (int) pc.getBonusDueToType("COMBAT", "TOHIT-SECONDARY", "NOTRANGED"); } if (hitMode == HITMODE_OHHIT) { // If only using one weapon, Two-weapon Fighting Bonus does not apply // If you have TWF, you have both TOHIT-P and TOHIT-S, so remove TOHIT-P // TODO: Rework on this code and/or on the lst, because it "sounds" wrong // Felipe Diniz - 12/Feb/2003 secondaryBonus -= (int) pc.getTotalBonusTo("COMBAT", "TOHIT-PRIMARY"); } } if (((hitMode == HITMODE_TWPHITH) || (hitMode == HITMODE_TWPHITL))) { primaryBonus = (int) pc.getTotalBonusTo("COMBAT", "TOHIT-PRIMARY"); if (eq.isRanged()) { primaryBonus -= (int) pc.getBonusDueToType("COMBAT", "TOHIT-PRIMARY", "NOTRANGED"); } } } /* If the character normally can't wield this weapon 1-handed, but for some reason they can (e.g. Monkey Grip) then check for TOHIT modifiers */ if (eq.getLocation() == Equipment.EQUIPPED_PRIMARY || eq.getLocation() == Equipment.EQUIPPED_SECONDARY || eq.getLocation() == Equipment.EQUIPPED_TWO_HANDS) { // TODO Fix this // if (eq.isWeaponOneHanded(pc, wp, false) != eq.isWeaponOneHanded(pc, wp, true)) // { // baseBonus += (int) pc.getTotalBonusTo("WEAPONPROF=" + profName, "TOHITOVERSIZE"); // baseBonus += getWeaponProfTypeBonuses(pc, eq, "TOHITOVERSIZE", WPTYPEBONUS_PC); // } } if (hitMode == HITMODE_TWPHITH || hitMode == HITMODE_TWPHITL) { baseBonus += primaryBonus; } if (hitMode == HITMODE_TWOHIT || hitMode == HITMODE_OHHIT || hitMode == HITMODE_TWFOHL || hitMode == HITMODE_TWFOHH) { baseBonus += secondaryBonus; } /* An equipped buckler gives an additional -1 penalty to weapons used off hand or a weapon used two handed. */ /******************************************** * This is now all done via BONUS:COMBAT|TOHIT|-1|PREMULT:1,[PREEQUIPBOTH:1,TYPE=Melee],[PREEQUIPSECONDARY:1,TYPE=Melee] on the item(s) * Byngl - Nov 20, 2005 if (eq.isMelee() && (hitMode == HITMODE_THHIT || hitMode == HITMODE_TWOHIT || hitMode == HITMODE_OHHIT)) { for (Iterator e = pc.getEquipmentOfType("buckler", 1).iterator(); e.hasNext();) { baseBonus--; break; } } */ // Get BONUS:COMBAT|TOHIT.abc|x // Where abc: Ranged, Melee, Slashing, etc for (String type : eq.typeList()) { // Finesseable is a special case that // is Handled elsewhere if (type.equalsIgnoreCase("Finesseable")) { continue; } //Prevents weapon from getting both melee & ranged bonuses if ((range > -1 && type.equals("MELEE")) || (range == -1 && eq.isMelee() && (type.equals("THROWN") || type .equals("RANGED")))) { continue; } baseBonus += (int) pc.getTotalBonusTo("TOHIT", "TYPE." + type); baseBonus += (int) pc.getTotalBonusTo("COMBAT", "TOHIT." + type); } if (range == -1 && eq.isMelee() && eq.isFinessable(pc)) { baseBonus += (int) pc.getTotalBonusTo("COMBAT", "TOHIT.Finesseable"); } // 3.0 Syntax // This fixes Weapon Finesse for thrown weapons // BONUS:WEAPONPROF=abc|TOHIT|DEX|TYPE.NotRanged // // Dagger yields following: // WEAPONPROF=abc.TOHIT:NOTRANGED // if ((ref != null) && eq.isRanged()) { baseBonus -= (int) pc.getBonusDueToType("WEAPONPROF=" + profKey, "TOHIT", "NOTRANGED"); baseBonus -= getWeaponProfTypeBonuses(pc, eq, "TOHIT.NOTRANGED", WPTYPEBONUS_PC); } if (!eq.isNatural() && ((ref == null) || !pc.hasWeaponProfKeyed(profKey))) { baseBonus += pc.getNonProficiencyPenalty(); } baseBonus += (int) pc.getTotalBonusTo("WEAPONPROF=" + profKey, "TOHIT"); baseBonus += getWeaponProfTypeBonuses(pc, eq, "TOHIT", WPTYPEBONUS_PC); if (range > -1) { int rangeSize = getRangeList(eq, true, pc).size(); int thisRange = Integer.parseInt(getRangeList(eq, true, pc).get(range)); int shortRange = SettingsHandler.getGame().getShortRangeDistance(); /* range here is an index that represents a number of range * increments, the actual distance is held in this range */ if (range < rangeSize) { // at short range, add SHORTRANGE bonus if (thisRange <= shortRange) { baseBonus += (int) pc.getTotalBonusTo("COMBAT", "TOHIT-SHORTRANGE"); baseBonus += (int) pc.getTotalBonusTo("TOHIT", "SHORTRANGE"); baseBonus += (int) pc.getTotalBonusTo("WEAPONPROF=" + profKey, "TOHIT-SHORTRANGE"); baseBonus += getWeaponProfTypeBonuses(pc, eq, "TOHIT-SHORTRANGE", WPTYPEBONUS_PC); baseBonus += (int) eq.bonusTo(pc, "WEAPON", "TOHIT-SHORTRANGE", true); } // Long Range To-Hit Modifier int defaultRange = Integer.parseInt(eq.getRange(pc).toString()); int rangePenalty = SettingsHandler.getGame().getRangePenalty(); baseBonus += rangePenalty * (int) Math.max(Math .ceil(((float) thisRange / defaultRange)) - 1, 0); } } //Ammunition & Contents Modifier Equipment containedEq = null; if (content > -1) { if (content < eq.getContainedEquipmentCount()) { containedEq = eq.getContainedEquipment(content); baseBonus += containedEq.getBonusToHit(pc, true); } } Equipment ammoUser = getAmmoUser(pc, eq, ammo); if (ammoUser != null) { baseBonus += ammoUser.getBonusToHit(pc, true); } // do NOT include the size bonus/penalty since // it is call in pc.getTotalBonusTo() // include players TOHIT bonuses baseBonus += (int) pc.getTotalBonusTo("TOHIT", "TOHIT"); baseBonus += (int) pc.getTotalBonusTo("COMBAT", "TOHIT"); // subtract Armor and Shield non-proficiency baseBonus += pc.modFromArmorOnWeaponRolls(); // include bonuses from Item itself baseBonus += eq.getBonusToHit(pc, true); // If not using ammo stacking, correct for stacked enhancement bonus if (!Globals.checkRule(RuleConstants.AMMOSTACKSWITHWEAPON)) { baseBonus += calcAmmoEqCorrection("WEAPON.TOHIT.ENHANCEMENT", eq, containedEq, ammoUser); } // BONUS:COMBAT|ATTACKS|# // represent extra attacks at BaB // such as from a weapon of 'Speed' int extra_attacks = (int) eq.bonusTo(pc, "WEAPON", "ATTACKS", true); // or possibly the "Haste" spell cast on PC extra_attacks += (int) pc.getTotalBonusTo("COMBAT", "ATTACKS"); String babProgression = null; /* The range == -1 here deals with the case where the weapon is both ranged and melee (e.g. a dagger). The range == -1 indicates that we want the melee progression */ if (eq.isMelee() && range == -1) { babProgression = melee; } else if (eq.isRanged()) { babProgression = ranged; } else { /* A weapon must either be ranged or melee. If it's not, trap it here */ return "???"; } StringTokenizer bTok = new StringTokenizer(babProgression, "/+"); String attack = Delta.toString(Integer.parseInt(bTok.nextToken())); StringBuffer newAttack = new StringBuffer(); for (int i = extra_attacks; i > 0; i--) { newAttack.append(attack).append("/"); } boolean progress = eq.getSafe(ObjectKey.ATTACKS_PROGRESS); int bonusProgress = (int)eq.bonusTo(pc, "WEAPON", "ATTACKSPROGRESS", true); if (bonusProgress != 0) { progress = bonusProgress > 0; } if (progress) { /* For normal weapons, we need to append the original * attack progression which was derived from the BAB to * the end of the extra attacks */ newAttack.append(babProgression); } else { /* This is for Natural weapons and any other weapon * which has its attack progression turned off. The * attack progression should consist of the full number * of attacks at the maximum tohit i.e. without * appending the attacks from the normal attack * progression */ newAttack.append(attack); } StringTokenizer aTok = new StringTokenizer(newAttack.toString(), "/+"); // When attackNum is > 0, the code is looking for a single attack // from the sequence. This section of code down to // if (buildNewAttackSequence) builds a new aTok which contains // only the single attack we're looking for. int selectAttack = attackNum; String singleAttack = ""; boolean buildNewAttackSequence = false; while (aTok.hasMoreTokens() && (selectAttack >= 0)) { singleAttack = aTok.nextToken(); selectAttack--; buildNewAttackSequence = true; } if (buildNewAttackSequence) { aTok = new StringTokenizer(singleAttack, "/+"); } int secondariesToadd = 1 + (int) pc.getTotalBonusTo("COMBAT", "ATTACKS-SECONDARY"); /* * The data team wishes to keep the old syntax for secondary attacks. * The docs have been updated to reflect this. The new syntax (with * the hyphen, see above) is not used in the repository. This comment * is here so that the old syntax will not be deprecated or removed in * the future. */ secondariesToadd += (int) pc.getTotalBonusTo("COMBAT", "SECONDARYATTACKS"); if (pc.getPrimaryWeapons().isEmpty() && (hitMode == HITMODE_TOTALHIT)) { secondariesToadd = 100; } // Whether to construct a string for secondary attacks. This is only // needed for double weapons because single weapons in the off hand // are processed on their own as secondary weapons. Additionally, We // should only construct a secondary attack string if we are not // looking for a single attack from the sequence (attackNum < 0) boolean doDouble = isDouble && (eq.getLocation() == Equipment.EQUIPPED_TWO_HANDS) && attackNum < 0; // If the weapon is being considered as a secondary weapon, then we // shouldn't add the full attack progression as a secondary weapon only // gets one attack (plus any added by feats, etc. see extra attacks // above) i.e. we may need to break out of the loop while aTok has more // tokens boolean considerEarlyExit = !isDouble && (hitMode == HITMODE_TWOHIT || pc.isSecondaryWeapon(eq)); int toHit = 0; int secondariesAdded = 0; StringBuffer primaryAttack = new StringBuffer(20); StringBuffer secondaryAttack = new StringBuffer(20); StringBuffer totalAttack = new StringBuffer(); while (aTok.hasMoreTokens()) { if (primaryAttack.length() > 0) { primaryAttack.append('/'); } toHit = Integer.parseInt(aTok.nextToken()) + baseBonus; primaryAttack.append(Delta.toString(toHit)); if (doDouble && secondariesAdded < secondariesToadd) { if (secondaryAttack.length() > 0) { secondaryAttack.append('/'); } secondaryAttack.append(Delta.toString(toHit)); } // Just in case we are looping forever if (++secondariesAdded > 100) { break; } if (considerEarlyExit && secondariesAdded >= secondariesToadd) { break; } } totalAttack.append(primaryAttack.toString()); if (secondaryAttack.length() != 0 && (hitMode == HITMODE_TOTALHIT || hitMode == HITMODE_TWOHIT)) { totalAttack.append(";" + secondaryAttack); } return totalAttack.toString(); } /** * Calculate the correction required to cancel out all enhancement bonuses * other than the highest one. This is because in some game modes, the * enhancement bonuses for ammo does not stack with that of the weapon. * Normally the key would be WEAPON.TOHIT.ENHANCEMENT or * WEAPON.DAMAGE.ENHANCEMENT * * @param aKey The bonus to get the correction for. * @param weapon The weapon that is holding the ammo or contents. * @param contents The contents fo the weapon * @param ammo The ammo being used in the weapon. * @return The correction from the total enhancement bonus to the highest one. */ private static int calcAmmoEqCorrection(String aKey, Equipment weapon, Equipment contents, Equipment ammo) { float maxEnhancement = 0; float totalEnhancement; float bonusVal; String bonus; if (weapon == null) { return 0; } bonus = weapon.getBonusMap().get(aKey); if (bonus != null) { maxEnhancement = Float.parseFloat(bonus); } totalEnhancement = maxEnhancement; if (contents != null) { bonus = contents.getBonusMap().get(aKey); if (bonus != null) { bonusVal = Float.parseFloat(bonus); totalEnhancement += bonusVal; if (bonusVal > maxEnhancement) { maxEnhancement = bonusVal; } } } if (ammo != null) { bonus = ammo.getBonusMap().get(aKey); if (bonus != null) { bonusVal = Float.parseFloat(bonus); totalEnhancement += bonusVal; if (bonusVal > maxEnhancement) { maxEnhancement = bonusVal; } } } return (int) (maxEnhancement - totalEnhancement); } private static String getDamage(PlayerCharacter pc, Equipment eq, int range, int content, int ammo, boolean bonusOnly, int hands, int damageMode, boolean base) { boolean isDouble = (eq.isDouble() && (eq.getLocation() == Equipment.EQUIPPED_TWO_HANDS)); boolean isDoubleSplit = (eq.isType("Head1") || eq.isType("Head2")); if (eq.isMelee() && (eq.isWeaponTwoHanded(pc))) { if (!isDouble && !isDoubleSplit && (damageMode != DAMAGEMODE_NORMAL) && (damageMode != DAMAGEMODE_TWOHANDS) && (damageMode != DAMAGEMODE_DOUBLE)) { return SettingsHandler.getInvalidDmgText(); } } if (eq.isMelee() && eq.isWeaponOutsizedForPC(pc) && !eq.isNatural()) { return SettingsHandler.getInvalidDmgText(); } if (eq.isWeaponLightForPC(pc) && (hands == 2)) { // if wielding a 'Light' weapon two handed // treat as if wielding 1 handed for damage bonus hands = 1; } CDOMSingleRef<WeaponProf> ref = eq.get(ObjectKey.WEAPON_PROF); String profName; if (ref == null) { profName = ""; } else { profName = ref.resolvesTo().getKeyName(); } String damString = getEqDamage(pc, eq); int meleeDamageStatBonus = (int) pc.getStatBonusTo("COMBAT", "DAMAGE.MELEE"); // TODO: remove this old syntax meleeDamageStatBonus += (int) pc.getStatBonusTo("DAMAGE", "TYPE.MELEE"); double meleeDamageMult = pc.getTotalBonusTo("COMBAT", "DAMAGEMULT:" + hands); meleeDamageMult += pc.getTotalBonusTo("WEAPONPROF=" + profName, "DAMAGEMULT:" + hands); meleeDamageMult += eq.bonusTo("WEAPON", "DAMAGEMULT:" + hands, pc, pc); int bonus = 0; int weaponProfBonus = 0; int eqbonus = 0; int totalBonus = 0; damString = getMonkUnarmed(pc, eq, damString); if (!base) { int index; for (index = 0; index < damString.length(); ++index) { if ((damString.charAt(index) == '+') || (damString.charAt(index) == '-')) { totalBonus = Delta.decode(damString.substring(index)).intValue(); break; } } eqbonus = getEqBonus(pc, eq, content, ammo); bonus = getGeneralBonus(pc, eq, range, meleeDamageStatBonus, meleeDamageMult); weaponProfBonus = getWeaponProfBonus(pc, eq, range); totalBonus += (bonus + weaponProfBonus + eqbonus); damString = damString.substring(0, index); } StringBuffer sb = new StringBuffer(); if (!"0d0".equalsIgnoreCase(damString)) { if (!bonusOnly) { sb.append(damString); } if ((totalBonus != 0) || bonusOnly) { sb.append(Delta.toString(totalBonus)); } } else { sb.append("0"); } // Handle Double weapons if ((damageMode == DAMAGEMODE_DOUBLE) && (eq.getLocation() == Equipment.EQUIPPED_TWO_HANDS)) { // This is the 'Off-Hand' portion of the double weapon hands = 0; meleeDamageMult = pc.getTotalBonusTo("COMBAT", "DAMAGEMULT:" + hands); meleeDamageMult += pc.getTotalBonusTo("WEAPONPROF=" + profName, "DAMAGEMULT:" + hands); meleeDamageMult += eq.bonusTo("WEAPON", "DAMAGEMULT:" + hands, pc, pc); totalBonus -= eqbonus; /* * eq.getBonusToDamage(false) returns the eq bonus for * the secondary head */ eqbonus = eq.getBonusToDamage(pc, false); if (eq.getAltDamage(pc).length() > 0) { totalBonus = 0; damString = eq.getAltDamage(pc); if (damString.lastIndexOf('-') >= 0) { totalBonus = Integer.parseInt(damString.substring(damString .lastIndexOf('-'))); damString = damString.substring(0, damString.lastIndexOf('-')); } else if (damString.lastIndexOf('+') >= 0) { totalBonus = Integer.parseInt(damString.substring(damString .lastIndexOf('+') + 1)); damString = damString.substring(0, damString.lastIndexOf('+')); } } else { weaponProfBonus = 0; bonus = 0; } if (meleeDamageStatBonus > 0) { // getTotalBonusTo() includes the Stat Bonuses // so have to remove them before we can compute // the hands multiplier bonus -= meleeDamageStatBonus; // Off-hand, OneHanded and TwoHanded wield // have a Stat Bonus damage multiplier bonus += (meleeDamageMult * meleeDamageStatBonus); } totalBonus += bonus + weaponProfBonus + eqbonus; sb.append("/"); if (!"0d0".equalsIgnoreCase(damString)) { if (bonusOnly) { sb.append(damString); } if (totalBonus != 0 || bonusOnly) { sb.append(Delta.toString(totalBonus)); } } else { sb.append("0"); } } return sb.toString(); } private static int getGeneralBonus(PlayerCharacter pc, Equipment eq, int range, int meleeDamageStatBonus, double meleeDamageMult) { int bonus = 0; for (String type : eq.typeList()) { //Makes sure that thrown weapons only get the right bonus at the right time if ((range > -1 && type.equals("MELEE")) || (range == -1 && (type.equals("THROWN") || type .equals("RANGED")))) { continue; } bonus += (int) pc.getTotalBonusTo("COMBAT", "DAMAGE." + type); // TODO: remove this old syntax bonus += (int) pc.getTotalBonusTo("DAMAGE", "TYPE." + type); } if (eq.isFinessable(pc) && !eq.isType("Finesseable")) { bonus += (int) pc.getTotalBonusTo("COMBAT", "DAMAGE.Finesseable"); } if (eq.isMelee() && (meleeDamageStatBonus > 0)) { // getTotalBonusTo() includes the Stat Bonuses // so have to remove them before we can compute // the hands multiplier bonus -= meleeDamageStatBonus; // Off-hand, OneHanded and TwoHanded wield // have a Stat Bonus damage multiplier bonus += (meleeDamageMult * meleeDamageStatBonus); } else if (eq.isThrown()) { // Thrown weapons just get stat bonus // and its already been added in the // getTotalBonusTo(TYPE) above } // If at short range, add SHORTRANGE bonus if (range > -1) { int rangeSize = getRangeList(eq, true, pc).size(); if ((range < rangeSize) && (Integer.parseInt(getRangeList(eq, true, pc).get(range)) <= SettingsHandler .getGame().getShortRangeDistance())) { bonus += (int) eq.bonusTo(pc, "WEAPON", "DAMAGE-SHORTRANGE", true); bonus += (int) pc.getTotalBonusTo("DAMAGE", "SHORTRANGE"); bonus += (int) pc.getTotalBonusTo("COMBAT", "DAMAGE-SHORTRANGE"); } } return bonus; } private static int getWeaponProfBonus(PlayerCharacter pc, Equipment eq, int range) { CDOMSingleRef<WeaponProf> ref = eq.get(ObjectKey.WEAPON_PROF); String profKey; if (ref == null) { profKey = ""; } else { profKey = ref.resolvesTo().getKeyName(); } int weaponProfBonus = (int) pc.getTotalBonusTo("WEAPONPROF=" + profKey, "DAMAGE") + getWeaponProfTypeBonuses(pc, eq, "DAMAGE", WPTYPEBONUS_PC); if (eq.isRanged()) { weaponProfBonus -= ((int) pc.getBonusDueToType("WEAPONPROF=" + profKey.toUpperCase(), "DAMAGE", "NOTRANGED") + getWeaponProfTypeBonuses( pc, eq, "DAMAGE.NOTRANGED", WPTYPEBONUS_PC)); } // If at short range, add SHORTRANGE bonus if (range > -1) { int rangeSize = getRangeList(eq, true, pc).size(); if ((range < rangeSize) && (Integer.parseInt(getRangeList(eq, true, pc).get(range)) <= SettingsHandler .getGame().getShortRangeDistance())) { weaponProfBonus += ((int) pc.getTotalBonusTo("WEAPONPROF=" + profKey, "DAMAGE-SHORTRANGE") + getWeaponProfTypeBonuses(pc, eq, "DAMAGE-SHORTRANGE", WPTYPEBONUS_PC)); } } return weaponProfBonus; } private static int getEqBonus(PlayerCharacter pc, Equipment eq, int content, int ammo) { int eqbonus = eq.getBonusToDamage(pc, true); //Ammunition & Contents Modifier Equipment containedEq = null; if (content > -1) { if (content < eq.getContainedEquipmentCount()) { containedEq = eq.getContainedEquipment(content); eqbonus += containedEq.getBonusToDamage(pc, true); } } Equipment ammoUser = getAmmoUser(pc, eq, ammo); if (ammoUser != null) { eqbonus += ammoUser.getBonusToDamage(pc, true); } // If not using ammo stacking, correct for stacked enhancement bonus if (!Globals.checkRule(RuleConstants.AMMOSTACKSWITHWEAPON)) { eqbonus += calcAmmoEqCorrection("WEAPON.DAMAGE.ENHANCEMENT", eq, containedEq, ammoUser); } return eqbonus; } private static String getMonkUnarmed(PlayerCharacter pc, Equipment eq, String damString) { if (eq.isMonk() && eq.isUnarmed()) { int eqSize = pc.getRace().getSafe(FormulaKey.SIZE).resolve(pc, "") .intValue(); int iMod = pc.sizeInt(); /* This modifies damage (by size) from the default when the race is * not the default size and the character is the default size for * their race */ boolean applySize = (eqSize == iMod); String uDamString = pc.getUnarmedDamageString(false, false, applySize); StringTokenizer bTok = new StringTokenizer(damString, " d+-", false); bTok.nextToken(); String b1String = bTok.nextToken(); StringTokenizer cTok = new StringTokenizer(uDamString, " d+-", false); cTok.nextToken(); String c1String = cTok.nextToken(); if (Integer.parseInt(b1String) < Integer.parseInt(c1String)) { damString = uDamString; } /* * This modifies damage by size when the character is a different size * than the race. It also modifies it by applying any Bonuses to damage * size. */ iMod += (int) pc.getTotalBonusTo("WEAPONPROF=Unarmed Strike", "DAMAGESIZE"); iMod += (int) pc.getTotalBonusTo("COMBAT", "DAMAGESIZE"); /* If not applying the race size modifier, then damString will * represent the damage as if this Character were the default * size. Set eqSize to adjust from damage for the default size, * not the race's actual size. */ if (!applySize) { final SizeAdjustment defAdj = SettingsHandler.getGame().getDefaultSizeAdjustment(); if (defAdj != null) { eqSize = Globals.sizeInt(defAdj.getAbbreviation()); } } damString = Globals.adjustDamage(damString, eqSize, iMod); } return damString; } private static String getEqDamage(PlayerCharacter pc, Equipment eq) { String retString = eq.getDamage(pc); if (pc == null) { return retString; } CDOMSingleRef<WeaponProf> ref = eq.get(ObjectKey.WEAPON_PROF); String profKey; if (ref == null) { profKey = ""; } else { profKey = ref.resolvesTo().getKeyName(); } if (eq.isNatural()) { // int eqSize = Globals.sizeInt(pc.getRace().getSize()); int eqSize = pc.racialSizeInt(); int iMod = pc.sizeInt(); iMod += (int) pc.getTotalBonusTo("WEAPONPROF=" + profKey, "DAMAGESIZE"); iMod += (int) pc.getTotalBonusTo("COMBAT", "DAMAGESIZE"); retString = Globals.adjustDamage(retString, eqSize, iMod); } else { int eqSize = eq.sizeInt(); int iMod = eqSize; iMod += (int) pc.getTotalBonusTo("WEAPONPROF=" + profKey, "DAMAGESIZE"); iMod += (int) pc.getTotalBonusTo("COMBAT", "DAMAGESIZE"); retString = Globals.adjustDamage(retString, eqSize, iMod); } return retString; } private static Equipment getAmmoUser(PlayerCharacter pc, Equipment eq, int ammo) { int ammoCount = 0; if (ammo < 0) { return null; } String containerCapacity = eq.getContainerCapacityString(); for (Equipment equip : pc.getEquipmentListInOutputOrder()) { for (String type : equip.typeList()) { if (containerCapacity.indexOf(type) >= 0) { ++ammoCount; break; } } if (ammoCount == (ammo + 1)) { return equip; } } return null; } private static int getWeaponProfTypeBonuses(PlayerCharacter pc, Equipment eq, String bonusType, int index) { int bonus = 0; boolean hasBoth = (eq.isRanged() && eq.isMelee()); CDOMSingleRef<WeaponProf> ref = eq.get(ObjectKey.WEAPON_PROF); if (ref == null) { return 0; } WeaponProf wp = ref.resolvesTo(); StringTokenizer aTok = new StringTokenizer(wp.getType(), "."); while (aTok.hasMoreTokens()) { String tString = aTok.nextToken(); if (!hasBoth || !"RANGED".equalsIgnoreCase(tString)) { switch (index) { case WPTYPEBONUS_PC: bonus += (int) pc.getTotalBonusTo("WEAPONPROF=TYPE." + tString, bonusType); break; case WPTYPEBONUS_EQ: bonus += (int) eq.bonusTo("WEAPONPROF=TYPE." + tString, bonusType, pc, pc); break; case WPTYPEBONUS_FEAT: bonus += (int) pc.getFeatBonusTo("WEAPONPROF=TYPE." + tString, bonusType); break; case WPTYPEBONUS_TEMPLATE: bonus += (int) pc.getTemplateBonusTo("WEAPONPROF=TYPE." + tString, bonusType); break; default: Logging .errorPrint("In getWeaponProfTypeBonuses there is an unhandled case in a switch (the value is " + index + "."); break; } } } return bonus; } private static String weaponCategories(Equipment eq) { StringBuffer wc = new StringBuffer(10); StringTokenizer aTok = new StringTokenizer(SettingsHandler.getGame() .getWeaponCategories(), "|", false); while (aTok.hasMoreTokens()) { String type = aTok.nextToken(); if (eq.isType(type, true)) { if (wc.length() != 0) { wc.append('/'); } wc.append(type); } } if (wc.length() == 0) { wc.append("Non-Standard"); } return wc.toString(); } private static String weaponTypes(Equipment eq, boolean primary) { StringBuffer wt = new StringBuffer(10); StringTokenizer aTok = new StringTokenizer(SettingsHandler.getGame().getWeaponTypes(), "|", false); while (aTok.countTokens() >= 2) { String type = aTok.nextToken(); String abbrev = aTok.nextToken(); if (eq.isType(type, primary)) { wt.append(abbrev); } } return wt.toString(); } /** * Get the ranged attack string for this <code>pc</code> * * @param pc The character that this ranged attack string is for * @return The ranged attack string affected only by BAB */ private static String getRangedAttackString(PlayerCharacter pc) { return pc.getAttackString(AttackType.RANGED, 0, 0); } /** * Get the ranged attack string for this <code>pc</code>. Use * <code>bonus</code> to affect the size of attacks e.g. +9/+4 with * bonus 2 becomes +11/+6. Use <code>BABbonus</code> to affect the * size and number of attacks e.g. +9/+4 with BABBonus 2 becomes * +11/+6/+1. * * @param pc The character that this ranged attack string is for * @param bonus An increase to be applied to each number in the attack * string. * @param BABBonus A bonus Which also affects the number of attacks in * the returned attackString. * @return The ranged attack string with number and size of attacks * affected by BAB and bonus */ private static String getRangedAttackString(PlayerCharacter pc, int bonus, int BABBonus) { return pc.getAttackString(AttackType.RANGED, bonus, BABBonus); } /** * Get the melee attack string for this <code>pc</code> * * @param pc The character that this melee attack string is for * @return The melee attack string affected only by BAB */ private static String getMeleeAttackString(PlayerCharacter pc) { return pc.getAttackString(AttackType.MELEE, 0, 0); } /** * Get the melee attack string for this <code>pc</code>. Use * <code>bonus</code> to affect the size of attacks e.g. +9/+4 with * bonus 2 becomes +11/+6. Use <code>BABbonus</code> to affect the * size and number of attacks e.g. +9/+4 with BABBonus 2 becomes * +11/+6/+1. * * @param pc The character that this melee attack string is for * @param bonus An increase to be applied to each number in the attack * string. * @param BABBonus A bonus Which also affects the number of attacks in * the returned attackString. * @return The melee attack string with number and size of attacks * affected by BAB and bonus */ private static String getMeleeAttackString(PlayerCharacter pc, int bonus, int BABBonus) { return pc.getAttackString(AttackType.MELEE, bonus, BABBonus); } /** * Get the unarmed attack string for this <code>pc</code> * * @param pc The character that this unarmed attack string is for * @return The unarmed attack string affected only by BAB */ private static String getUnarmedAttackString(PlayerCharacter pc) { return pc.getAttackString(AttackType.UNARMED, 0, 0); } /** * Get the unarmed attack string for this <code>pc</code>. Use * <code>bonus</code> to affect the size of attacks e.g. +9/+4 with * bonus 2 becomes +11/+6. Use <code>BABbonus</code> to affect the * size and number of attacks e.g. +9/+4 with BABBonus 2 becomes * +11/+6/+1. * * @param pc The character that this unarmed attack string is for * @param bonus An increase to be applied to each number in the attack * string. * @param BABBonus A bonus Which also affects the number of attacks in * the returned attackString. * @return The unarmed attack string with number and size of attacks * affected by BAB and bonus */ private static String getUnarmedAttackString(PlayerCharacter pc, int bonus, int BABBonus) { return pc.getAttackString(AttackType.UNARMED, bonus, BABBonus); } /** * If the equipment has a type beyond natural then we need a * seperator * @param eq * @return true if we need a sepearator */ private static boolean appendSeperator(Equipment eq) { if (eq.isType("Natural") && (eq.isType("Both") || eq.isType("Melee") || eq.isType("Ranged"))) { return true; } return false; } /** * If none of the four types are true then it's non standard * @param eq * @return true if non standard */ private static boolean isNonStandard(Equipment eq) { if (eq.isType("Natural") || eq.isType("Both") || eq.isType("Melee") || eq.isType("Ranged")) { return false; } return true; } /** * Gets the range list of the Equipment object, adding the 30' range, if not present and required * * @param addShortRange boolean * @param aPC * @return The range list */ public static List<String> getRangeList(Equipment eq, boolean addShortRange, final PlayerCharacter aPC) { final List<String> aList = new ArrayList<String>(); final int baseRange = eq.getRange(aPC).intValue(); int aRange = baseRange; int maxIncrements = 0; if (eq.isRanged()) { if (eq.isThrown()) { maxIncrements = 5; } else { maxIncrements = 10; } } for (int numIncrements = 0; numIncrements < maxIncrements; ++numIncrements) { if (aRange == SettingsHandler.getGame().getShortRangeDistance()) { addShortRange = false; } if ((aRange > SettingsHandler.getGame().getShortRangeDistance()) && addShortRange) { aList.add(Integer.toString(SettingsHandler.getGame().getShortRangeDistance())); addShortRange = false; } aList.add(Integer.toString(aRange)); aRange += baseRange; } return aList; } }

The table below shows all metrics for WeaponToken.java.

MetricValueDescription
BLOCKS394.00Number of blocks
BLOCK_COMMENT75.00Number of block comment lines
COMMENTS730.00Comment lines
COMMENT_DENSITY 0.54Comment density
COMPARISONS395.00Number of comparison operators
CYCLOMATIC452.00Cyclomatic complexity
DECL_COMMENTS91.00Comments in declarations
DOC_COMMENT530.00Number of javadoc comment lines
ELOC1345.00Effective lines of code
EXEC_COMMENTS88.00Comments in executable code
EXITS207.00Procedure exits
FUNCTIONS80.00Number of function declarations
HALSTEAD_DIFFICULTY125.68Halstead difficulty
HALSTEAD_EFFORT 0.00Halstead effort
INTERFACE_COMPLEXITY392.00Interface complexity
JAVA0001 0.00JAVA0001 Package name does not contain only lower case letters
JAVA0002 1.00JAVA0002 Package name does not begin with a top level domain name or country code
JAVA0003 0.00JAVA0003 Minimize use of on-demand (.*) imports
JAVA0004 0.00JAVA0004 Unnecessary import from java.lang
JAVA0005 0.00JAVA0005 Imports not in specified order
JAVA0006 0.00JAVA0006 Empty finally block
JAVA0007 0.00JAVA0007 Should not declare public field
JAVA0008 0.00JAVA0008 Empty catch block
JAVA0009 0.00JAVA0009 Protected member in final class
JAVA0010 0.00JAVA0010 Non-instantiable class does not contain a non-private static member
JAVA0011 0.00JAVA0011 Abstract class does not contain an abstract method
JAVA0012 0.00JAVA0012 Non-constructor method with same name as declaring class
JAVA0013 0.00JAVA0013 Non-blank final field is not static
JAVA0014 0.00JAVA0014 Class with only static members has non-private constructor
JAVA0015 0.00JAVA0015 Package class contains public nested type
JAVA0016 0.00JAVA0016 Abstract class contains public constructor
JAVA0017 0.00JAVA0017 Class name does not have required form
JAVA0018 0.00JAVA0018 Method name does not have required form
JAVA0019 0.00JAVA0019 Interface name does not have required form
JAVA0020 0.00JAVA0020 Field name does not have required form
JAVA0021 0.00JAVA0021 Interface method name does not have required form
JAVA0022 0.00JAVA0022 Static final field name does not have required form
JAVA0023 0.00JAVA0023 Empty finalize method
JAVA0024 0.00JAVA0024 Empty class
JAVA0025 0.00JAVA0025 Method override is empty
JAVA0026 0.00JAVA0026 Finalize method with parameters
JAVA0029 0.00JAVA0029 Private method not used
JAVA0030 0.00JAVA0030 Private field not used
JAVA0031 0.00JAVA0031 Case statement not properly closed
JAVA0032 0.00JAVA0032 Switch statement missing default
JAVA0033 0.00JAVA0033 default: not last case in switch statement
JAVA0034 0.00JAVA0034 Missing braces in if statement
JAVA0035 0.00JAVA0035 Missing braces in for statement
JAVA0036 0.00JAVA0036 Missing braces in while statement
JAVA0038 0.00JAVA0038 Non-case label in switch statement
JAVA0039 0.00JAVA0039 Break statement with label
JAVA0040 0.00JAVA0040 Switch statement contains N cases (maximum: M)
JAVA0041 0.00JAVA0041 Nested synchronized block
JAVA0042 0.00JAVA0042 Empty synchronized statement
JAVA0043 0.00JAVA0043 Inner class does not use outer class
JAVA0044 0.00JAVA0044 Serializable class with no instance variables
JAVA0045 0.00JAVA0045 Serializable class with only transient fields
JAVA0046 0.00JAVA0046 Name of class not derived from Exception ends with 'Exception'
JAVA0047 0.00JAVA0047 Serializable class derives from invalid base class
JAVA0048 0.00JAVA0048 Name of class derived from Exception does not end with 'Exception'
JAVA0049 0.00JAVA0049 Nested block at depth N (maximum: M)
JAVA0050 0.00JAVA0050 Class derives from java.lang.Error
JAVA0051 0.00JAVA0051 Class derives from java.lang.RuntimeException
JAVA0052 0.00JAVA0052 Class derives from java.lang.Throwable
JAVA0053 0.00JAVA0053 Unused label
JAVA0054 0.00JAVA0054 Inheritance depth N exceeds maximum M
JAVA0055 0.00JAVA0055 Class should be interface
JAVA0056 0.00JAVA0056 Unnecessary abstract modifier for interface or annotation
JAVA0057 0.00JAVA0057 Unnecessary default constructor
JAVA0058 0.00JAVA0058 Constructor calls super()
JAVA0059 0.00JAVA0059 Method override only calls super()
JAVA0061 0.00JAVA0061 Inaccessible member in anonymous class
JAVA0062 0.00JAVA0062 Public class missing public member or protected constructor
JAVA0063 0.00JAVA0063 Identifier name should not contain '$'
JAVA0064 0.00JAVA0064 N variations of identifier name (maximum: M)
JAVA0065 0.00JAVA0065 Unnecessary final modifier for method in final class
JAVA0066 0.00JAVA0066 Unnecessary modifier for interface nested type
JAVA0067 0.00JAVA0067 Array descriptor on identifier name
JAVA0068 0.00JAVA0068 Modifiers not declared in recommended order
JAVA0071 0.00JAVA0071 Strings compared with ==
JAVA0073 0.00JAVA0073 Integer division in floating-point context
JAVA0074 0.00JAVA0074 Use of Object.notify()
JAVA0075 0.00JAVA0075 Method parameter hides field
JAVA007613.00JAVA0076 Use of magic number
JAVA0077 0.00JAVA0077 Private field not used in declaring class
JAVA0078 0.00JAVA0078 Floating point values compared with ==
JAVA0079 0.00JAVA0079 Use of instance to reference static member
JAVA0080 0.00JAVA0080 Import declaration not used
JAVA0081 0.00JAVA0081 Boolean literal in comparison
JAVA0082 0.00JAVA0082 Unnecessary widening cast
JAVA0083 0.00JAVA0083 Unnecessary instanceof test
JAVA0084 0.00JAVA0084 Should use compound assignment operator
JAVA0085 0.00JAVA0085 Use of sun.* class
JAVA0087 0.00JAVA0087 Use of Thread.sleep()
JAVA0089 0.00JAVA0089 Use of restricted package
JAVA0092 0.00JAVA0092 Use of restricted type
JAVA0093 0.00JAVA0093 Redundant assignment
JAVA0094 0.00JAVA0094 Field hides a superclass field
JAVA0095 0.00JAVA0095 Uninitialized private field
JAVA0096 0.00JAVA0096 Field in nested class hides outer field
JAVA0098 0.00JAVA0098 Minimize use of implicit field initializers
JAVA0100 0.00JAVA0100 Class contains N non-final fields (maximum: M)
JAVA0101 0.00JAVA0101 Unnecessary modifier for field in interface
JAVA0102 0.00JAVA0102 Last statement in finalize() not super.finalize()
JAVA0103 0.00JAVA0103 Explicit call to finalize()
JAVA0104 0.00JAVA0104 finalize() only calls super.finalize()
JAVA0105 0.00JAVA0105 Duplicate import declaration
JAVA0106 0.00JAVA0106 Unnecessary import from current package
JAVA0108 1.00JAVA0108 Incorrect javadoc: no @param tag for 'parameter'
JAVA0109 0.00JAVA0109 Incorrect javadoc: no parameter 'parameter'
JAVA0110 2.00JAVA0110 Incorrect javadoc: no @return tag
JAVA0111 0.00JAVA0111 Incorrect javadoc: @return tag for void method
JAVA0112 0.00JAVA0112 Incorrect javadoc: no exception 'exception' in throws
JAVA0113 1.00JAVA0113 Incorrect javadoc: no @author tag
JAVA0114 1.00JAVA0114 Incorrect javadoc: no @version tag
JAVA0115 0.00JAVA0115 Incorrect javadoc: no @throws or @exception tag for 'exception'
JAVA0116 0.00JAVA0116 Missing javadoc: field 'field'
JAVA0117 0.00JAVA0117 Missing javadoc: method 'method'
JAVA0118 0.00JAVA0118 Missing javadoc: type 'type'
JAVA0119 0.00JAVA0119 Control variable changed within body of for loop
JAVA0123 0.00JAVA0123 Use all three components of for loop
JAVA0125 0.00JAVA0125 Continue statement with label
JAVA0126 0.00JAVA0126 Method declares unchecked exception in throws
JAVA0128 0.00JAVA0128 Public constructor in non-public class
JAVA0130 0.00JAVA0130 Non-static method does not use instance fields
JAVA0131 0.00JAVA0131 Compatible method does not override base
JAVA0132 0.00JAVA0132 Method overload with compatible signature
JAVA0133 0.00JAVA0133 Non-synchronized method overrides synchronized method
JAVA0135 0.00JAVA0135 Only one of Object.equals and Object.hashCode defined: missing 'method'
JAVA0136 1.00JAVA0136 N methods defined in class (maximum: M)
JAVA0137 0.00JAVA0137 Non-abstract class missing constructor
JAVA013813.00JAVA0138 N parameters defined for method (maximum: M)
JAVA0139 0.00JAVA0139 Definition of main other than public static void main(java.lang.String[])
JAVA0141 0.00JAVA0141 Unnecessary modifier for method in interface
JAVA0143 0.00JAVA0143 Synchronized method
JAVA0144 1.00JAVA0144 Line exceeds maximum M characters
JAVA01456725.00JAVA0145 Tab character used in source file
JAVA0150 0.00JAVA0150 java.lang.Error (or subclass) thrown
JAVA0153 0.00JAVA0153 Inefficient conversion of integer to string
JAVA0159 0.00JAVA0159 Inefficient conversion of string to integer
JAVA0160 0.00JAVA0160 Method does not throw specified exception
JAVA0161 0.00JAVA0161 Conditional wait() not in loop
JAVA0163 0.00JAVA0163 Empty statement
JAVA0165 0.00JAVA0165 Conflicting return statement in finally block
JAVA0166 0.00JAVA0166 Generic exception caught
JAVA0167 0.00JAVA0167 ThreadDeath not rethrown
JAVA0169 0.00JAVA0169 Unnecessary catch block: exception 'exception'
JAVA0170 0.00JAVA0170 Caught exception not derived from java.lang.Exception
JAVA0171 0.00JAVA0171 Unused local variable
JAVA0173 2.00JAVA0173 Unused method parameter
JAVA0174 0.00JAVA0174 Assigned local variable never used
JAVA0175 0.00JAVA0175 Successive assignment to variable
JAVA0176 0.00JAVA0176 Local variable name does not have required form
JAVA017718.00JAVA0177 Variable declaration missing initializer
JAVA0179 0.00JAVA0179 Local variable hides visible field
JAVA0233 0.00JAVA0233 Definition of serialVersionUID other than 'private static final long serialVersionUID'
JAVA0234 0.00JAVA0234 Class is Serializable but does not define serialVersionUID
JAVA0235 0.00JAVA0235 Class defines serialVersionUID but does not implement Serializable
JAVA0236 0.00JAVA0236 Attempt to clone an object which does not implement Cloneable
JAVA0237 0.00JAVA0237 Class implements Cloneable but does not have public clone method
JAVA0238 0.00JAVA0238 Clone method does not call super.clone()
JAVA0239 0.00JAVA0239 Class declares 'readObject' or 'writeObject' but does not implement Serializable
JAVA0240 0.00JAVA0240 Serializable class which declares readObject or writeObject but not both
JAVA0241 0.00JAVA0241 'readObject' or 'writeObject' should be declared private in Serializable class
JAVA0242 0.00JAVA0242 Transient field in non-Serializable class
JAVA0243 0.00JAVA0243 'readResolve' or 'writeReplace' should be declared private or protected
JAVA0244 0.00JAVA0244 Field or method name in subclass differs only by case from inherited field or method
JAVA0245 0.00JAVA0245 JUnit TestCase with non-trivial constructor
JAVA0246 0.00JAVA0246 JUnit assertXXX statement missing message parameter
JAVA0247 0.00JAVA0247 JUnit 'setUp()' and 'tearDown()' should call super method
JAVA0248 0.00JAVA0248 JUnit method 'setUp' or 'tearDown' with incorrect signature
JAVA0249 0.00JAVA0249 JUnit TestCase 'suite()' should be declared static
JAVA0250 0.00JAVA0250 JUnit TestCase declares testXXX method with incorrect signature
JAVA0251 0.00JAVA0251 Use '%n' for line breaks in printf/format for platform independence
JAVA0252 0.00JAVA0252 'enum' is a Java 1.5 reserved word
JAVA0253 0.00JAVA0253 Not all enum constants consumed in switch statement
JAVA0254 0.00JAVA0254 Use enhanced for loop construct instead of Iterator
JAVA0255 0.00JAVA0255 Result of method invocation not used
JAVA0256 0.00JAVA0256 Assignment of external collection/array to field
JAVA0257 0.00JAVA0257 Use of 'Constant Interface' anti-pattern
JAVA0258 0.00JAVA0258 Implement Iterable for foreach compatibility
JAVA0259 0.00JAVA0259 Return of collection/array field
JAVA0260 0.00JAVA0260 Use 'enum' instead of Enumerated Type pattern
JAVA0261 0.00JAVA0261 Use specialized Enum collection types
JAVA0262 0.00JAVA0262 Use of char in integer context
JAVA0263 0.00JAVA0263 Long literal ends with 'l' instead of 'L'
JAVA0264 0.00JAVA0264 Integer math in long context - check for overflow
JAVA0265 0.00JAVA0265 Use of Throwable.printStackTrace()
JAVA0266 0.00JAVA0266 Use of System.out
JAVA0267 0.00JAVA0267 Use of System.err
JAVA0269 0.00JAVA0269 Contents of StringBuffer never used
JAVA0270 0.00JAVA0270 Use Java 5.0 enhanced for loop construct to iterate over all elements in an array
JAVA0271 0.00JAVA0271 Minimize use of on-demand (.*) static imports
JAVA0272 0.00JAVA0272 Thread.run() called
JAVA0273 0.00JAVA0273 Non-final derivative of Thread calls start() in constructor
JAVA0274 0.00JAVA0274 Serializable class has a synchronized readObject()
JAVA0275 0.00JAVA0275 Serializable class has a synchronized writeObject() and no other synchronized methods
JAVA0276 0.00JAVA0276 Unnecessary use of String constructor
JAVA0277 0.00JAVA0277 Iterator.next() implementation does not throw NoSuchElementException
JAVA0278 0.00JAVA0278 Unnecessary use of Boolean constructor
JAVA0279 0.00JAVA0279 Serialization method readObject or readObjectNoData calls an overridable method
JAVA0280 0.00JAVA0280 IllegalMonitorStateException caught
JAVA0281 0.00JAVA0281 Iterator.next() not called in loop
JAVA0282 0.00JAVA0282 Call to Iterator.next() in loop which does not test Iterator.hasNext()
JAVA0283 0.00JAVA0283 Control variable not updated in loop body
JAVA0284 0.00JAVA0284 Explicit garbage collection
JAVA0285 0.00JAVA0285 Dereference of potentially null variable
JAVA0286 0.00JAVA0286 Dereference of null variable
JAVA0287 0.00JAVA0287 Unnecessary null check
JAVA0288 0.00JAVA0288 Inconsistent null check
LINES3146.00Number of lines in the source file
LINE_COMMENT125.00Number of line comments
LOC2137.00Lines of code
LOGICAL_LINES721.00Number of statements
LOOPS12.00Number of loops
NEST_DEPTH 5.00Maximum nesting depth
OPERANDS4236.00Number of operands
OPERATORS8002.00Number of operators
PARAMS232.00Number of formal parameter declarations
PROGRAM_LENGTH12238.00Halstead program length
PROGRAM_VOCAB964.00Halstead program vocabulary
PROGRAM_VOLUME 0.00Halstead program volume
RETURNS160.00Number of return points from functions
SIZE76133.00Size of the file in bytes
UNIQUE_OPERANDS910.00Number of unique operands
UNIQUE_OPERATORS54.00Number of unique operators
WHITESPACE279.00Number of whitespace lines