/** Construct the list of available spells for the character. */ private void buildAvailableNodes() { availableSpellNodes.clearContents(); // Scan character classes for spell classes List<PCClass> classList = getCharactersSpellcastingClasses(); // Look at each spell on each spellcasting class for (PCClass pcClass : classList) { DoubleKeyMapToList<SpellFacade, String, SpellNode> existingSpells = buildExistingSpellMap(availableSpellNodes, pcClass); for (Spell spell : pc.getAllSpellsInLists(charDisplay.getSpellLists(pcClass))) { // Create SpellNodeImpl for each spell CharacterSpell charSpell = new CharacterSpell(pcClass, spell); SpellFacadeImplem spellImplem = new SpellFacadeImplem(pc, spell, charSpell, null); HashMapToList<CDOMList<Spell>, Integer> levelInfo = pc.getSpellLevelInfo(spell); for (CDOMList<Spell> spellList : charDisplay.getSpellLists(pcClass)) { List<Integer> levels = levelInfo.getListFor(spellList); if (levels != null) { for (Integer level : levels) { SpellNodeImpl node = new SpellNodeImpl(spellImplem, pcClass, String.valueOf(level), null); if (!existingSpells.containsInList(spellImplem, node.getSpellLevel(), node)) { // Add to list availableSpellNodes.addElement(node); } } } } } } }
/* (non-Javadoc) * @see pcgen.core.facade.SpellSupportFacade#addKnownSpell(pcgen.core.facade.SpellSupportFacade.SpellNode) */ @Override public void addKnownSpell(SpellNode spell) { SpellNode node = addSpellToCharacter(spell, Globals.getDefaultSpellBook(), new ArrayList<>()); if (node != null) { allKnownSpellNodes.addElement(node); knownSpellNodes.addElement(node); if (!StringUtils.isEmpty(charDisplay.getSpellBookNameToAutoAddKnown())) { addToSpellBook(node, charDisplay.getSpellBookNameToAutoAddKnown()); } } updateSpellsTodo(); pcFacade.refreshAvailableTempBonuses(); }
/* (non-Javadoc) * @see pcgen.core.prereq.PrerequisiteTest#passes(pcgen.core.PlayerCharacter) */ @Override public int passes(final Prerequisite prereq, final CharacterDisplay display, CDOMObject source) { // // If game mode doesn't support alignment, then pass the prereq // int runningTotal = 0; if (Globals.getGameModeAlignmentText().length() == 0) { runningTotal = 1; } else { CDOMSingleRef<PCAlignment> deityAlign = null; // $NON-NLS-1$ Deity deity = display.getDeity(); if (deity != null) { deityAlign = deity.get(ObjectKey.ALIGNMENT); } if (deityAlign != null) { String desiredAlignIdentifier = prereq.getOperand(); PCAlignment desiredAlign = getPCAlignment(desiredAlignIdentifier); if (desiredAlign.equals(deityAlign.get())) { runningTotal = 1; } } } return countedTotal(prereq, runningTotal); }
/** * Create a new instance of SpellSupportFacadeImpl to manage the display and update of a * character's spells. * * @param pc The character we are managing. * @param delegate The delegate class for UI display. * @param dataSet The current data being used. * @param todoManager The user tasks tracker. * @param pcFacade The character facade. */ public SpellSupportFacadeImpl( PlayerCharacter pc, UIDelegate delegate, DataSetFacade dataSet, TodoManager todoManager, CharacterFacadeImpl pcFacade) { this.pc = pc; this.infoFactory = pcFacade.getInfoFactory(); this.charDisplay = pc.getDisplay(); this.delegate = delegate; this.dataSet = dataSet; this.todoManager = todoManager; this.pcFacade = pcFacade; rootNodeMap = new HashMap<>(); spellBookNames = new DefaultListFacade<>(); defaultSpellBook = new DefaultReferenceFacade<>(charDisplay.getSpellBookNameToAutoAddKnown()); availableSpellNodes = new DefaultListFacade<>(); buildAvailableNodes(); allKnownSpellNodes = new DefaultListFacade<>(); knownSpellNodes = new DefaultListFacade<>(); preparedSpellNodes = new DefaultListFacade<>(); bookSpellNodes = new DefaultListFacade<>(); preparedSpellLists = new ArrayList<>(); spellBooks = new ArrayList<>(); buildKnownPreparedNodes(); updateSpellsTodo(); }
/** * Get the LOAD sub token * * @param display * @return the LOAD sub token */ public static String getLoadToken(CharacterDisplay display) { Load load = display.getLoadType(); switch (load) { case LIGHT: return CoreUtility.capitalizeFirstLetter(Load.LIGHT.toString()); case MEDIUM: return CoreUtility.capitalizeFirstLetter(Load.MEDIUM.toString()); case HEAVY: return CoreUtility.capitalizeFirstLetter(Load.HEAVY.toString()); case OVERLOAD: return CoreUtility.capitalizeFirstLetter(Load.OVERLOAD.toString()); default: Logging.errorPrint( "Unknown load constant detected in TokenTotal.getLoadToken, the constant was " + load + "."); return "Unknown"; } }
private void buildKnownPreparedSpellsForCDOMObject(CDOMObject pObject) { Collection<? extends CharacterSpell> sp = charDisplay.getCharacterSpells(pObject); List<CharacterSpell> cSpells = new ArrayList<>(sp); // Add in the spells granted by objects pc.addBonusKnownSpellsToList(pObject, cSpells); PCClass pcClass = (PCClass) (pObject instanceof PCClass ? pObject : null); for (CharacterSpell charSpell : cSpells) { for (SpellInfo spellInfo : charSpell.getInfoList()) { // Create SpellNodeImpl for each spell String book = spellInfo.getBook(); boolean isKnown = Globals.getDefaultSpellBook().equals(book); SpellFacadeImplem spellImplem = new SpellFacadeImplem(pc, charSpell.getSpell(), charSpell, spellInfo); SpellNodeImpl node; if (pcClass != null) { node = new SpellNodeImpl( spellImplem, pcClass, String.valueOf(spellInfo.getActualLevel()), getRootNode(book)); } else { node = new SpellNodeImpl( spellImplem, String.valueOf(spellInfo.getActualLevel()), getRootNode(book)); } if (spellInfo.getTimes() > 1) { node.addCount(spellInfo.getTimes() - 1); } boolean isSpellBook = charDisplay.getSpellBookByName(book).getType() == SpellBook.TYPE_SPELL_BOOK; // Add to list if (isKnown) { allKnownSpellNodes.addElement(node); knownSpellNodes.addElement(node); } else if (isSpellBook) { bookSpellNodes.addElement(node); } else if (pObject instanceof Race) { allKnownSpellNodes.addElement(node); } else { preparedSpellNodes.addElement(node); } } } }
/** * Set the spell book to hold any new known spells. * * @param bookName The name of the new default spell book. */ @Override public void setDefaultSpellBook(String bookName) { SpellBook book = charDisplay.getSpellBookByName(bookName); if (book == null || book.getType() != SpellBook.TYPE_SPELL_BOOK) { return; } pc.setSpellBookNameToAutoAddKnown(bookName); defaultSpellBook.set(bookName); }
@Override public void setBonus(int bonus) { String initiativeVar = ControlUtilities.getControlToken(Globals.getContext(), CControl.INITIATIVE); if (initiativeVar == null) { this.incrementalBonus = bonus - display.processOldInitiativeMod(); } else { this.incrementalBonus = bonus - ((Number) pc.getGlobal(initiativeVar)).intValue(); } setCurrentInitiative(roll + getModifier() + mod); }
/** * Get FOLLOWERLIST Token * * @param display The character to be queried * @return The list of followers. */ public static String getFollowerListToken(CharacterDisplay display) { StringBuilder buf = new StringBuilder(); boolean needComma = false; for (Follower aF : display.getFollowerList()) { for (PlayerCharacter nPC : Globals.getPCList()) { CharacterDisplay nDisplay = nPC.getDisplay(); if (aF.getFileName().equals(nDisplay.getFileName())) { if (needComma) { buf.append(", "); } buf.append(FileAccess.filterString(nDisplay.getName())); needComma = true; } } } return buf.toString(); }
private List<PCClass> getCharactersSpellcastingClasses() { List<PCClass> castingClasses = new ArrayList<>(); Collection<PCClass> classes = charDisplay.getClassSet(); for (PCClass pcClass : classes) { if (pcClass.get(FactKey.valueOf("SpellType")) != null) { SpellSupportForPCClass spellSupport = pc.getSpellSupport(pcClass); if (spellSupport.canCastSpells(pc) || spellSupport.hasKnownList()) { castingClasses.add(pcClass); } } } return castingClasses; }
/** * Get a pipe separated list of creature types for this PC (defaults to humanoid). * * @return the list of types */ @Deprecated public static String getCritterType(CharacterDisplay display) { final StringBuilder critterType = new StringBuilder(); // Not too sure about this if, but that's what the previous code // implied... Race race = display.getRace(); if (race != null) { critterType.append(race.getType()); } else { critterType.append("Humanoid"); } for (PCTemplate t : display.getTemplateSet()) { final String aType = t.getType(); if (!"".equals(aType)) { critterType.append('|').append(aType); } } return critterType.toString(); }
/* (non-Javadoc) * @see pcgen.core.prereq.PrerequisiteTest#passes(pcgen.core.PlayerCharacter) */ @Override public int passes(final Prerequisite prereq, final CharacterDisplay display, CDOMObject source) throws PrerequisiteException { int runningTotal; try { final int targetHands = Integer.parseInt(prereq.getOperand()); runningTotal = prereq.getOperator().compare(display.getHands(), targetHands); } catch (NumberFormatException nfe) { throw new PrerequisiteException( LanguageBundle.getFormattedString( "PreHands.error.badly_formed", prereq.getOperand())); // $NON-NLS-1$ } return countedTotal(prereq, runningTotal); }
/** Construct the list of spells the character knows, has prepared or has in a spell book. */ private void buildKnownPreparedNodes() { allKnownSpellNodes.clearContents(); knownSpellNodes.clearContents(); bookSpellNodes.clearContents(); preparedSpellNodes.clearContents(); // Ensure spell information is up to date pc.getSpellList(); // Scan character classes for spell classes List<PCClass> classList = getCharactersSpellcastingClasses(); List<PObject> pobjList = new ArrayList<>(classList); // Include spells from race etc pobjList.add(charDisplay.getRace()); // Look at each spell on each spellcasting class for (PObject pcClass : pobjList) { buildKnownPreparedSpellsForCDOMObject(pcClass); } spellBooks.clear(); spellBookNames.clearContents(); for (SpellBook spellBook : charDisplay.getSpellBooks()) { if (spellBook.getType() == SpellBook.TYPE_PREPARED_LIST) { DummySpellNodeImpl spellListNode = new DummySpellNodeImpl(getRootNode(spellBook.getName())); preparedSpellLists.add(spellListNode); addDummyNodeIfSpellListEmpty(spellBook.getName()); } else if (spellBook.getType() == SpellBook.TYPE_SPELL_BOOK) { DummySpellNodeImpl spellListNode = new DummySpellNodeImpl(getRootNode(spellBook.getName())); spellBooks.add(spellListNode); addDummyNodeIfSpellBookEmpty(spellBook.getName()); spellBookNames.addElement(spellBook.getName()); } } }
@Override public int getBonus() { String initiativeVar = ControlUtilities.getControlToken(Globals.getContext(), CControl.INITIATIVE); String initiativeStatVar = ControlUtilities.getControlToken(Globals.getContext(), CControl.INITIATIVESTAT); if (initiativeVar == null) { PCStat dex = Globals.getContext() .getReferenceContext() .silentlyGetConstructedCDOMObject(PCStat.class, "DEX"); return display.processOldInitiativeMod() - pc.getStatModFor(dex) + incrementalBonus; } return ((Number) pc.getGlobal(initiativeVar)).intValue() - ((Number) pc.getGlobal(initiativeStatVar)).intValue() + incrementalBonus; }
private RootNodeImpl getRootNode(String bookName) { if (Globals.getDefaultSpellBook().equals(bookName)) { return null; } RootNodeImpl rootNode = rootNodeMap.get(bookName); if (rootNode == null) { SpellBook book = charDisplay.getSpellBookByName(bookName); if (book == null) { return null; } rootNode = new RootNodeImpl(book); rootNodeMap.put(bookName, rootNode); } return rootNode; }
/* * (non-Javadoc) * * @see * pcgen.core.prereq.PrerequisiteTest#passes(pcgen.core.PlayerCharacter) */ @Override public int passes(final Prerequisite prereq, final CharacterDisplay display, CDOMObject source) { final int reqnumber = Integer.parseInt(prereq.getOperand()); final String requiredRaceType = prereq.getKey(); int runningTotal = 0; try { RaceType preRaceType = RaceType.valueOf(requiredRaceType); if (preRaceType.equals(display.getRace().get(ObjectKey.RACETYPE))) { runningTotal++; } } catch (IllegalArgumentException e) { // Can't match } if (getCritterType(display).indexOf(requiredRaceType) >= 0) { runningTotal++; } runningTotal = prereq.getOperator().compare(runningTotal, reqnumber); return countedTotal(prereq, runningTotal); }
private void updateSpellsTodo() { boolean hasFree = false; for (PCClass aClass : charDisplay.getClassSet()) { if (pc.getSpellSupport(aClass).hasKnownList() || pc.getSpellSupport(aClass).hasKnownSpells(pc)) { int highestSpellLevel = pc.getSpellSupport(aClass).getHighestLevelSpell(pc); for (int i = 0; i <= highestSpellLevel; ++i) { if (pc.availableSpells(i, aClass, Globals.getDefaultSpellBook(), true, false) || pc.availableSpells(i, aClass, Globals.getDefaultSpellBook(), true, true)) { hasFree = true; break; } } } } if (hasFree) { todoManager.addTodo(new TodoFacadeImpl(Tab.SPELLS, "Known", "in_splTodoRemain", 120)); } else { todoManager.removeTodo("in_splTodoRemain"); } }
@Override public Float resolve(CharacterDisplay display) { String CompString = display.getSafeStringFor(StringKey.MISC_COMPANIONS); List<String> companions = Arrays.asList(CompString.split("\r?\n")); return (float) companions.size(); }
@Override public void exportSpells() { final String template = PCGenSettings.getInstance().getProperty(PCGenSettings.SELECTED_SPELL_SHEET_PATH); if (StringUtils.isEmpty(template)) { delegate.showErrorMessage( Constants.APPLICATION_NAME, LanguageBundle.getString("in_spellNoSheet")); // $NON-NLS-1$ return; } String ext = template.substring(template.lastIndexOf('.')); // Get the name of the file to output to. JFileChooser fcExport = new JFileChooser(); fcExport.setCurrentDirectory(new File(PCGenSettings.getPcgDir())); fcExport.setDialogTitle( LanguageBundle.getString("InfoSpells.export.spells.for") + charDisplay.getDisplayName()); // $NON-NLS-1$ if (fcExport.showSaveDialog(null) != JFileChooser.APPROVE_OPTION) { return; } final String aFileName = fcExport.getSelectedFile().getAbsolutePath(); if (aFileName.length() < 1) { delegate.showErrorMessage( Constants.APPLICATION_NAME, LanguageBundle.getString("InfoSpells.must.set.filename")); // $NON-NLS-1$ return; } try { final File outFile = new File(aFileName); if (outFile.isDirectory()) { delegate.showErrorMessage( Constants.APPLICATION_NAME, LanguageBundle.getString("InfoSpells.can.not.overwrite.directory")); // $NON-NLS-1$ return; } if (outFile.exists()) { int reallyClose = JOptionPane.showConfirmDialog( null, LanguageBundle.getFormattedString( "InfoSpells.confirm.overwrite", outFile.getName()), // $NON-NLS-1$ LanguageBundle.getFormattedString("InfoSpells.overwriting", outFile.getName()), JOptionPane.YES_NO_OPTION); // $NON-NLS-1$ if (reallyClose != JOptionPane.YES_OPTION) { return; } } // Output the file File templateFile = new File(template); boolean success; if (ExportUtilities.isPdfTemplate(templateFile)) { success = BatchExporter.exportCharacterToPDF(pcFacade, outFile, templateFile); } else { success = BatchExporter.exportCharacterToNonPDF(pcFacade, outFile, templateFile); } if (!success) { delegate.showErrorMessage( Constants.APPLICATION_NAME, LanguageBundle.getFormattedString( "InfoSpells.export.failed", charDisplay.getDisplayName())); // $NON-NLS-1$ } } catch (Exception ex) { Logging.errorPrint( LanguageBundle.getFormattedString( "InfoSpells.export.failed", charDisplay.getDisplayName()), ex); //$NON-NLS-1$ delegate.showErrorMessage( Constants.APPLICATION_NAME, LanguageBundle.getFormattedString( "InfoSpells.export.failed.retry", charDisplay.getDisplayName())); // $NON-NLS-1$ } }
/** * Get the CAPACITY sub token * * @param display * @return the CAPACITY sub token */ public static String getCapacityToken(CharacterDisplay display) { return Globals.getGameModeUnitSet().displayWeightInUnitSet(display.getMaxLoad().doubleValue()); }
/** * Get the WEIGHT sub token * * @param display * @return the WEIGHT sub token */ public static String getWeightToken(CharacterDisplay display) { return Globals.getGameModeUnitSet().displayWeightInUnitSet(display.totalWeight().doubleValue()) + Globals.getGameModeUnitSet().getWeightUnit(); }
private static String _writeArmorProperty(Equipment eq, String property, PlayerCharacter aPC) { CharacterDisplay display = aPC.getDisplay(); StringBuilder ret = new StringBuilder(); if (property.startsWith("NAME")) { if (eq.isEquipped() && !property.equals("NAMENOSTAR")) { ret.append("*"); } ret.append(OutputNameFormatting.parseOutputName(eq, aPC)); ret.append(eq.getAppliedName()); } else if (property.startsWith("OUTPUTNAME")) { // TODO this appears to be the same as above. Should be refactored if (eq.isEquipped()) { ret.append("*"); } ret.append(OutputNameFormatting.parseOutputName(eq, aPC)); ret.append(eq.getAppliedName()); } else if (property.startsWith("TOTALAC") || property.startsWith("ACBONUS")) { // adjustments for new equipment modifier // EQMARMOR|AC|x|TYPE=ENHANCEMENT changed to COMBAT|AC|x|TYPE=Armor.ENHANCEMENT // FileAccess.write(output, Delta.toString(eq.getACMod())); String acMod = aPC.getControl(CControl.EQACMOD); if (acMod != null) { Object o = aPC.getLocal(eq, acMod); int intValue = ((Number) o).intValue(); ret.append(Delta.toString(intValue)); } else { ret.append(Delta.toString((int) eq.bonusTo(aPC, "COMBAT", "AC", true))); } } else if (property.startsWith("BASEAC")) { // adjustments for new equipment modifier // EQMARMOR|AC|x|TYPE=ENHANCEMENT changed to COMBAT|AC|x|TYPE=Armor.ENHANCEMENT // FileAccess.write(output, Delta.toString(eq.getACMod())); String baseMod = aPC.getControl(CControl.EQBASEACMOD); if (baseMod != null) { Object o = aPC.getLocal(eq, baseMod); int intValue = ((Number) o).intValue(); ret.append(Delta.toString(intValue)); } else { ret.append(Delta.toString((int) BonusCalc.charBonusTo(eq, "COMBAT", "AC", aPC))); } } else if (property.startsWith("MAXDEX")) { final int iMax = EqToken.getMaxDexTokenInt(aPC, eq); if (iMax != Constants.MAX_MAXDEX) { ret.append(Delta.toString(iMax)); } } else if (property.startsWith("ACCHECK")) { ret.append(Delta.toString(EqToken.getAcCheckTokenInt(aPC, eq))); } else if (property.startsWith("EDR")) { ret.append(Delta.toString(EqToken.getEdrTokenInt(aPC, eq))); } else if (property.startsWith("ISTYPE")) { if (eq.isType(property.substring(property.indexOf(".") + 1))) { ret.append("TRUE"); } else { ret.append("FALSE"); } } else if (property.startsWith("SPELLFAIL")) { ret.append(EqToken.getSpellFailureTokenInt(aPC, eq)); } else if (property.startsWith("MOVE")) { final StringTokenizer aTok = new StringTokenizer(eq.moveString(), ",", false); String tempString = ""; if (("M".equals(display.getSize()) || "S".equals(display.getSize())) && (aTok.countTokens() > 0)) { tempString = aTok.nextToken(); if ("S".equals(display.getSize()) && (aTok.countTokens() > 1)) { tempString = aTok.nextToken(); } } ret.append(tempString); } else if (property.startsWith("SPROP")) { ret.append(eq.getSpecialProperties(aPC)); } else if (property.startsWith("TYPE")) { String typeString = ""; if (eq.isLight()) { typeString = "Light"; } else if (eq.isMedium()) { typeString = "Medium"; } else if (eq.isHeavy()) { typeString = "Heavy"; } else if (eq.isShield()) { typeString = "Shield"; } else if (eq.isExtra()) { typeString = "Extra"; } ret.append(typeString); } else if (property.startsWith("WT")) { ret.append(BigDecimalHelper.trimZeros(eq.getWeight(aPC).toString())); } return ret.toString(); }
// TODO Refactor this with all the equipment tests. @Override public int passes(final Prerequisite prereq, final CharacterDisplay display, CDOMObject source) throws PrerequisiteException { final int number; try { number = Integer.parseInt(prereq.getOperand()); } catch (NumberFormatException e) { throw new PrerequisiteException( LanguageBundle.getFormattedString( "PreItem.error.bad_operand", prereq.toString())); // $NON-NLS-1$ } int runningTotal = 0; if (display.hasEquipment()) { // Work out exactlywhat we are going to test. final String aString = prereq.getKey(); List<String> typeList = null; if (aString.startsWith(Constants.LST_TYPE_EQUAL) || aString.startsWith(Constants.LST_TYPE_DOT)) { String stripped = aString.substring(Constants.SUBSTRING_LENGTH_FIVE); typeList = CoreUtility.split(stripped, '.'); } for (Equipment eq : display.getEquipmentSet()) { if (typeList != null) { // Check to see if the equipment matches // all of the types in the requested list; boolean bMatches = true; for (int i = 0, x = typeList.size(); i < x; ++i) { if (!eq.isType(typeList.get(i))) { bMatches = false; break; } } if (bMatches) { runningTotal++; } } else { // not a TYPE string final String eqName = eq.getName().toUpperCase(); if (aString.indexOf('%') >= 0) { // handle wildcards (always assume // they end the line) final int percentPos = aString.indexOf('%'); final String substring = aString.substring(0, percentPos).toUpperCase(); if ((eqName.startsWith(substring))) { ++runningTotal; break; } } else if (eqName.equalsIgnoreCase(aString)) { // just a straight String compare ++runningTotal; break; } } } } runningTotal = prereq.getOperator().compare(runningTotal, number); return countedTotal(prereq, runningTotal); }
/* (non-Javadoc) * @see pcgen.core.facade.SpellSupportFacade#getClassInfo(pcgen.core.facade.ClassFacade) */ @Override public String getClassInfo(ClassFacade spellcaster) { if (!(spellcaster instanceof PCClass)) { return ""; } PCClass aClass = (PCClass) spellcaster; SpellSupportForPCClass spellSupport = pc.getSpellSupport(aClass); int highestSpellLevel = spellSupport.getHighestLevelSpell(pc); final HtmlInfoBuilder b = new HtmlInfoBuilder(); b.append("<table border=1><tr><td><font size=-2><b>"); // $NON-NLS-1$ b.append(OutputNameFormatting.piString(aClass, false)).append(" ["); // $NON-NLS-1$ b.append( String.valueOf( charDisplay.getLevel(aClass) + (int) pc.getTotalBonusTo("PCLEVEL", aClass.getKeyName()))); // $NON-NLS-1$ b.append("]</b></font></td>"); // $NON-NLS-1$ for (int i = 0; i <= highestSpellLevel; ++i) { b.append("<td><font size=-2><b><center> "); // $NON-NLS-1$ b.append(String.valueOf(i)); b.append(" </b></center></font></td>"); // $NON-NLS-1$ } b.append("</tr>"); // $NON-NLS-1$ b.append("<tr><td><font size=-1><b>Cast</b></font></td>"); // $NON-NLS-1$ for (int i = 0; i <= highestSpellLevel; ++i) { b.append("<td><font size=-1><center>"); // $NON-NLS-1$ b.append(getNumCast(aClass, i, pc)); b.append("</center></font></td>"); // $NON-NLS-1$ } b.append("</tr>"); // $NON-NLS-1$ // Making sure KnownList can be handled safely and produces the correct behaviour if (spellSupport.hasKnownList() || spellSupport.hasKnownSpells(pc)) { b.append("<tr><td><font size=-1><b>Known</b></font></td>"); // $NON-NLS-1$ for (int i = 0; i <= highestSpellLevel; ++i) { final int a = spellSupport.getKnownForLevel(i, pc); final int bonus = spellSupport.getSpecialtyKnownForLevel(i, pc); b.append("<td><font size=-1><center>"); // $NON-NLS-1$ b.append(String.valueOf(a)); if (bonus > 0) { b.append('+').append(Integer.toString(bonus)); } b.append("</center></font></td>"); // $NON-NLS-1$ } b.append("</tr>"); // $NON-NLS-1$ } b.append("<tr><td><font size=-1><b>DC</b></font></td>"); // $NON-NLS-1$ for (int i = 0; i <= highestSpellLevel; ++i) { b.append("<td><font size=-1><center>"); // $NON-NLS-1$ b.append(String.valueOf(getDC(aClass, i, pc))); b.append("</center></font></td>"); // $NON-NLS-1$ } b.append("</tr></table>"); // $NON-NLS-1$ b.appendI18nElement("InfoSpells.caster.type", aClass.getSpellType()); // $NON-NLS-1$ b.appendLineBreak(); b.appendI18nElement("InfoSpells.stat.bonus", aClass.getSpellBaseStat()); // $NON-NLS-1$ if (pc.hasAssocs(aClass, AssociationKey.SPECIALTY) || charDisplay.hasDomains()) { boolean needComma = false; StringBuilder schoolInfo = new StringBuilder(); String spec = pc.getAssoc(aClass, AssociationKey.SPECIALTY); if (spec != null) { schoolInfo.append(spec); needComma = true; } for (Domain d : charDisplay.getSortedDomainSet()) { if (needComma) { schoolInfo.append(','); } needComma = true; schoolInfo.append(d.getKeyName()); } b.appendLineBreak(); b.appendI18nElement("InfoSpells.school", schoolInfo.toString()); // $NON-NLS-1$ } Set<String> set = new TreeSet<>(); for (SpellProhibitor sp : aClass.getSafeListFor(ListKey.PROHIBITED_SPELLS)) { set.addAll(sp.getValueList()); } Collection<? extends SpellProhibitor> prohibList = charDisplay.getProhibitedSchools(aClass); if (prohibList != null) { for (SpellProhibitor sp : prohibList) { set.addAll(sp.getValueList()); } } if (!set.isEmpty()) { b.appendLineBreak(); b.appendI18nElement( "InfoSpells.prohibited.school", //$NON-NLS-1$ StringUtil.join(set, ",")); // $NON-NLS-1$ } String bString = SourceFormat.getFormattedString(aClass, Globals.getSourceDisplay(), true); if (bString.length() > 0) { b.appendLineBreak(); b.appendI18nElement("in_source", bString); // $NON-NLS-1$ } return b.toString(); }