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);
}
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;
}
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;
}
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);
}
}
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() };
}
Aggregations