Search in sources :

Example 1 with HitDie

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.
		 */
}
Also used : HitDie(pcgen.cdom.content.HitDie)

Example 2 with HitDie

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);
}
Also used : PlayerCharacter(pcgen.core.PlayerCharacter) HitDie(pcgen.cdom.content.HitDie) PCClassLevel(pcgen.cdom.inst.PCClassLevel)

Example 3 with HitDie

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;
}
Also used : HitDie(pcgen.cdom.content.HitDie) PCTemplate(pcgen.core.PCTemplate) PCClassLevel(pcgen.cdom.inst.PCClassLevel)

Example 4 with HitDie

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;
}
Also used : HitDie(pcgen.cdom.content.HitDie) PCLevelInfo(pcgen.core.pclevelinfo.PCLevelInfo)

Example 5 with HitDie

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);
    }
}
Also used : HitDieFormula(pcgen.cdom.processor.HitDieFormula) ParseResult(pcgen.rules.persistence.token.ParseResult) PCClass(pcgen.core.PCClass) MultiplyingFormula(pcgen.base.formula.MultiplyingFormula) HitDieLock(pcgen.cdom.processor.HitDieLock) AddingFormula(pcgen.base.formula.AddingFormula) HitDieStep(pcgen.cdom.processor.HitDieStep) HitDie(pcgen.cdom.content.HitDie) DividingFormula(pcgen.base.formula.DividingFormula) SubtractingFormula(pcgen.base.formula.SubtractingFormula)

Aggregations

HitDie (pcgen.cdom.content.HitDie)24 Test (org.junit.Test)14 HitDieLock (pcgen.cdom.processor.HitDieLock)9 HitDieStep (pcgen.cdom.processor.HitDieStep)6 PCClass (pcgen.core.PCClass)4 ParseResult (pcgen.rules.persistence.token.ParseResult)4 AddingFormula (pcgen.base.formula.AddingFormula)3 DividingFormula (pcgen.base.formula.DividingFormula)3 MultiplyingFormula (pcgen.base.formula.MultiplyingFormula)3 SubtractingFormula (pcgen.base.formula.SubtractingFormula)3 HitDieFormula (pcgen.cdom.processor.HitDieFormula)3 PCClassLevel (pcgen.cdom.inst.PCClassLevel)2 PlayerCharacter (pcgen.core.PlayerCharacter)2 ComplexParseResult (pcgen.rules.persistence.token.ComplexParseResult)2 CDOMObject (pcgen.cdom.base.CDOMObject)1 CharID (pcgen.cdom.enumeration.CharID)1 PCTemplate (pcgen.core.PCTemplate)1 SubClass (pcgen.core.SubClass)1 PCLevelInfo (pcgen.core.pclevelinfo.PCLevelInfo)1 HtmlInfoBuilder (pcgen.gui2.util.HtmlInfoBuilder)1