use of pcgen.core.display.CharacterDisplay in project pcgen by PCGen.
the class WeaponToken method getToHit.
private static String getToHit(PlayerCharacter pc, Equipment eq, int range, int content, int ammo, int hitMode, int attackNum) {
boolean isDouble = (eq.isDouble() && (eq.getLocation() == EquipmentLocation.EQUIPPED_TWO_HANDS));
boolean isDoubleSplit = (eq.isType("Head1") || eq.isType("Head2"));
// 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);
WeaponProf prof;
String profKey;
if (ref == null) {
profKey = "";
prof = null;
} else {
prof = ref.get();
profKey = prof.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);
// 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() == EquipmentLocation.EQUIPPED_PRIMARY) {
/* Primary Natural Weapons have no bonus or penalty
* associated with secondary weapons/attacks */
baseBonus = 0;
} else if (eq.getLocation() == EquipmentLocation.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 (eq.getLocation() == EquipmentLocation.EQUIPPED_PRIMARY || eq.getLocation() == EquipmentLocation.EQUIPPED_SECONDARY || eq.getLocation() == EquipmentLocation.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;
}
// Where abc: Ranged, Melee, Slashing, etc
for (String type : eq.typeList()) {
// is Handled elsewhere
if (type.equalsIgnoreCase("Finesseable")) {
continue;
}
//Prevents weapon from getting both melee & ranged bonuses
if ((range > -1 && type.equalsIgnoreCase("MELEE")) || (range == -1 && eq.isMelee() && (type.equalsIgnoreCase("THROWN") || type.equalsIgnoreCase("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");
}
//
if ((ref != null) && eq.isRanged()) {
baseBonus -= (int) pc.getBonusDueToType("WEAPONPROF=" + profKey, "TOHIT", "NOTRANGED");
baseBonus -= getWeaponProfTypeBonuses(pc, eq, "TOHIT.NOTRANGED", WPTYPEBONUS_PC);
}
CharacterDisplay display = pc.getDisplay();
if (!eq.isNatural() && ((ref == null) || !display.hasWeaponProf(prof))) {
baseBonus += display.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 shortRange = SettingsHandler.getGame().getShortRangeDistance();
if (range < rangeSize) {
int thisRange = Integer.parseInt(getRangeList(eq, true, pc).get(range));
// 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(EqToken.getRange(pc, eq).toString());
int rangePenalty = SettingsHandler.getGame().getRangePenalty();
rangePenalty += pc.getTotalBonusTo("COMBAT", "RANGEPENALTY");
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 += modFromArmorOnWeaponRolls(pc);
// 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;
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()));
StringBuilder newAttack = new StringBuilder();
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 (!display.hasPrimaryWeapons() && (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() == EquipmentLocation.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 || display.isSecondaryWeapon(eq));
int toHit = 0;
int secondariesAdded = 0;
StringBuilder primaryAttack = new StringBuilder(20);
StringBuilder secondaryAttack = new StringBuilder(20);
StringBuilder totalAttack = new StringBuilder();
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();
}
use of pcgen.core.display.CharacterDisplay in project pcgen by PCGen.
the class FollowerToken method getFollowerOutput.
/**
* Process a token for a follower (must already be loaded) and return the output.
*
* @param eh The ExportHandler being used for output.
* @param followerToken The token to be processed.
* @param follower The follower to be reported upon.
* @return The follower's token output
*/
public static String getFollowerOutput(ExportHandler eh, String followerToken, final Follower follower) {
StringWriter writer = new StringWriter();
BufferedWriter bw = new BufferedWriter(writer);
String token = "".equals(followerToken) ? "NAME" : followerToken;
for (PlayerCharacter eachPC : Globals.getPCList()) {
CharacterDisplay eachDisplay = eachPC.getDisplay();
if (follower.getFileName().equals(eachDisplay.getFileName()) && follower.getName().equals(eachDisplay.getName())) {
PlayerCharacter newPC = eachPC;
eh.replaceToken(token, bw, newPC);
}
}
try {
bw.flush();
} catch (IOException e) {
Logging.errorPrint("Ignoring error while processing FOLLOWER or FOLLOWERTYPE token", e);
}
return writer.toString();
}
use of pcgen.core.display.CharacterDisplay in project pcgen by PCGen.
the class SkillpointsToken method getUsedSkillPoints.
/**
* Get the used skill points for the PC
* @param pc
* @return the used skill points for the PC
*/
public static int getUsedSkillPoints(PlayerCharacter pc, int classNum) {
CharacterDisplay display = pc.getDisplay();
if (classNum < 0 || classNum >= display.getClassCount()) {
return 0;
}
PCClass targetClass = display.getClassList().get(classNum);
float usedPoints = 0;
for (Skill aSkill : display.getSkillSet()) {
Integer outputIndex = pc.getSkillOrder(aSkill);
if ((pc.getRank(aSkill).doubleValue() > 0) || (outputIndex != null && outputIndex != 0)) {
Double rank = pc.getSkillRankForClass(aSkill, targetClass);
if (rank == null) {
rank = 0.0d;
}
SkillCost skillCost = pc.getSkillCostForClass(aSkill, targetClass);
usedPoints += (rank * skillCost.getCost());
}
}
return (int) usedPoints;
}
use of pcgen.core.display.CharacterDisplay in project pcgen by PCGen.
the class PreEquipTester method passes.
/*
* (non-Javadoc)
*
* @see pcgen.core.prereq.PrerequisiteTest#passes(pcgen.core.PlayerCharacter)
*/
@Override
public int passes(final Prerequisite prereq, final PlayerCharacter character, CDOMObject source) throws PrerequisiteException {
int runningTotal = 0;
final int number;
try {
number = Integer.parseInt(prereq.getOperand());
} catch (NumberFormatException exceptn) {
throw new PrerequisiteException(LanguageBundle.getFormattedString("PreFeat.error", //$NON-NLS-1$
prereq.toString()));
}
CharacterDisplay display = character.getDisplay();
if (display.hasEquipment()) {
String targetEquip = prereq.getKey();
for (Equipment eq : display.getEquippedEquipmentSet()) {
if (targetEquip.startsWith("WIELDCATEGORY=") || targetEquip.startsWith("WIELDCATEGORY.")) {
final WieldCategory wCat = eq.getEffectiveWieldCategory(character);
if ((wCat != null) && wCat.getKeyName().equalsIgnoreCase(targetEquip.substring(14))) {
++runningTotal;
break;
}
} else if (//$NON-NLS-1$ //$NON-NLS-2$
targetEquip.startsWith("TYPE=") || targetEquip.startsWith("TYPE.")) {
StringTokenizer tok = new StringTokenizer(targetEquip.substring(5).toUpperCase(), ".");
boolean match = false;
if (tok.hasMoreTokens()) {
match = true;
}
//
while (tok.hasMoreTokens()) {
final String type = tok.nextToken();
if (!eq.isType(type)) {
match = false;
break;
}
}
if (match) {
++runningTotal;
break;
}
} else //not a TYPE string
{
String eqName;
if (//$NON-NLS-1$ //$NON-NLS-2$
targetEquip.startsWith("BASEITEM=")) {
eqName = eq.getBaseItemName().toUpperCase();
targetEquip = targetEquip.substring(targetEquip.indexOf(Constants.EQUALS) + 1);
} else {
eqName = eq.getName().toUpperCase();
}
if (targetEquip.indexOf('%') >= 0) {
//handle wildcards (always assume
// they end the line)
final int percentPos = targetEquip.indexOf('%');
final String substring = targetEquip.substring(0, percentPos).toUpperCase();
if ((eqName.startsWith(substring))) {
++runningTotal;
break;
}
} else if (eqName.equalsIgnoreCase(targetEquip)) {
//just a straight String compare
++runningTotal;
break;
}
}
}
}
runningTotal = prereq.getOperator().compare(runningTotal, number);
return countedTotal(prereq, runningTotal);
}
use of pcgen.core.display.CharacterDisplay in project pcgen by PCGen.
the class PreClassTester method passes.
/**
* @see pcgen.core.prereq.PrerequisiteTest#passes(pcgen.core.PlayerCharacter)
*/
@Override
public int passes(final Prerequisite prereq, final PlayerCharacter character, CDOMObject source) {
CharacterDisplay display = character.getDisplay();
int runningTotal = 0;
int countedTotal = 0;
final boolean sumLevels = prereq.isTotalValues();
final String aString = prereq.getKey().toUpperCase();
final int preClass = Integer.parseInt(prereq.getOperand());
if (//$NON-NLS-1$
"SPELLCASTER".equals(aString)) {
int spellCaster = character.isSpellCaster(preClass, sumLevels);
if (spellCaster > 0) {
if (prereq.isCountMultiples()) {
countedTotal = spellCaster;
} else {
runningTotal = preClass;
}
}
} else if (//$NON-NLS-1$
aString.startsWith("SPELLCASTER.")) {
int spellCaster = character.isSpellCaster(aString.substring(12), preClass, sumLevels);
if (spellCaster > 0) {
if (prereq.isCountMultiples()) {
countedTotal = spellCaster;
} else {
runningTotal = preClass;
}
}
} else if (aString.equals("ANY")) {
for (PCClass cl : display.getClassSet()) {
if (prereq.isCountMultiples()) {
if (display.getLevel(cl) >= preClass) {
countedTotal++;
}
} else {
runningTotal = Math.max(runningTotal, display.getLevel(cl));
}
}
} else if (aString.startsWith("TYPE=") || aString.startsWith("TYPE.")) {
String typeString = aString.substring(5);
for (PCClass cl : display.getClassSet()) {
if (cl.isType(typeString)) {
if (prereq.isCountMultiples()) {
if (display.getLevel(cl) >= preClass) {
countedTotal++;
}
} else {
runningTotal = Math.max(runningTotal, display.getLevel(cl));
}
} else {
for (CDOMReference<PCClass> ref : cl.getSafeListFor(ListKey.SERVES_AS_CLASS)) {
for (PCClass fakeClass : ref.getContainedObjects()) {
if (fakeClass.isType(typeString)) {
if (prereq.isCountMultiples()) {
if (display.getLevel(cl) >= preClass) {
countedTotal++;
}
} else {
runningTotal += display.getLevel(cl);
}
break;
}
}
}
}
}
} else {
PCClass aClass = character.getClassKeyed(aString);
if (aClass != null) {
if (prereq.isCountMultiples()) {
if (display.getLevel(aClass) >= preClass) {
countedTotal++;
}
} else {
runningTotal += display.getLevel(aClass);
}
} else {
CLASSLIST: for (PCClass theClass : display.getClassSet()) {
for (CDOMReference<PCClass> ref : theClass.getSafeListFor(ListKey.SERVES_AS_CLASS)) {
for (PCClass fakeClass : ref.getContainedObjects()) {
if (fakeClass.getKeyName().equalsIgnoreCase(aString)) {
if (prereq.isCountMultiples()) {
if (display.getLevel(theClass) >= preClass) {
countedTotal++;
}
} else {
runningTotal += display.getLevel(theClass);
}
break CLASSLIST;
}
}
}
}
}
}
runningTotal = prereq.getOperator().compare(runningTotal, preClass);
return countedTotal(prereq, prereq.isCountMultiples() ? countedTotal : runningTotal);
}
Aggregations