@Override public PCClass clone() { PCClass aClass = null; try { aClass = (PCClass) super.clone(); List<KnownSpellIdentifier> ksl = getListFor(ListKey.KNOWN_SPELLS); if (ksl != null) { aClass.removeListFor(ListKey.KNOWN_SPELLS); for (KnownSpellIdentifier ksi : ksl) { aClass.addToListFor(ListKey.KNOWN_SPELLS, ksi); } } Map<AttackType, Integer> acmap = getMapFor(MapKey.ATTACK_CYCLE); if (acmap != null && !acmap.isEmpty()) { aClass.removeMapFor(MapKey.ATTACK_CYCLE); for (Map.Entry<AttackType, Integer> me : acmap.entrySet()) { aClass.addToMapFor(MapKey.ATTACK_CYCLE, me.getKey(), me.getValue()); } } aClass.levelMap = new TreeMap<>(); for (Map.Entry<Integer, PCClassLevel> me : levelMap.entrySet()) { aClass.levelMap.put(me.getKey(), me.getValue().clone()); } } catch (CloneNotSupportedException exc) { ShowMessageDelegate.showMessageDialog( exc.getMessage(), Constants.APPLICATION_NAME, MessageType.ERROR); } return aClass; }
/** * Get a temporary file name for outputting a character using a particular output template. * * @param templateFile The output template that will be used. * @return The temporary file, or null if it could not be created. */ public static File getTempOutputFilename(File templateFile) { String extension = ExportUtilities.getOutputExtension( templateFile.getName(), ExportUtilities.isPdfTemplate(templateFile)); try { // create a temporary file to view the character output return File.createTempFile( Constants.TEMPORARY_FILE_NAME, "." + extension, SettingsHandler.getTempPath()); } catch (IOException ioe) { ShowMessageDelegate.showMessageDialog( "Could not create temporary preview file.", "PCGen", MessageType.ERROR); Logging.errorPrint("Could not create temporary preview file.", ioe); return null; } }
/** * Remove a spell from the named book for the character. The request will be validated and any * errors shown to the user by the UIDelegate. * * @param spell The spell to be removed. * @param bookName The book to remove the spell from. * @return True if the removal worked, false if the selection was invalid. */ private boolean removeSpellFromCharacter(SpellNode spell, String bookName) { if (!(spell.getSpell() instanceof SpellFacadeImplem)) { return false; } SpellFacadeImplem sfi = (SpellFacadeImplem) spell.getSpell(); CharacterSpell charSpell = sfi.getCharSpell(); SpellInfo spellInfo = sfi.getSpellInfo(); if (charSpell == null || spellInfo == null) { return false; } final String errorMsg = pc.delSpell(spellInfo, (PCClass) spell.getSpellcastingClass(), bookName); if (errorMsg.length() > 0) { delegate.showErrorMessage(Constants.APPLICATION_NAME, errorMsg); ShowMessageDelegate.showMessageDialog( errorMsg, Constants.APPLICATION_NAME, MessageType.ERROR); return false; } return true; }
/* * 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)); } // Don't roll the hit points if the gui is not being used. // This is so GMGen can add classes to a person without pcgen flipping // 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; // Add any bonus feats or stats that will be gained from this level // 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()) { // We do not want to do these // calculations a second time when are // importing a character. The feat // number and the stat point pool are // already saved in the import file. // if (processBonusFeats) { // final double bonusFeats = aPC.getBonusFeatsForNewLevel(this); // if (bonusFeats > 0) { // aPC.adjustFeats(bonusFeats); // } // } 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()) { // // Ask for stat increase after skill points have been calculated // 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); } } } // // Allow exchange of classes only when assign 1st level // if (containsKey(ObjectKey.EXCHANGE_LEVEL) && (aPC.getLevel(this) == 1) && !aPC.isImporting()) { ExchangeLevelApplication.exchangeLevels(aPC, this); } return true; }