use of pcgen.cdom.content.HitDie in project pcgen by PCGen.
the class HitDieStep method applyProcessor.
/**
* Applies this Processor to the given input object, in the context of the
* given context object.
*
* *NOTE* if the HitDie provided is not in the global sequence of HitDie
* objects (defined in the Game Mode), then this method will fail to step
* that HitDie, and the original, unmodified HitDie will be returned.
*
* Since HitDieStep is universal, the given context is ignored.
*
* @param origHD
* The input HitDie this HitDieStep will act upon.
* @param context
* The context, ignored by HitDieStep.
* @return The modified HitDie, as limited by the bound of this HitDieStep.
* @throws NullPointerException
* if the given HitDie is null
*/
@Override
public HitDie applyProcessor(HitDie origHD, Object context) {
int steps = numSteps;
HitDie currentDie = origHD;
while (steps != 0) {
// Order is important, dieLimit may be null
if (currentDie.equals(dieLimit)) {
return currentDie;
}
if (steps > 0) {
currentDie = currentDie.getNext();
steps--;
} else {
assert steps < 0;
currentDie = currentDie.getPrevious();
steps++;
}
}
return currentDie;
/*
* Theoretically, the die sizes here should be stored as ... what? A
* AbstractSequencedConstant, effectively? This gives the ability to
* look up the next one... that makes HitDie not really storing an
* Int... so Hit Die really should be a helper, or an enumeration?
*
* So it looks like an enumeration is OUT because the MODs will actually
* alter to unexpected values... like 8 * 3 = 24... therefore, this
* really needs to be thought through to determine what is best... The
* behavior for these cases is undefined.
*
* There is a (short) thread on pcgen-devel "Hit Die Locking" from Nov
* 2006, where this issue remains unresolved.
*/
}
use of pcgen.cdom.content.HitDie in project pcgen by PCGen.
the class HitPointFacet method rollHP.
/**
* Rolls the hit points for a given PCClass and level.
*
* @param id
* The CharID identifying the Player Character on which the hit
* points are to be rolled
* @param pcc
* The PCClass for which the hit points are to be rolled
* @param level
* The class level for which the hit points are to be rolled
* @param first
* And identifier indicating if this is the Player Character's
* first level.
*/
public void rollHP(CharID id, PCClass pcc, int level, boolean first) {
int roll = 0;
HitDie lvlDie = getLevelHitDie(id, pcc, level);
if ((lvlDie == null) || (lvlDie.getDie() == 0)) {
roll = 0;
} else {
final int min = 1 + (int) bonusCheckingFacet.getBonus(id, "HD", "MIN") + (int) bonusCheckingFacet.getBonus(id, "HD", "MIN;CLASS." + pcc.getKeyName());
final int max = getLevelHitDie(id, pcc, level).getDie() + (int) bonusCheckingFacet.getBonus(id, "HD", "MAX") + (int) bonusCheckingFacet.getBonus(id, "HD", "MAX;CLASS." + pcc.getKeyName());
if (SettingsHandler.getGame().getHPFormula().isEmpty()) {
if (first && level == 1 && SettingsHandler.isHPMaxAtFirstLevel() && (!SettingsHandler.isHPMaxAtFirstPCClassLevelOnly() || pcc.isType("PC"))) {
roll = max;
} else {
PlayerCharacter pc = trackingFacet.getPC(id);
if (!pc.isImporting()) {
roll = rollHP(min, max, levelFacet.getTotalLevels(id));
}
}
}
roll += ((int) bonusCheckingFacet.getBonus(id, "HP", "CURRENTMAXPERLEVEL"));
}
PCClassLevel classLevel = classFacet.getClassLevel(id, pcc, level - 1);
set(id, classLevel, roll);
}
use of pcgen.cdom.content.HitDie in project pcgen by PCGen.
the class HitPointFacet method getLevelHitDie.
/**
* Returns the HitDie for the given PCClass and level in the Player
* Character identified by the given CharID.
*
* @param id
* The CharID identifying the Player Character for which the
* HitDie of the given PCClass and level will be returned
* @param pcClass
* The PCClass for which the HitDie will be returned
* @param classLevel
* The level for which the HitDie will be returned
* @return The HitDie for the given PCClass and level in the Player
* Character identified by the given CharID
*/
public HitDie getLevelHitDie(CharID id, PCClass pcClass, int classLevel) {
// Class Base Hit Die
HitDie currDie = pcClass.getSafe(ObjectKey.LEVEL_HITDIE);
Processor<HitDie> dieLock = raceFacet.get(id).get(ObjectKey.HITDIE);
if (dieLock != null) {
currDie = dieLock.applyProcessor(currDie, pcClass);
}
// Templates
for (PCTemplate template : templateFacet.getSet(id)) {
if (template != null) {
Processor<HitDie> lock = template.get(ObjectKey.HITDIE);
if (lock != null) {
currDie = lock.applyProcessor(currDie, pcClass);
}
}
}
// Levels
PCClassLevel cl = classFacet.getClassLevel(id, pcClass, classLevel);
if (cl != null) {
if (cl.get(ObjectKey.DONTADD_HITDIE) != null) {
//null;
currDie = HitDie.ZERO;
} else {
Processor<HitDie> lock = cl.get(ObjectKey.HITDIE);
if (lock != null) {
currDie = lock.applyProcessor(currDie, pcClass);
}
}
}
return currDie;
}
use of pcgen.cdom.content.HitDie in project pcgen by PCGen.
the class PlayerCharacter method addTemplate.
public boolean addTemplate(final PCTemplate inTemplate) {
if (inTemplate == null) {
return false;
}
// Don't allow multiple copies of template.
if (hasTemplate(inTemplate)) {
return false;
}
// this is what this value was before
int lockMonsterSkillPoints = 0;
// adding this template
for (PCClass pcClass : getClassSet()) {
if (pcClass.isMonster()) {
lockMonsterSkillPoints = (int) getTotalBonusTo("MONSKILLPTS", "LOCKNUMBER");
break;
}
}
boolean added = templateInputFacet.add(id, inTemplate);
if (!added) {
return false;
}
this.setDirty(true);
calcActiveBonuses();
// this is what this value was before
int postLockMonsterSkillPoints;
// adding this template
boolean first = true;
for (PCClass pcClass : getClassSet()) {
if (pcClass.isMonster()) {
postLockMonsterSkillPoints = (int) getTotalBonusTo("MONSKILLPTS", "LOCKNUMBER");
if (postLockMonsterSkillPoints != lockMonsterSkillPoints && postLockMonsterSkillPoints > 0) {
for (PCLevelInfo pi : getLevelInfo()) {
final int newSkillPointsGained = recalcSkillPointMod(pcClass, pi.getClassLevel());
if (pi.getClassKeyName().equals(pcClass.getKeyName())) {
final int formerGained = pi.getSkillPointsGained(this);
pi.setSkillPointsGained(this, newSkillPointsGained);
pi.setSkillPointsRemaining(pi.getSkillPointsRemaining() + newSkillPointsGained - formerGained);
setSkillPool(pcClass, pcClass.getSkillPool(this) + newSkillPointsGained - formerGained);
}
}
}
}
//
if (!importing) {
Processor<HitDie> dieLock = inTemplate.get(ObjectKey.HITDIE);
if (dieLock != null) {
for (int level = 1; level <= getLevel(pcClass); level++) {
HitDie baseHD = pcClass.getSafe(ObjectKey.LEVEL_HITDIE);
if (!baseHD.equals(getLevelHitDie(pcClass, level))) {
// If the HD has changed from base reroll
rollHP(pcClass, level, first);
}
}
}
}
first = false;
}
setDirty(true);
return true;
}
use of pcgen.cdom.content.HitDie in project pcgen by PCGen.
the class HitdieToken method parseNonEmptyToken.
@Override
protected ParseResult parseNonEmptyToken(LoadContext context, Race race, String value) {
try {
String lock = value;
int pipeLoc = lock.indexOf(Constants.PIPE);
if (pipeLoc != lock.lastIndexOf(Constants.PIPE)) {
return new ParseResult.Fail(getTokenName() + " has more than one pipe, " + "is not of format: <int>[|<prereq>]", context);
}
// Do not initialize, null is significant
CDOMReference<PCClass> owner = null;
if (pipeLoc != -1) {
// Has a limitation
String lockPre = lock.substring(pipeLoc + 1);
if (lockPre.startsWith("CLASS.TYPE=")) {
String substring = lock.substring(pipeLoc + 12);
if (substring.isEmpty()) {
return new ParseResult.Fail("Cannot have Empty Type Limitation in " + getTokenName() + ": " + value, context);
}
ParseResult pr = checkForIllegalSeparator('.', substring);
if (!pr.passed()) {
return pr;
}
owner = context.getReferenceContext().getCDOMTypeReference(PCCLASS_CLASS, substring.split("\\."));
} else if (lockPre.startsWith(Constants.LST_CLASS_EQUAL)) {
String substring = lock.substring(pipeLoc + 7);
if (substring.isEmpty()) {
return new ParseResult.Fail("Cannot have Empty Class Limitation in " + getTokenName() + ": " + value, context);
}
owner = context.getReferenceContext().getCDOMReference(PCCLASS_CLASS, substring);
} else {
return new ParseResult.Fail("Invalid Limitation in HITDIE: " + lockPre, context);
}
lock = lock.substring(0, pipeLoc);
}
Processor<HitDie> hdm;
if (lock.startsWith("%/")) {
// HITDIE:%/num --- divides the classes hit die by num.
int denom = Integer.parseInt(lock.substring(2));
if (denom <= 0) {
return new ParseResult.Fail(getTokenName() + " was expecting a Positive Integer " + "for dividing Lock, was : " + lock.substring(2), context);
}
hdm = new HitDieFormula(new DividingFormula(denom));
} else if (lock.startsWith("%*")) {
// HITDIE:%*num --- multiplies the classes hit die by num.
int mult = Integer.parseInt(lock.substring(2));
if (mult <= 0) {
return new ParseResult.Fail(getTokenName() + " was expecting a Positive " + "Integer for multiplying Lock, was : " + lock.substring(2), context);
}
hdm = new HitDieFormula(new MultiplyingFormula(mult));
} else if (lock.startsWith("%+")) {
// possibly redundant with BONUS:HD MAX|num
// HITDIE:%+num --- adds num to the classes hit die.
int add = Integer.parseInt(lock.substring(2));
if (add <= 0) {
return new ParseResult.Fail(getTokenName() + " was expecting a Positive " + "Integer for adding Lock, was : " + lock.substring(2), context);
}
hdm = new HitDieFormula(new AddingFormula(add));
} else if (lock.startsWith("%-")) {
// HITDIE:%-num --- subtracts num from the classes hit die.
// possibly redundant with BONUS:HD MAX|num if that will
// take negative numbers.
int sub = Integer.parseInt(lock.substring(2));
if (sub <= 0) {
return new ParseResult.Fail(getTokenName() + " was expecting a Positive " + "Integer for subtracting Lock, was : " + lock.substring(2), context);
}
hdm = new HitDieFormula(new SubtractingFormula(sub));
} else if (lock.startsWith("%up")) {
// HITDIE:%upnum --- moves the hit die num steps up the die size
// list d4,d6,d8,d10,d12. Stops at d12.
int steps = Integer.parseInt(lock.substring(3));
if (steps <= 0) {
return new ParseResult.Fail("Invalid Step Count: " + steps + " in " + getTokenName() + " up (must be positive)", context);
}
if (steps >= 5) {
return new ParseResult.Fail("Invalid Step Count: " + steps + " in " + getTokenName() + " up (too large)", context);
}
hdm = new HitDieStep(steps, new HitDie(12));
} else if (lock.startsWith("%Hup")) {
// HITDIE:%upnum --- moves the hit die num steps up the die size
// list d4,d6,d8,d10,d12. Stops at d12.
int steps = Integer.parseInt(lock.substring(4));
if (steps <= 0) {
return new ParseResult.Fail("Invalid Step Count: " + steps + " in " + getTokenName(), context);
}
hdm = new HitDieStep(steps, null);
} else if (lock.startsWith("%down")) {
// HITDIE:%downnum --- moves the hit die num steps down the die
// size
// list d4,d6,d8,d10,d12. Stops at d4.
int steps = Integer.parseInt(lock.substring(5));
if (steps <= 0) {
return new ParseResult.Fail("Invalid Step Count: " + steps + " in " + getTokenName() + " down (must be positive)", context);
}
if (steps >= 5) {
return new ParseResult.Fail("Invalid Step Count: " + steps + " in " + getTokenName() + " down (too large)", context);
}
hdm = new HitDieStep(-steps, new HitDie(4));
} else if (lock.startsWith("%Hdown")) {
// HITDIE:%downnum --- moves the hit die num steps down the die
// size
// list. No limit.
int steps = Integer.parseInt(lock.substring(6));
if (steps <= 0) {
return new ParseResult.Fail("Invalid Step Count: " + steps + " in " + getTokenName(), context);
}
hdm = new HitDieStep(-steps, null);
} else {
int i = Integer.parseInt(lock);
if (i <= 0) {
return new ParseResult.Fail("Invalid HitDie: " + i + " in " + getTokenName(), context);
}
// HITDIE:num --- sets the hit die to num regardless of class.
hdm = new HitDieLock(new HitDie(i));
}
Processor<HitDie> mod = owner == null ? hdm : new ContextProcessor<>(hdm, owner);
context.getObjectContext().put(race, ObjectKey.HITDIE, mod);
return ParseResult.SUCCESS;
} catch (NumberFormatException nfe) {
return new ParseResult.Fail("Invalid Number (must be an Integer) in " + getTokenName() + ": " + nfe.getLocalizedMessage(), context);
}
}
Aggregations