Search in sources :

Example 11 with LevelCommandFactory

use of pcgen.cdom.content.LevelCommandFactory in project pcgen by PCGen.

the class PlayerCharacter method setMaster.

/**
	 * Set the master for this object also set the level dependent stats based
	 * on the masters level and info contained in the companionModList Array
	 * such as HitDie, SR, BONUS, SA, etc.
	 *
	 * @param aM
	 *            The master to be set.
	 */
public void setMaster(final Follower aM) {
    masterFacet.set(id, aM);
    final PlayerCharacter mPC = getMasterPC();
    if (mPC == null) {
        return;
    }
    // make sure masters Name and fileName are correct
    if (!aM.getFileName().equals(mPC.getFileName())) {
        aM.setFileName(mPC.getFileName());
        setDirty(true);
    }
    if (!aM.getName().equals(mPC.getName())) {
        aM.setName(mPC.getName());
        setDirty(true);
    }
    // Get total wizard + sorcerer levels as they stack like a mother
    int mTotalLevel = 0;
    int addHD = 0;
    for (PCClass mClass : mPC.getClassSet()) {
        boolean found = false;
        for (CompanionMod cMod : Globals.getContext().getReferenceContext().getManufacturer(CompanionMod.class, aM.getType()).getAllObjects()) {
            if ((cMod.getLevelApplied(mClass) > 0) && !found) {
                mTotalLevel += getLevel(mClass);
                found = true;
            }
        }
    }
    List<CompanionMod> newCompanionMods = new ArrayList<>();
    // Clear the companionModList so we can add everything to it
    Collection<CompanionMod> oldCompanionMods = companionModFacet.removeAll(id);
    for (CompanionMod cMod : Globals.getContext().getReferenceContext().getManufacturer(CompanionMod.class, aM.getType()).getAllObjects()) {
        // Check all the masters classes
        for (PCClass mClass : mPC.getClassSet()) {
            final int mLev = mPC.getLevel(mClass) + aM.getAdjustment();
            final int compLev = cMod.getLevelApplied(mClass);
            if (compLev < 0) {
                continue;
            }
            // and for the correct level or lower
            if ((compLev <= mLev) || (compLev <= mTotalLevel)) {
                if (cMod.qualifies(this, cMod)) {
                    if (!oldCompanionMods.contains(cMod)) {
                        newCompanionMods.add(cMod);
                    }
                    companionModFacet.add(id, cMod);
                    addHD += cMod.getSafe(IntegerKey.HIT_DIE);
                }
            }
        }
        Map<String, Integer> varmap = cMod.getMapFor(MapKey.APPLIED_VARIABLE);
        for (String varName : varmap.keySet()) {
            final int mLev = mPC.getVariableValue(varName, Constants.EMPTY_STRING).intValue() + aM.getAdjustment();
            if (mLev >= cMod.getVariableApplied(varName)) {
                if (cMod.qualifies(this, cMod)) {
                    if (!oldCompanionMods.contains(cMod)) {
                        newCompanionMods.add(cMod);
                    }
                    companionModFacet.add(id, cMod);
                    addHD += cMod.getSafe(IntegerKey.HIT_DIE);
                }
            }
        }
    }
    // Add additional HD if required
    LevelCommandFactory lcf = getRace().get(ObjectKey.MONSTER_CLASS);
    final int usedHD = aM.getUsedHD();
    addHD -= usedHD;
    // if ((newClass != null) && (addHD != 0))
    if ((lcf != null) && (addHD != 0)) {
        // set the new HD (but only do it once!)
        incrementClassLevel(addHD, lcf.getPCClass(), true);
        aM.setUsedHD(addHD + usedHD);
        setDirty(true);
    }
    // If it's a familiar, we need to change it's Skills
    if (masterFacet.getUseMasterSkill(id)) {
        final Collection<Skill> mList = mPC.getSkillSet();
        final List<Skill> sKeyList = new ArrayList<>();
        // take the higher rank of each skill for the Familiar
        for (Skill fSkill : getSkillSet()) {
            for (Skill mSkill : mList) {
                // already has ranks in the skill
                if (mSkill.equals(fSkill)) {
                    // need higher rank of the two
                    Float totalMasterRank = SkillRankControl.getTotalRank(mPC, mSkill);
                    if (totalMasterRank.intValue() > this.getRank(fSkill).intValue()) {
                        // first zero current
                        SkillRankControl.setZeroRanks(lcf == null ? null : lcf.getPCClass(), this, fSkill);
                        // We don't pass in a class here so that the real
                        // skills can be distinguished from the ones from
                        // the master.
                        SkillRankControl.modRanks(totalMasterRank.doubleValue(), null, true, this, fSkill);
                    }
                }
                // Possesses, but the familiar does not
                if (!hasSkill(mSkill) && !sKeyList.contains(mSkill)) {
                    sKeyList.add(mSkill);
                }
            }
        }
        // now add all the skills only the master has
        for (Skill newSkill : sKeyList) {
            // familiar doesn't have skill,
            // but master does, so add it
            final double sr = SkillRankControl.getTotalRank(mPC, newSkill).doubleValue();
            // We don't pass in a class here so that the real skills can be
            // distinguished from the ones form the master.
            SkillRankControl.modRanks(sr, null, true, this, newSkill);
            if (ChooseActivation.hasNewChooseToken(newSkill)) {
                //TODO a bit reckless :P
                ChooseInformation<Language> chooseInfo = (ChooseInformation<Language>) newSkill.get(ObjectKey.CHOOSE_INFO);
                List<? extends Language> selected = chooseInfo.getChoiceActor().getCurrentlySelected(newSkill, mPC);
                ChoiceManagerList<Language> controller = ChooserUtilities.getConfiguredController(newSkill, this, null, new ArrayList<>());
                for (Language lang : selected) {
                    if (!controller.conditionallyApply(this, lang)) {
                        Logging.errorPrint("Failed to add master's language " + lang + " to companion.");
                    }
                }
            }
        }
    }
    oldCompanionMods.removeAll(companionModFacet.getSet(id));
    for (CompanionMod cMod : oldCompanionMods) {
        CDOMObjectUtilities.removeAdds(cMod, this);
        CDOMObjectUtilities.restoreRemovals(cMod, this);
    }
    for (CompanionMod cMod : newCompanionMods) {
        CDOMObjectUtilities.addAdds(cMod, this);
        CDOMObjectUtilities.checkRemovals(cMod, this);
        for (CDOMReference<PCTemplate> ref : cMod.getSafeListFor(ListKey.TEMPLATE)) {
            for (PCTemplate pct : ref.getContainedObjects()) {
                addTemplate(pct);
            }
        }
        for (CDOMReference<PCTemplate> ref : cMod.getSafeListFor(ListKey.REMOVE_TEMPLATES)) {
            for (PCTemplate pct : ref.getContainedObjects()) {
                removeTemplate(pct);
            }
        }
        for (TransitionChoice<Kit> kit : cMod.getSafeListFor(ListKey.KIT_CHOICE)) {
            kit.act(kit.driveChoice(this), cMod, this);
        }
    }
    calcActiveBonuses();
    setDirty(true);
}
Also used : ChooseInformation(pcgen.cdom.base.ChooseInformation) LevelCommandFactory(pcgen.cdom.content.LevelCommandFactory) ArrayList(java.util.ArrayList) CompanionMod(pcgen.core.character.CompanionMod)

Example 12 with LevelCommandFactory

use of pcgen.cdom.content.LevelCommandFactory in project pcgen by PCGen.

the class PCClass method addLevel.

/**
	 * Adds a level of this class to the character.
	 *
	 * TODO: Split the PlayerCharacter code out of PCClass (i.e. the level
	 * property). Then have a joining class assigned to PlayerCharacter that
	 * maps PCClass and number of levels in the class.
	 *
	 *
	 * @param argLevelMax
	 *            True if we should only allow extra levels if there are still
	 *            levels in this class to take. (i.e. a lot of prestige classes
	 *            stop at level 10, so if this is true it would not allow an
	 *            11th level of the class to be added
	 * @param bSilent
	 *            True if we are not to show any dialog boxes about errors or
	 *            questions.
	 * @param aPC
	 *            The character we are adding the level to.
	 * @param ignorePrereqs
	 *            True if prereqs for the level should be ignored. Used in
	 *            situations such as when the character is being loaded.
	 * @return true or false
	 */
/*
	 * REFACTOR Clearly this is part of the PCClass factory method that produces
	 * PCClassLevels combined with some other work that will need to be done to
	 * extract some of the complicated gunk out of here that goes out and puts
	 * information into PCLevelInfo and PlayerCharacter.
	 */
public boolean addLevel(final boolean argLevelMax, final boolean bSilent, final PlayerCharacter aPC, final boolean ignorePrereqs) {
    // Check to see if we can add a level of this class to the
    // current character
    final int newLevel = aPC.getLevel(this) + 1;
    boolean levelMax = argLevelMax;
    aPC.setAllowInteraction(false);
    aPC.setLevelWithoutConsequence(this, newLevel);
    if (!ignorePrereqs) {
        // When loading a character, classes are added before feats, so
        // this test would always fail on loading if feats are required
        boolean doReturn = false;
        if (!qualifies(aPC, this)) {
            doReturn = true;
            if (!bSilent) {
                ShowMessageDelegate.showMessageDialog("This character does not qualify for level " + newLevel, Constants.APPLICATION_NAME, MessageType.ERROR);
            }
        }
        aPC.setLevelWithoutConsequence(this, newLevel - 1);
        if (doReturn) {
            return false;
        }
    }
    aPC.setAllowInteraction(true);
    if (isMonster()) {
        levelMax = false;
    }
    if (hasMaxLevel() && (newLevel > getSafe(IntegerKey.LEVEL_LIMIT)) && levelMax) {
        if (!bSilent) {
            ShowMessageDelegate.showMessageDialog("This class cannot be raised above level " + Integer.toString(getSafe(IntegerKey.LEVEL_LIMIT)), Constants.APPLICATION_NAME, MessageType.ERROR);
        }
        return false;
    }
    // Add the level to the current character
    int total = aPC.getTotalLevels();
    // No longer need this since the race now sets a bonus itself and Templates
    // are not able to reassign their feats.  There was nothing else returned in
    // this number
    //		if (total == 0) {
    //			aPC.setFeats(aPC.getInitialFeats());
    //		}
    setLevel(newLevel, aPC);
    // the level has now been added to the character,
    // so now assign the attributes of this class level to the
    // character...
    PCClassLevel classLevel = aPC.getActiveClassLevel(this, newLevel);
    // Make sure that if this Class adds a new domain that
    // we record where that domain came from
    final int dnum = aPC.getMaxCharacterDomains(this, aPC) - aPC.getDomainCount();
    if (dnum > 0 && !aPC.hasDefaultDomainSource()) {
        aPC.setDefaultDomainSource(new ClassSource(this, newLevel));
    }
    // out
    if (Globals.getUseGUI()) {
        final int levels = SettingsHandler.isHPMaxAtFirstClassLevel() ? aPC.totalNonMonsterLevels() : aPC.getTotalLevels();
        final boolean isFirst = levels == 1;
        aPC.rollHP(this, aPC.getLevel(this), isFirst);
    }
    if (!aPC.isImporting()) {
        DomainApplication.addDomainsUpToLevel(this, newLevel, aPC);
    }
    int levelUpStats = 0;
    // i.e. a bonus feat every 3 levels
    if (aPC.getTotalLevels() > total) {
        boolean processBonusStats = true;
        total = aPC.getTotalLevels();
        if (isMonster()) {
            // If we have less levels that the races monster levels
            // then we can not give a stat bonus (i.e. an Ogre has
            // 4 levels of Giant, so it does not get a stat increase at
            // 4th level because that is already taken into account in
            // its racial stat modifiers, but it will get one at 8th
            LevelCommandFactory lcf = aPC.getRace().get(ObjectKey.MONSTER_CLASS);
            int monLevels = 0;
            if (lcf != null) {
                monLevels = lcf.getLevelCount().resolve(aPC, "").intValue();
            }
            if (total <= monLevels) {
                processBonusStats = false;
            }
        }
        if (!aPC.isImporting()) {
            if (processBonusStats) {
                final int bonusStats = Globals.getBonusStatsForLevel(total, aPC);
                if (bonusStats > 0) {
                    aPC.setPoolAmount(aPC.getPoolAmount() + bonusStats);
                    if (!bSilent && SettingsHandler.getShowStatDialogAtLevelUp()) {
                        levelUpStats = StatApplication.askForStatIncrease(aPC, bonusStats, true);
                    }
                }
            }
        }
    }
    int spMod = getSkillPointsForLevel(aPC, classLevel, total);
    PCLevelInfo pcl;
    if (aPC.getLevelInfoSize() > 0) {
        pcl = aPC.getLevelInfo(aPC.getLevelInfoSize() - 1);
        if (pcl != null) {
            pcl.setClassLevel(aPC.getLevel(this));
            pcl.setSkillPointsGained(aPC, spMod);
            pcl.setSkillPointsRemaining(pcl.getSkillPointsGained(aPC));
        }
    }
    Integer currentPool = aPC.getSkillPool(this);
    int newSkillPool = spMod + (currentPool == null ? 0 : currentPool);
    aPC.setSkillPool(this, newSkillPool);
    if (!aPC.isImporting()) {
        //
        if (levelUpStats > 0) {
            StatApplication.askForStatIncrease(aPC, levelUpStats, false);
        }
        if (newLevel == 1) {
            AddObjectActions.doBaseChecks(this, aPC);
            CDOMObjectUtilities.addAdds(this, aPC);
            CDOMObjectUtilities.checkRemovals(this, aPC);
        }
        for (TransitionChoice<Kit> kit : classLevel.getSafeListFor(ListKey.KIT_CHOICE)) {
            kit.act(kit.driveChoice(aPC), classLevel, aPC);
        }
        TransitionChoice<Region> region = classLevel.get(ObjectKey.REGION_CHOICE);
        if (region != null) {
            region.act(region.driveChoice(aPC), classLevel, aPC);
        }
    }
    // this is a monster class, so don't worry about experience
    if (isMonster()) {
        return true;
    }
    if (!aPC.isImporting()) {
        CDOMObjectUtilities.checkRemovals(this, aPC);
        final int minxp = aPC.minXPForECL();
        if (aPC.getXP() < minxp) {
            aPC.setXP(minxp);
        } else if (aPC.getXP() >= aPC.minXPForNextECL()) {
            if (!bSilent) {
                ShowMessageDelegate.showMessageDialog(SettingsHandler.getGame().getLevelUpMessage(), Constants.APPLICATION_NAME, MessageType.INFORMATION);
            }
        }
    }
    //
    if (containsKey(ObjectKey.EXCHANGE_LEVEL) && (aPC.getLevel(this) == 1) && !aPC.isImporting()) {
        ExchangeLevelApplication.exchangeLevels(aPC, this);
    }
    return true;
}
Also used : LevelCommandFactory(pcgen.cdom.content.LevelCommandFactory) Region(pcgen.cdom.enumeration.Region) PCLevelInfo(pcgen.core.pclevelinfo.PCLevelInfo) ClassSource(pcgen.cdom.helper.ClassSource) PCClassLevel(pcgen.cdom.inst.PCClassLevel)

Example 13 with LevelCommandFactory

use of pcgen.cdom.content.LevelCommandFactory in project pcgen by PCGen.

the class RaceToken method getRaceToken.

private static String getRaceToken(PlayerCharacter pc) {
    String retString = Constants.EMPTY_STRING;
    Race race = pc.getDisplay().getRace();
    String tempRaceName = OutputNameFormatting.getOutputName(race);
    if (tempRaceName == null || tempRaceName.isEmpty()) {
        tempRaceName = race.getDisplayName();
    }
    StringBuilder extraRaceInfo = new StringBuilder(40);
    String subRace = pc.getDisplay().getSubRace();
    if (subRace != null) {
        extraRaceInfo.append(subRace);
    }
    if (SettingsHandler.hideMonsterClasses()) {
        LevelCommandFactory lcf = race.get(ObjectKey.MONSTER_CLASS);
        if (lcf != null) {
            PCClass monsterClass = lcf.getPCClass();
            final PCClass aClass = pc.getClassKeyed(monsterClass.getKeyName());
            if (aClass != null) {
                int minHD = lcf.getLevelCount().resolve(pc, "").intValue();
                int monsterHD = pc.getDisplay().getLevel(aClass);
                if (monsterHD != minHD) {
                    if (extraRaceInfo.length() != 0) {
                        extraRaceInfo.append(' ');
                    }
                    extraRaceInfo.append(monsterHD).append(//$NON-NLS-1$
                    LanguageBundle.getString("in_hdLabel"));
                }
            }
        }
    }
    retString = tempRaceName;
    if (extraRaceInfo.length() != 0) {
        //$NON-NLS-1$
        retString += " (" + extraRaceInfo + ')';
    }
    return retString;
}
Also used : LevelCommandFactory(pcgen.cdom.content.LevelCommandFactory) Race(pcgen.core.Race) PCClass(pcgen.core.PCClass)

Example 14 with LevelCommandFactory

use of pcgen.cdom.content.LevelCommandFactory in project pcgen by PCGen.

the class MonsterclassToken method parseNonEmptyToken.

@Override
protected ParseResult parseNonEmptyToken(LoadContext context, Race race, String value) {
    ParsingSeparator sep = new ParsingSeparator(value, ':');
    sep.addGroupingPair('[', ']');
    sep.addGroupingPair('(', ')');
    String classString = sep.next();
    if (!sep.hasNext()) {
        return new ParseResult.Fail(getTokenName() + " must have a colon: " + value, context);
    }
    String numLevels = sep.next();
    if (sep.hasNext()) {
        return new ParseResult.Fail(getTokenName() + " must have only one colon: " + value, context);
    }
    CDOMSingleRef<PCClass> cl = context.getReferenceContext().getCDOMReference(PCCLASS_CLASS, classString);
    try {
        int lvls = Integer.parseInt(numLevels);
        if (lvls <= 0) {
            return new ParseResult.Fail("Number of levels in " + getTokenName() + " must be greater than zero: " + value, context);
        }
        LevelCommandFactory cf = new LevelCommandFactory(cl, FormulaFactory.getFormulaFor(lvls));
        context.getObjectContext().put(race, ObjectKey.MONSTER_CLASS, cf);
        return ParseResult.SUCCESS;
    } catch (NumberFormatException nfe) {
        return new ParseResult.Fail("Number of levels in " + getTokenName() + " must be an integer greater than zero: " + value, context);
    }
}
Also used : LevelCommandFactory(pcgen.cdom.content.LevelCommandFactory) ParsingSeparator(pcgen.base.text.ParsingSeparator) ParseResult(pcgen.rules.persistence.token.ParseResult) PCClass(pcgen.core.PCClass)

Example 15 with LevelCommandFactory

use of pcgen.cdom.content.LevelCommandFactory in project pcgen by PCGen.

the class MonsterclassToken method unparse.

@Override
public String[] unparse(LoadContext context, Race race) {
    LevelCommandFactory lcf = context.getObjectContext().getObject(race, ObjectKey.MONSTER_CLASS);
    if (lcf == null) {
        return null;
    }
    StringBuilder sb = new StringBuilder();
    sb.append(lcf.getLSTformat()).append(Constants.COLON).append(lcf.getLevelCount().toString());
    return new String[] { sb.toString() };
}
Also used : LevelCommandFactory(pcgen.cdom.content.LevelCommandFactory)

Aggregations

LevelCommandFactory (pcgen.cdom.content.LevelCommandFactory)25 PCClass (pcgen.core.PCClass)10 PlayerCharacter (pcgen.core.PlayerCharacter)7 CharID (pcgen.cdom.enumeration.CharID)4 FixedSizeFormula (pcgen.cdom.formula.FixedSizeFormula)4 ArrayList (java.util.ArrayList)3 Test (org.junit.Test)3 Race (pcgen.core.Race)3 SizeAdjustment (pcgen.core.SizeAdjustment)3 LoadContext (pcgen.rules.context.LoadContext)3 URI (java.net.URI)2 ParsingSeparator (pcgen.base.text.ParsingSeparator)2 CDOMObject (pcgen.cdom.base.CDOMObject)2 PCTemplate (pcgen.core.PCTemplate)2 BonusObj (pcgen.core.bonus.BonusObj)2 PCLevelInfo (pcgen.core.pclevelinfo.PCLevelInfo)2 CampaignSourceEntry (pcgen.persistence.lst.CampaignSourceEntry)2 PCClassLoader (pcgen.persistence.lst.PCClassLoader)2 PreParserFactory (pcgen.persistence.lst.prereq.PreParserFactory)2 PcgCombatant (gmgen.plugin.PcgCombatant)1