/* * PCGVer2Creator.java * Copyright 2002 (C) Thomas Behr <ravenlock@gmx.de> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Created on March 19, 2002, 4:15 PM * * Current Ver: $Revision$ * */ package pcgen.io; import java.awt.Rectangle; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.TreeSet; import org.apache.commons.lang3.StringUtils; import pcgen.base.lang.StringUtil; import pcgen.cdom.base.CDOMList; import pcgen.cdom.base.CDOMListObject; import pcgen.cdom.base.CDOMObject; import pcgen.cdom.base.CDOMReference; import pcgen.cdom.base.Category; import pcgen.cdom.base.Constants; import pcgen.cdom.base.PersistentTransitionChoice; import pcgen.cdom.base.SelectableSet; import pcgen.cdom.base.TransitionChoice; import pcgen.cdom.content.CNAbility; import pcgen.cdom.enumeration.AssociationKey; import pcgen.cdom.enumeration.AssociationListKey; import pcgen.cdom.enumeration.BiographyField; import pcgen.cdom.enumeration.ListKey; import pcgen.cdom.enumeration.Nature; import pcgen.cdom.enumeration.ObjectKey; import pcgen.cdom.enumeration.PCStringKey; import pcgen.cdom.helper.CNAbilitySelection; import pcgen.cdom.helper.ClassSource; import pcgen.cdom.inst.PCClassLevel; import pcgen.cdom.list.ClassSpellList; import pcgen.cdom.reference.CDOMSingleRef; import pcgen.core.Ability; import pcgen.core.AbilityCategory; import pcgen.core.BonusManager; import pcgen.core.BonusManager.TempBonusInfo; import pcgen.core.ChronicleEntry; import pcgen.core.Deity; import pcgen.core.Description; import pcgen.core.Domain; import pcgen.core.Equipment; import pcgen.core.GameMode; import pcgen.core.Globals; import pcgen.core.Kit; import pcgen.core.Language; import pcgen.core.NoteItem; import pcgen.core.PCAlignment; import pcgen.core.PCClass; import pcgen.core.PCStat; import pcgen.core.PCTemplate; import pcgen.core.PlayerCharacter; import pcgen.core.SettingsHandler; import pcgen.core.Skill; import pcgen.core.SpecialAbility; import pcgen.core.SpellProhibitor; import pcgen.core.WeaponProf; import pcgen.core.analysis.SpellLevel; import pcgen.core.bonus.BonusObj; import pcgen.core.character.CharacterSpell; import pcgen.core.character.EquipSet; import pcgen.core.character.Follower; import pcgen.core.character.SpellBook; import pcgen.core.character.SpellInfo; import pcgen.core.display.BonusDisplay; import pcgen.core.display.CharacterDisplay; import pcgen.core.pclevelinfo.PCLevelInfo; import pcgen.core.pclevelinfo.PCLevelInfoStat; import pcgen.core.spell.Spell; import pcgen.facade.core.CampaignFacade; import pcgen.system.PCGenPropBundle; import pcgen.util.FileHelper; import pcgen.util.Logging; import pcgen.util.StringPClassUtil; /** * {@code PCGVer2Creator}<br> * Creates a line oriented format. * Each line should adhere to the following grammar:<br> * * <i>line</i> := EMPTY | <i>comment</i> | <i>taglist</i> * <i>comment</i> := '#' STRING * <i>taglist</i> := tag ('|' tag)* * <i>tag</i> := simpletag | nestedtag * <i>nestedtag</i> := TAGNAME ':' '[' taglist ']' * <i>simpletag</i> := TAGNAME ':' TAGVALUE * * @author Thomas Behr 19-03-02 */ public final class PCGVer2Creator { /* * DO NOT CHANGE line separator. * Need to keep the Unix line separator to ensure cross-platform portability. * * author: Thomas Behr 2002-11-13 */ private final PlayerCharacter thePC; private final CharacterDisplay charDisplay; private GameMode mode; private List<? extends CampaignFacade> campaigns; /** * Constructor * @param aPC */ public PCGVer2Creator(final PlayerCharacter aPC, GameMode mode, List<? extends CampaignFacade> campaigns) { thePC = aPC; charDisplay = aPC.getDisplay(); this.mode = mode; this.campaigns = campaigns; } /** * create PCG string for a given PlayerCharacter * * <br>author: Thomas Behr 19-03-02 * * @return a String in PCG format, containing all information * PCGen associates with a given PlayerCharacter */ public String createPCGString() { // Guess that this should be about 1000 StringBuilder buffer = new StringBuilder(1000); appendPCGVersionLine(buffer); /* * #System Information * CAMPAIGNS:>:-delimited list< * VERSION:x.x.x * ROLLMETHOD:xxx * PURCHASEPOINTS:Y or N|TYPE:>living City, Living greyhawk, etc< * UNLIMITEDPOOLCHECKED:Y or N * POOLPOINTS:>numeric value 0-?< * GAMEMODE:DnD * TABLABEL:0 * AUTOSPELLS:Y or N * AUTOCOMPANIONS:Y or N * * hmmm, better have * CAMPAIGNS:>campaign_name<|CAMPAIGNS:>campaign_name<|... */ appendNewline(buffer); appendComment("System Information", buffer); //$NON-NLS-1$ //appendCampaignLineOldFormat(buffer); appendCampaignLine(buffer); appendVersionLine(buffer); appendRollMethodLine(buffer); appendPurchasePointsLine(buffer); appendCharacterTypeLine(buffer); appendPreviewSheetLine(buffer); //appendUnlimitedPoolCheckedLine(buffer); appendPoolPointsLine(buffer); appendGameModeLine(buffer); appendTabLabelLine(buffer); appendAutoSpellsLine(buffer); appendUseHigherSpellSlotsLines(buffer); appendLoadCompanionLine(buffer); appendUseTempModsLine(buffer); appendOutputSheetsLines(buffer); appendAutoSortLines(buffer); appendSkillFilterLine(buffer); appendGearCostSizeLines(buffer); /* * #Character Bio * CHARACTERNAME:Code Monkey * TABNAME:Code Monkey the Best Ever No Really! * PLAYERNAME:Jason Monkey * HEIGHT:75 * WEIGHT:198 * AGE:17 * GENDER:text * HANDED:text * SKIN:text * EYECOLOR:text * HAIRCOLOR:text * HAIRSTYLE:text * LOCATION:text * CITY:text * PERSONALITYTRAIT1:text * PERSONALITYTRAIT2:text * SPEECHPATTERN:text * PHOBIAS:text * INTERESTS:text * CATCHPHRASE:text */ appendNewline(buffer); appendComment("Character Bio", buffer); //$NON-NLS-1$ appendCharacterNameLine(buffer); appendTabNameLine(buffer); appendPlayerNameLine(buffer); appendHeightLine(buffer); appendWeightLine(buffer); appendAgeLine(buffer); appendGenderLine(buffer); appendHandedLine(buffer); appendSkinColorLine(buffer); appendEyeColorLine(buffer); appendHairColorLine(buffer); appendHairStyleLine(buffer); appendLocationLine(buffer); appendResidenceLine(buffer); appendBirthdayLine(buffer); appendBirthplaceLine(buffer); appendPersonalityTrait1Line(buffer); appendPersonalityTrait2Line(buffer); appendSpeechPatternLine(buffer); appendPhobiasLine(buffer); appendInterestsLine(buffer); appendCatchPhraseLine(buffer); appendPortraitLine(buffer); /* * #Character Attributes * STAT:STR=18 * STAT:DEX=18 * STAT:CON=18 * STAT:INT=18 * STAT:WIS=18 * STAT:CHA=18 * ALIGN:LG * RACE:Human * * hmmm better have * STAT:STR|SCORE:18 */ appendNewline(buffer); appendComment("Character Attributes", buffer); //$NON-NLS-1$ appendStatLines(buffer); appendAlignmentLine(buffer); appendRaceLine(buffer); appendFavoredClassLine(buffer); /* * #Character Class(es) * CLASS:Fighter|LEVEL=3 * CLASSABILITIESLEVEL:Fighter=1(>This would only display up to the level the character has already,) * CLASSABILITIESLEVEL:Fighter=2(>with any special abilities not covered by other areas,) * CLASSABILITIESLEVEL:Fighter=3(>such as skills, feats, etc., but would list SA's, and the like<) * CLASS:Wizard|LEVEL=1 * CLASSABILITIESLEVEL:Wizard=1(SA's, MEMORIZE:Y, etc) * * hmmm, better have * CLASS:Fighter|LEVEL:3|SKILLPOOL:0 * CLASS:Wizard|LEVEL:1|SKILLPOOL:0|CANCASTPERDAY:1,1 */ appendNewline(buffer); appendComment("Character Class(es)", buffer); //$NON-NLS-1$ appendClassLines(buffer); /* * #Character Experience * EXPERIENCE:6000 */ appendNewline(buffer); appendComment("Character Experience", buffer); //$NON-NLS-1$ appendExperienceLine(buffer); appendExperienceTableLine(buffer); /* * #Character Templates * TEMPLATESAPPLIED:If any, else this would just have the comment line, and skip to the next */ appendNewline(buffer); appendComment("Character Templates", buffer); //$NON-NLS-1$ appendTemplateLines(buffer); appendNewline(buffer); appendComment("Character Region", buffer); //$NON-NLS-1$ appendRegionLine(buffer); /* * #Character Skills * CLASSBOUGHT:Fighter * SKILL:Alchemy|CROSSCLASS:Y|COST:2|RANK:7 (Should be Obvious what each of these does, I hope ;p) * SKILL:Survival|CLASS:Y|COST:1|SYNERGY:Wilderness Lore=5=2|RANK:10 * CLASSBOUGHT:Wizard * SKILL:Spellcraft|CLASS:Y|COST:1|RANK7 * * * hmmm, better have * SKILL:Alchemy|SYNERGY:....|OUTPUTORDER:1|CLASSBOUGHT:[CLASS:FIGHTER|RANKS:7|COST:2|CLASSSKILL:N] * SKILL:Spellcraft|SYNERGY:....|OUTPUTORDER:1|CLASSBOUGHT:[CLASS:WIZARD|RANKS:7|COST:1|CLASSSKILL:Y] */ appendNewline(buffer); appendComment("Character Skills", buffer); //$NON-NLS-1$ appendSkillLines(buffer); /* * #Character Languages */ appendNewline(buffer); appendComment("Character Languages", buffer); //$NON-NLS-1$ appendLanguageLine(buffer); /* * Anything that is already Pipe Delimited should be in * parenthesis to avoid confusion on PCGen's part * * #Character Feats * FEAT:Alertness|TYPE:General|(BONUS:SKILL|Listen,Spot|2)|DESC:+2 on Listen and Spot checks * * hmmm, better have colons and pipes encoded as entities * FEAT:Alertness|TYPE:General|SAVE:BONUS:SKILL&pipe;Listen,Spot&pipe;2|DESC:+2 on Listen and Spot checks */ appendNewline(buffer); appendComment("Character Feats", buffer); //$NON-NLS-1$ appendFeatLines(buffer); appendNewline(buffer); appendComment("Character Abilities", buffer); //$NON-NLS-1$ appendAbilityLines(buffer); /* * #Character Weapon proficiencies */ appendNewline(buffer); appendComment("Character Weapon proficiencies", buffer); //$NON-NLS-1$ appendWeaponProficiencyLines(buffer); /* * This is the REALLY ugly part for all characters as it should contain ALL the information for the equipment * Money goes here as well * * #Character Equipment * EQUIPNAME:Longsword|OUTPUTORDER:2|COST:5|WT:5|QTY:1|>other info< * EQUIPNAME:Backpack|OUTPUTORDER:9|COST:5|WT:5 * EQUIPNAME:Rope (Silk)|OUTPUTORDER:-1|COST:5|WT:5 */ appendNewline(buffer); appendComment("Character Equipment", buffer); //$NON-NLS-1$ appendMoneyLine(buffer); appendEquipmentLines(buffer); appendEquipmentSetLines(buffer); /* * Append Temporary Bonuses */ appendNewline(buffer); appendComment("Temporary Bonuses", buffer); //$NON-NLS-1$ appendTempBonuses(buffer); /* * Append EquipSet Temp Bonuses */ appendNewline(buffer); appendComment("EquipSet Temp Bonuses", buffer); //$NON-NLS-1$ appendEqSetBonuses(buffer); /* * #Character Deity/Domain * DEITY:Yondalla|DEITYDOMAINS:Good,Law,Protection|ALIGNALLOW:013|DESC:Halflings, Protection, Fertility|SYMBOL:None|DEITYFAVWEAP:Sword (Short)|DEITYALIGN:ALIGN:LG * DOMAIN:GOOD|DOMAINGRANTS:>list of abilities< * DOMAINSPELLS:GOOD(>list of level by level spells) * * hmmm, better have * DEITY:Yondalla|DEITYDOMAINS:[DOMAIN:Good|DOMAIN:Law|DOMAIN:Protection]|... * DOMAINSPELLS:GOOD|SPELLLIST:(>list of level by level spells) */ appendNewline(buffer); appendComment("Character Deity/Domain", buffer); //$NON-NLS-1$ appendDeityLine(buffer); appendDomainLines(buffer); /* * This one is what will make spellcasters U G L Y!!! * * #Character Spells Information * CLASS:Wizard|CANCASTPERDAY:2,4(Totals the levels all up + includes attribute bonuses) * SPELLNAME:Blah|SCHOOL:blah|SUBSCHOOL:blah|Etc * * hmmm, moved CANCASTPERDAY to standard class line */ appendNewline(buffer); appendComment("Character Spells Information", buffer); //$NON-NLS-1$ appendSpellBookLines(buffer); appendSpellLines(buffer); appendSpellListLines(buffer); /* * #Character Description/Bio/History * CHARACTERBIO:any text that's in the BIO field * CHARACTERDESC:any text that's in the BIO field */ appendNewline(buffer); appendComment("Character Description/Bio/History", buffer); //$NON-NLS-1$ appendCharacterBioLine(buffer); appendCharacterDescLine(buffer); appendCharacterCompLine(buffer); appendCharacterAssetLine(buffer); appendCharacterMagicLine(buffer); appendCharacterDmNotesLine(buffer); /* * #Kits */ appendNewline(buffer); appendComment("Kits", buffer); //$NON-NLS-1$ appendKitLines(buffer); /* * #Character Master/Followers * MASTER:Mynex|TYPE:Follower|HITDICE:20|FILE:E$\DnD\dnd-chars\ravenlock.pcg * FOLLOWER:Raven|TYPE:Animal Companion|HITDICE:5|FILE:E$\DnD\dnd-chars\raven.pcg */ appendNewline(buffer); appendComment("Character Master/Follower", buffer); //$NON-NLS-1$ appendFollowerLines(buffer); /* * #Character Notes Tab */ appendNewline(buffer); appendComment("Character Notes Tab", buffer); //$NON-NLS-1$ appendNotesLines(buffer); /* * #AgeSet Kit selections */ appendNewline(buffer); appendComment("Age Set Selections", buffer); //$NON-NLS-1$ appendAgeSetLine(buffer); /* * #Campaign History */ appendNewline(buffer); appendComment("Campaign History", buffer); //$NON-NLS-1$ appendCampaignHistoryLines(buffer); /* * #Suppressed fields */ appendNewline(buffer); appendComment("Suppressed Biography Fields", buffer); //$NON-NLS-1$ appendSuppressBioFieldLines(buffer); /* * Add one more newline at end of file */ appendNewline(buffer); // All done! return buffer.toString(); } private void appendCampaignLine(StringBuilder buffer) { String del = Constants.EMPTY_STRING; if (campaigns != null) { for (CampaignFacade campaign : campaigns) { buffer.append(del); buffer.append(IOConstants.TAG_CAMPAIGN).append(':'); buffer.append(campaign.getKeyName()); del = "|"; //$NON-NLS-1$ } buffer.append(IOConstants.LINE_SEP); } } /** * @param buffer */ private void appendSuppressBioFieldLines(StringBuilder buffer) { buffer.append(IOConstants.TAG_SUPPRESS_BIO_FIELDS).append(':'); String delim = Constants.EMPTY_STRING; for (BiographyField field : BiographyField.values()) { if (charDisplay.getSuppressBioField(field)) { buffer.append(delim); buffer.append(field); delim = "|"; //$NON-NLS-1$ } } buffer.append(IOConstants.LINE_SEP); } private GameMode getGameMode() { if (mode != null) { return mode; } else { return SettingsHandler.getGame(); } } private void appendGameModeLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_GAMEMODE).append(':'); buffer.append(getGameMode().getName()); buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * private helper methods * ############################################################### */ private static void appendPCGVersionLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_PCGVERSION).append(':'); buffer.append("2.0"); //$NON-NLS-1$ buffer.append(IOConstants.LINE_SEP); } private void appendPurchasePointsLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_PURCHASEPOINTS).append(':'); if (getGameMode().isPurchaseStatMode()) { buffer.append('Y'); buffer.append('|'); buffer.append(IOConstants.TAG_TYPE).append(':'); buffer .append(getGameMode().getPurchaseModeMethodName()); } else { buffer.append('N'); } buffer.append(IOConstants.LINE_SEP); } private void appendRollMethodLine(StringBuilder buffer) { final GameMode game = getGameMode(); buffer.append(IOConstants.TAG_ROLLMETHOD).append(':'); buffer.append(game.getRollMethod()); buffer.append('|'); buffer.append(IOConstants.TAG_EXPRESSION).append(':'); switch (game.getRollMethod()) { case Constants.CHARACTER_STAT_METHOD_ALL_THE_SAME: buffer.append(game.getAllStatsValue()); break; case Constants.CHARACTER_STAT_METHOD_PURCHASE: buffer.append(game.getPurchaseModeMethodName()); break; case Constants.CHARACTER_STAT_METHOD_ROLLED: buffer.append(game.getRollMethodExpression()); break; default: buffer.append(0); break; } buffer.append(IOConstants.LINE_SEP); } /* * modified this function to output the version number * as displayed in pcgenprop.properties instead of a simple int. * This will record the version more accurately. */ private static void appendVersionLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_VERSION).append(':'); buffer.append(PCGenPropBundle.getVersionNumber()); buffer.append(IOConstants.LINE_SEP); } private void appendAgeLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_AGE).append(':'); buffer.append(charDisplay.getAge()); buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * AgeSet * ############################################################### */ private void appendAgeSetLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_AGESET); for (int i = 0; i < 10; i++) { buffer.append(':'); if (thePC.hasMadeKitSelectionForAgeSet(i)) { buffer.append('1'); } else { buffer.append('0'); } } buffer.append(IOConstants.LINE_SEP); } private void appendAlignmentLine(StringBuilder buffer) { // // Only save alignment if game mode supports it // if (!Globals.getGameModeAlignmentText().isEmpty() && charDisplay.getPCAlignment() != null) { buffer.append(IOConstants.TAG_ALIGNMENT).append(':'); buffer.append(charDisplay.getPCAlignment().getKeyName()); buffer.append(IOConstants.LINE_SEP); } } private void appendBirthdayLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_BIRTHDAY).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.BIRTHDAY))); buffer.append(IOConstants.LINE_SEP); } private void appendBirthplaceLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_BIRTHPLACE).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.BIRTHPLACE))); buffer.append(IOConstants.LINE_SEP); } /** * @param buffer */ private void appendCampaignHistoryLines(StringBuilder buffer) { for (ChronicleEntry ce : charDisplay.getChronicleEntries()) { buffer.append(IOConstants.TAG_CHRONICLE_ENTRY).append(':'); buffer.append(ce.isOutputEntry()?"Y":"N:"); buffer.append('|'); buffer.append(IOConstants.TAG_CAMPAIGN).append(':'); buffer.append(EntityEncoder.encode(ce.getCampaign())); buffer.append('|'); buffer.append(IOConstants.TAG_ADVENTURE).append(':'); buffer.append(EntityEncoder.encode(ce.getAdventure())); buffer.append('|'); buffer.append(IOConstants.TAG_PARTY).append(':'); buffer.append(EntityEncoder.encode(ce.getParty())); buffer.append('|'); buffer.append(IOConstants.TAG_DATE).append(':'); buffer.append(EntityEncoder.encode(ce.getDate())); buffer.append('|'); buffer.append(IOConstants.TAG_EXPERIENCE).append(':'); buffer.append(ce.getXpField()); buffer.append('|'); buffer.append(IOConstants.TAG_GM).append(':'); buffer.append(EntityEncoder.encode(ce.getGmField())); buffer.append('|'); buffer.append(IOConstants.TAG_CHRONICLE).append(':'); buffer.append(EntityEncoder.encode(ce.getChronicle())); buffer.append(IOConstants.LINE_SEP); } } private void appendCatchPhraseLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_CATCHPHRASE).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.CATCHPHRASE))); buffer.append(IOConstants.LINE_SEP); } private void appendCharacterAssetLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_CHARACTERASSET).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.ASSETS))); buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * Character Description/Bio/History methods * ############################################################### */ private void appendCharacterBioLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_CHARACTERBIO).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.BIO))); buffer.append(IOConstants.LINE_SEP); } private void appendCharacterCompLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_CHARACTERCOMP).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.COMPANIONS))); buffer.append(IOConstants.LINE_SEP); } private void appendCharacterDescLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_CHARACTERDESC).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.DESCRIPTION))); buffer.append(IOConstants.LINE_SEP); } private void appendCharacterMagicLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_CHARACTERMAGIC).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.MAGIC))); buffer.append(IOConstants.LINE_SEP); } private void appendCharacterDmNotesLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_CHARACTERDMNOTES).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.GMNOTES))); buffer.append(IOConstants.LINE_SEP); } private void appendCharacterTypeLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_CHARACTERTYPE).append(':'); buffer.append(charDisplay.getCharacterType()); buffer.append(IOConstants.LINE_SEP); } private void appendPreviewSheetLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_PREVIEWSHEET).append(':'); buffer.append(charDisplay.getPreviewSheet()); buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * Character Class(es) methods * ############################################################### */ private void appendClassLines(StringBuilder buffer) { Cache specials = new Cache(); for (PCClass pcClass : charDisplay.getClassSet()) { int classLevel = charDisplay.getLevel(pcClass); buffer.append(IOConstants.TAG_CLASS).append(':'); buffer.append(EntityEncoder.encode(pcClass.getKeyName())); final String subClassKey = charDisplay.getSubClassName(pcClass); if (subClassKey != null && !Constants.EMPTY_STRING.equals(subClassKey)) { buffer.append('|'); buffer.append(IOConstants.TAG_SUBCLASS).append(':'); buffer.append(EntityEncoder.encode(subClassKey)); } buffer.append('|'); buffer.append(IOConstants.TAG_LEVEL).append(':'); buffer.append(classLevel); buffer.append('|'); buffer.append(IOConstants.TAG_SKILLPOOL).append(':'); Integer currentPool = thePC.getSkillPool(pcClass); buffer.append(currentPool == null ? 0 : currentPool); // determine if this class can cast spells boolean isCaster = false; if (!thePC.getSpellSupport(pcClass).canCastSpells(thePC)) { isCaster = true; } boolean isPsionic = thePC.getSpellSupport(pcClass).hasKnownList() && !isCaster; if (isCaster || isPsionic) { buffer.append('|'); buffer.append(IOConstants.TAG_SPELLBASE).append(':'); buffer.append(EntityEncoder.encode(pcClass.getSpellBaseStat())); buffer.append('|'); buffer.append(IOConstants.TAG_CANCASTPERDAY).append(':'); buffer.append(StringUtil.join(thePC.getSpellSupport(pcClass) .getCastListForLevel(classLevel), ",")); } Collection<? extends SpellProhibitor> prohib = charDisplay .getProhibitedSchools(pcClass); if (prohib != null) { Set<String> set = new TreeSet<>(); for (SpellProhibitor sp : prohib) { set.addAll(sp.getValueList()); } if (!set.isEmpty()) { buffer.append('|'); buffer.append(IOConstants.TAG_PROHIBITED).append(':'); buffer.append(EntityEncoder.encode(StringUtil .join(set, ","))); } } appendAddTokenInfo(buffer, pcClass); buffer.append(IOConstants.LINE_SEP); String spec = thePC.getAssoc(pcClass, AssociationKey.SPECIALTY); if (spec != null) { specials.put(pcClass.getKeyName() + IOConstants.TAG_SPECIALTY + '0', spec); } String key; key = pcClass.getKeyName() + IOConstants.TAG_SAVE + '0'; List<? extends SpecialAbility> salist = charDisplay.getUserSpecialAbilityList(pcClass); if (salist != null) { for (SpecialAbility sa : salist) { specials.put(pcClass.getKeyName() + IOConstants.TAG_SA + 0, sa .getKeyName()); break; } } for (BonusObj save : thePC.getSaveableBonusList(pcClass)) { specials.put(key, "BONUS|" + save); } for (int i = 1; i <= charDisplay.getLevel(pcClass); i++) { key = pcClass.getKeyName() + IOConstants.TAG_SAVE + (i - 1); PCClassLevel pcl = charDisplay.getActiveClassLevel(pcClass, i); for (BonusObj save : thePC.getSaveableBonusList(pcl)) { specials.put(key, "BONUS|" + save); } } } // // Save level up information in the order of levelling // for (PCLevelInfo pcl : charDisplay.getLevelInfo()) { final String classKeyName = pcl.getClassKeyName(); int lvl = pcl.getClassLevel() - 1; PCClass pcClass = thePC.getClassKeyed(classKeyName); buffer.append(IOConstants.TAG_CLASSABILITIESLEVEL).append(':'); if (pcClass == null) { pcClass = Globals.getContext().getReferenceContext() .silentlyGetConstructedCDOMObject(PCClass.class, classKeyName); if (pcClass != null) { pcClass = thePC.getClassKeyed(pcClass.get(ObjectKey.EX_CLASS) .get().getKeyName()); } } if (pcClass != null) { buffer.append(EntityEncoder.encode(pcClass.getKeyName())); } else { buffer.append(EntityEncoder.encode("???")); //$NON-NLS-1$ } buffer.append('=').append(lvl + 1); if (pcClass != null) { String aKey = charDisplay.getSubstitutionClassName(charDisplay .getActiveClassLevel(pcClass, lvl + 1)); if (aKey != null) { buffer.append('|'); buffer.append(IOConstants.TAG_SUBSTITUTIONLEVEL).append(':'); buffer.append(aKey); } buffer.append('|'); buffer.append(IOConstants.TAG_HITPOINTS).append(':'); PCClassLevel classLevel = charDisplay.getActiveClassLevel(pcClass, lvl); Integer hp = charDisplay.getHP(classLevel); buffer.append(hp == null ? 0 : hp); appendSpecials(buffer, specials.get(pcClass.getKeyName() + IOConstants.TAG_SAVE + lvl), IOConstants.TAG_SAVES, IOConstants.TAG_SAVE, lvl); appendSpecials(buffer, specials.get(pcClass.getKeyName() + IOConstants.TAG_SPECIALTY + lvl), IOConstants.TAG_SPECIALTIES, IOConstants.TAG_SPECIALTY, lvl); appendSpecials(buffer, specials.get(pcClass.getKeyName() + IOConstants.TAG_SA + lvl), IOConstants.TAG_SPECIALABILITIES, IOConstants.TAG_SA, lvl); if (lvl == 0) { appendSpecials(buffer, specials.get(pcClass.getKeyName() + IOConstants.TAG_SA + (lvl - 1)), IOConstants.TAG_SPECIALABILITIES, IOConstants.TAG_SA, -1); } // // Remember what choices were made for each of the ADD: tags // appendAddTokenInfo(buffer, charDisplay.getActiveClassLevel(pcClass, lvl + 1)); } List<PCLevelInfoStat> statList = pcl.getModifiedStats(true); if (statList != null) { for (PCLevelInfoStat stat : statList) { buffer.append('|').append(IOConstants.TAG_PRESTAT).append(':').append( stat.toString()); } } statList = pcl.getModifiedStats(false); if (statList != null) { for (PCLevelInfoStat stat : statList) { buffer.append('|').append(IOConstants.TAG_PRESTAT).append(':').append( stat.toString()); } } int sp = pcl.getSkillPointsGained(thePC); //if (sp != 0) { buffer.append('|').append(IOConstants.TAG_SKILLPOINTSGAINED).append(':') .append(sp); } sp = pcl.getSkillPointsRemaining(); //if (sp != 0) { buffer.append('|').append(IOConstants.TAG_SKILLPOINTSREMAINING).append(':') .append(sp); } buffer.append(IOConstants.LINE_SEP); } } /** * Convenience Method * * <br>author: Thomas Behr 19-03-02 * * @param comment * @param buffer */ private static void appendComment(String comment, StringBuilder buffer) { buffer.append(createComment(comment)); } /* * ############################################################### * Character Deity/Domain methods * ############################################################### */ private void appendDeityLine(StringBuilder buffer) { if (charDisplay.getDeity() != null) { final Deity aDeity = charDisplay.getDeity(); buffer.append(IOConstants.TAG_DEITY).append(':'); buffer.append(EntityEncoder.encode(aDeity.getKeyName())); /* * currently unused information * * author: Thomas Behr 09-09-02 */ buffer.append('|'); buffer.append(IOConstants.TAG_DEITYDOMAINS).append(':'); buffer.append('['); String del = Constants.EMPTY_STRING; for (CDOMReference<Domain> ref : aDeity .getSafeListMods(Deity.DOMAINLIST)) { for (Domain d : ref.getContainedObjects()) { buffer.append(del); buffer.append(IOConstants.TAG_DOMAIN).append(':'); buffer.append(EntityEncoder.encode(d.getKeyName())); del = "|"; //$NON-NLS-1$ } } buffer.append(']'); buffer.append('|'); buffer.append(IOConstants.TAG_ALIGNALLOW).append(':'); //TODO Need to clean this up? for (final Description desc : aDeity .getSafeListFor(ListKey.DESCRIPTION)) { buffer.append('|'); buffer.append(IOConstants.TAG_DESC).append(':'); buffer.append(desc.getPCCText()); } buffer.append('|'); buffer.append(IOConstants.TAG_DEITYFAVWEAP).append(':'); buffer.append('['); List<CDOMReference<WeaponProf>> dwp = aDeity.getListFor(ListKey.DEITYWEAPON); if (dwp != null) { del = Constants.EMPTY_STRING; for (CDOMReference<WeaponProf> ref : dwp) { buffer.append(del); buffer.append(IOConstants.TAG_WEAPON).append(':'); buffer.append(EntityEncoder.encode(ref.getLSTformat(false))); del = "|"; //$NON-NLS-1$ } } buffer.append(']'); buffer.append('|'); buffer.append(IOConstants.TAG_DEITYALIGN).append(':'); CDOMSingleRef<PCAlignment> al = aDeity.get(ObjectKey.ALIGNMENT); if (al != null) { buffer.append(al.getLSTformat(false)); } buffer.append(IOConstants.LINE_SEP); } } private void appendDomainLines(StringBuilder buffer) { for (final Domain domain : charDisplay.getDomainSet()) { // TODO is any of this commented out code any use anymore?: // // // improve here - performance and concept!!!! // domainSpells.clear(); // for (Iterator it2 = Globals.getSpellMap().values().iterator(); it2.hasNext();) // { // aSpell = (Spell)it2.next(); // // levelString = aSpell.levelForClass(aDomain.getName()); // if ((levelString.length() > 0) && // (levelString.indexOf("-1") < 0)) // { // tokens = new StringTokenizer(levelString, ","); // while (tokens.hasMoreTokens()) // { // if (tokens.nextToken().equals(aDomain.getName())) // { // break; // } // } // domainSpells.add(((tokens.hasMoreTokens()) ? tokens.nextToken() + " " : "") + // aSpell.getName()); // } // } buffer.append(IOConstants.TAG_DOMAIN).append(':'); buffer.append(EntityEncoder.encode(domain.getKeyName())); for (String assoc : thePC.getAssociationList(domain)) { buffer.append('|'); buffer.append(IOConstants.TAG_ASSOCIATEDDATA).append(':'); buffer.append(EntityEncoder.encode(assoc)); } for (final Description desc : domain .getSafeListFor(ListKey.DESCRIPTION)) { buffer.append('|'); buffer.append(IOConstants.TAG_DOMAINGRANTS).append(':'); buffer.append(desc.getPCCText()); } buffer.append('|'); appendSourceInTaggedFormat(buffer, getDomainSourcePcgString(domain)); // buffer.append('|'); // buffer.append(TAG_DOMAINFEATS).append(':'); // buffer.append(aDomain.getFeatList()); // buffer.append('|'); // buffer.append(TAG_DOMAINSKILLS).append(':'); // buffer.append(aDomain.getSkillList()); // buffer.append('|'); // buffer.append(TAG_DOMAINSPECIALS).append(':'); // buffer.append(aDomain.getSpecialAbility()); // buffer.append('|'); // buffer.append(TAG_DOMAINSPELLS).append(':'); // buffer.append(aDomain.getSpellList()); appendAddTokenInfo(buffer, domain); buffer.append(IOConstants.LINE_SEP); /* * not working yet anyways * * author: Thomas Behr 09-09-02 */ // buffer.append(TAG_DOMAINSPELLS).append(':'); // buffer.append(EntityEncoder.encode(aDomain.getKeyName())); // buffer.append('|'); // buffer.append(TAG_SPELLLIST).append(':'); // buffer.append('['); // del = ""; // Collections.sort(domainSpells); // for (Iterator it2 = domainSpells.iterator(); it2.hasNext();) // { // buffer.append(del); // buffer.append(TAG_SPELL).append(':'); // buffer.append(EntityEncoder.encode((String)it2.next())); // del = "|"; // } // buffer.append(']'); // buffer.append(LINE_SEP); } } /** * Returns the source of the domain in the format "PObject|name[|level]" * For example, "PCClass|Cleric|1" * (since the level is relevant) * For example, "Feat|Awesome Divinity" to attach a domain to a feat * * This method should NOT be called outside of file i/o routines * DO NOT perform comparisons on this String * * @return String the source of the domain */ private String getDomainSourcePcgString(Domain domain) { final StringBuilder buff = new StringBuilder(30); ClassSource source = thePC.getDomainSource(domain); buff.append("PCClass"); buff.append('|'); buff.append(source.getPcclass().getKeyName()); if (source.getLevel() > 0) { buff.append('|'); buff.append(source.getLevel()); } return buff.toString(); } /** * For each EquipSet, check for a tempBonusList and if found, save each * bonus * * @param buffer */ private void appendEqSetBonuses(StringBuilder buffer) { for (EquipSet eSet : charDisplay.getEquipSet()) { if (eSet.useTempBonusList()) { buffer.append(IOConstants.TAG_EQSETBONUS).append(':'); buffer.append(eSet.getIdPath()); List<String> trackList = new ArrayList<>(); for (Map.Entry<BonusObj, BonusManager.TempBonusInfo> me : eSet .getTempBonusMap().entrySet()) { //BonusObj bObj = me.getKey(); TempBonusInfo tbi = me.getValue(); Object cObj = tbi.source; Object tObj = tbi.target; final String aName = tempBonusName(cObj, tObj); if (trackList.contains(aName)) { continue; } trackList.add(aName); buffer.append('|'); buffer.append(IOConstants.TAG_TEMPBONUSBONUS).append(':'); buffer.append(EntityEncoder.encode(aName)); } buffer.append(IOConstants.LINE_SEP); } } } private void appendEquipmentLines(StringBuilder buffer) { List<Equipment> eqsorted = thePC.getEquipmentMasterList(); Collections.sort(eqsorted); for (final Equipment eq : eqsorted) { buffer.append(IOConstants.TAG_EQUIPNAME).append(':'); buffer.append(EntityEncoder.encode(eq.getName())); buffer.append('|'); buffer.append(IOConstants.TAG_OUTPUTORDER).append(':'); buffer.append(eq.getOutputIndex()); buffer.append('|'); buffer.append(IOConstants.TAG_COST).append(':'); buffer.append(eq.getCost(thePC).toString()); buffer.append('|'); buffer.append(IOConstants.TAG_WT).append(':'); buffer.append(eq.getWeight(thePC).toString()); buffer.append('|'); buffer.append(IOConstants.TAG_QUANTITY).append(':'); buffer.append(eq.qty()); final String note = eq.getNote(); if (note != null) { buffer.append('|'); buffer.append(IOConstants.TAG_NOTE).append(':'); buffer.append(eq.getNote()); } final String customization = eq.formatSaveLine('$', '=').trim(); final int delimiterIndex = customization.indexOf('$'); if ((!customization.isEmpty()) && (delimiterIndex >= 0)) { buffer.append('|'); buffer.append(IOConstants.TAG_CUSTOMIZATION).append(':'); buffer.append('['); buffer.append(IOConstants.TAG_BASEITEM).append(':'); buffer.append(EntityEncoder.encode(customization.substring(0, delimiterIndex))); buffer.append('|'); buffer.append(IOConstants.TAG_DATA).append(':'); buffer.append(EntityEncoder.encode(customization .substring(delimiterIndex + 1))); buffer.append(']'); } buffer.append(IOConstants.LINE_SEP); } } private void appendEquipmentSetLines(StringBuilder buffer) { // Output all the EquipSets final List<EquipSet> eqSetList = new ArrayList<>(charDisplay.getEquipSet()); Collections.sort(eqSetList); for (EquipSet eqSet : eqSetList) { buffer.append(IOConstants.TAG_EQUIPSET).append(':'); buffer.append(EntityEncoder.encode(eqSet.getName())); buffer.append('|'); buffer.append(IOConstants.TAG_ID).append(':'); buffer.append(eqSet.getIdPath()); if (!eqSet.getValue().isEmpty()) { buffer.append('|'); buffer.append(IOConstants.TAG_VALUE).append(':'); buffer.append(EntityEncoder.encode(eqSet.getValue())); buffer.append('|'); buffer.append(IOConstants.TAG_QUANTITY).append(':'); buffer.append(eqSet.getQty()); } if (!eqSet.getNote().isEmpty()) { buffer.append('|'); buffer.append(IOConstants.TAG_NOTE).append(':'); buffer.append(eqSet.getNote()); } if (eqSet.getUseTempMods()) { buffer.append('|'); buffer.append(IOConstants.TAG_USETEMPMODS).append(':'); buffer.append(eqSet.getUseTempMods() ? 'Y' : 'N'); } buffer.append(IOConstants.LINE_SEP); } // Then output EquipSet used for "working" equipmentList final String calcEquipSet = thePC.getCalcEquipSetId(); buffer.append(IOConstants.TAG_CALCEQUIPSET).append(':'); buffer.append(calcEquipSet); buffer.append(IOConstants.LINE_SEP); } private void appendEyeColorLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_EYECOLOR).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.EYECOLOR))); buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * Character Feats methods * Only need to output pool, other FEAT info is stored in the ABILITY lines. * ############################################################### */ private void appendFeatLines(StringBuilder buffer) { buffer.append(IOConstants.TAG_FEATPOOL).append(':'); buffer.append(thePC.getRemainingFeatPoints(false)); buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * Character Ability methods * ############################################################### */ private void appendAbilityLines(StringBuilder buffer) { ArrayList<AbilityCategory> categories = new ArrayList<>( getGameMode().getAllAbilityCategories()); categories.add(AbilityCategory.LANGBONUS); Collection<CNAbilitySelection> virtSave = thePC.getSaveAbilities(); categories.sort(new Comparator<AbilityCategory>() { @Override public int compare(AbilityCategory a, AbilityCategory b) { return a.getKeyName().compareTo(b.getKeyName()); } }); for (final AbilityCategory cat : categories) { final List<CNAbility> normalAbilitiesToSave = new ArrayList<>(thePC.getPoolAbilities(cat, Nature.NORMAL)); // ABILITY:FEAT|NORMAL|Feat Key|APPLIEDTO:xxx|TYPE:xxx|SAVE:xxx|DESC:xxx Collections.sort(normalAbilitiesToSave); for (final CNAbility ability : normalAbilitiesToSave) { writeAbilityToBuffer(buffer, ability); } boolean hasVirt = false; for (final CNAbilitySelection ability : virtSave) { CNAbility cnAbility = ability.getCNAbility(); if (cnAbility.getAbilityCategory().equals(cat)) { //TODO Need to write each CNAbility only once :/ writeAbilityToBuffer(buffer, cnAbility); hasVirt = true; } } if (!normalAbilitiesToSave.isEmpty() || hasVirt || thePC.getUserPoolBonus(cat) != 0.0) { buffer.append(IOConstants.TAG_USERPOOL).append(IOConstants.TAG_END); buffer.append(EntityEncoder.encode(cat.getKeyName())).append( IOConstants.TAG_SEPARATOR); buffer.append(IOConstants.TAG_POOLPOINTS).append(IOConstants.TAG_END); buffer.append(thePC.getUserPoolBonus(cat)); buffer.append(IOConstants.LINE_SEP); } } } private void writeAbilityToBuffer(StringBuilder buffer, CNAbility cna) { Category<Ability> cat = cna.getAbilityCategory(); Nature nature = cna.getNature(); Ability ability = cna.getAbility(); buffer.append(IOConstants.TAG_ABILITY).append(IOConstants.TAG_END); buffer.append(EntityEncoder.encode(cat.getKeyName())).append( IOConstants.TAG_SEPARATOR); buffer.append(IOConstants.TAG_TYPE).append(IOConstants.TAG_END); buffer.append(EntityEncoder.encode(nature.toString())).append( IOConstants.TAG_SEPARATOR); buffer.append(IOConstants.TAG_CATEGORY).append(IOConstants.TAG_END); buffer.append(EntityEncoder.encode(ability.getCategory())) .append(IOConstants.TAG_SEPARATOR); buffer.append(IOConstants.TAG_MAPKEY).append(IOConstants.TAG_END); buffer.append(EntityEncoder.encode(ability.getKeyName())) .append(IOConstants.TAG_SEPARATOR); if (ability.getSafe(ObjectKey.MULTIPLE_ALLOWED)) { buffer.append(IOConstants.TAG_APPLIEDTO).append(IOConstants.TAG_END); List<String> assocList = thePC.getAssociationList(cna); boolean first = true; for (String assoc : assocList) { if (!first) { buffer.append(Constants.COMMA); } first = false; buffer.append(EntityEncoder.encode(assoc)); } buffer.append(IOConstants.TAG_SEPARATOR); } buffer.append(IOConstants.TAG_TYPE).append(IOConstants.TAG_END); buffer.append(EntityEncoder.encode(ability.getType())); for (final BonusObj save : thePC.getSaveableBonusList(ability)) { buffer.append('|'); buffer.append(IOConstants.TAG_SAVE).append(':'); buffer.append(EntityEncoder.encode("BONUS|" + save)); } for (final Description desc : ability .getSafeListFor(ListKey.DESCRIPTION)) { buffer.append(Constants.PIPE); buffer.append(IOConstants.TAG_DESC).append(':'); buffer.append(EntityEncoder.encode(desc.getPCCText())); } buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * Character Follower methods * ############################################################### */ private void appendFollowerLines(StringBuilder buffer) { final Follower aMaster = charDisplay.getMaster(); if (aMaster != null) { buffer.append(IOConstants.TAG_MASTER).append(':'); buffer.append(EntityEncoder.encode(aMaster.getName())); buffer.append('|'); buffer.append(IOConstants.TAG_TYPE).append(':'); buffer.append(EntityEncoder.encode(aMaster.getType().getKeyName())); buffer.append('|'); buffer.append(IOConstants.TAG_HITDICE).append(':'); buffer.append(aMaster.getUsedHD()); buffer.append('|'); buffer.append(IOConstants.TAG_FILE).append(':'); buffer .append(EntityEncoder.encode(FileHelper.findRelativePath( new File(charDisplay.getFileName()), new File(aMaster.getFileName())))); buffer.append('|'); buffer.append(IOConstants.TAG_ADJUSTMENT).append(':'); buffer.append(aMaster.getAdjustment()); buffer.append(IOConstants.LINE_SEP); } if (charDisplay.hasFollowers()) { for (Follower follower : charDisplay.getFollowerList()) { buffer.append(IOConstants.TAG_FOLLOWER).append(':'); buffer.append(EntityEncoder.encode(follower.getName())); buffer.append('|'); buffer.append(IOConstants.TAG_TYPE).append(':'); buffer.append(EntityEncoder.encode(follower.getType() .getKeyName())); buffer.append('|'); if (follower.getRace() != null) { buffer.append(IOConstants.TAG_RACE).append(':'); buffer.append(EntityEncoder.encode(follower.getRace() .getKeyName().toUpperCase())); buffer.append('|'); } buffer.append(IOConstants.TAG_HITDICE).append(':'); buffer.append(follower.getUsedHD()); buffer.append('|'); buffer.append(IOConstants.TAG_FILE).append(':'); if (StringUtils.isNotEmpty(follower.getFileName())) { buffer.append(EntityEncoder.encode(FileHelper .findRelativePath(new File(charDisplay.getFileName()), new File(follower.getFileName())))); } buffer.append(IOConstants.LINE_SEP); } } } private void appendGenderLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_GENDER).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getGenderObject().name())); buffer.append(IOConstants.LINE_SEP); } private void appendHairColorLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_HAIRCOLOR).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.HAIRCOLOR))); buffer.append(IOConstants.LINE_SEP); } private void appendHairStyleLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_HAIRSTYLE).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.HAIRSTYLE))); buffer.append(IOConstants.LINE_SEP); } private void appendHandedLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_HANDED).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getHandedObject().name())); buffer.append(IOConstants.LINE_SEP); } private void appendInterestsLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_INTERESTS).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.INTERESTS))); buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * Kit Information methods * ############################################################### */ /* * #Kits * KIT:KitType|Region|KitName * * TODO: Do we need to support the below? * KIT:KitName|TYPE:KitType|REGION:Region */ private void appendKitLines(StringBuilder buffer) { for (final Kit kit : charDisplay.getKitInfo()) { buffer.append(IOConstants.TAG_KIT).append(':').append(kit.getKeyName()) .append(IOConstants.LINE_SEP); } } /* * ############################################################### * Character Language methods * ############################################################### */ private void appendLanguageLine(StringBuilder buffer) { String del = Constants.EMPTY_STRING; TreeSet<Language> sortedlangs = new TreeSet(charDisplay.getLanguageSet()); for (final Language lang : sortedlangs) { buffer.append(del); buffer.append(IOConstants.TAG_LANGUAGE).append(':'); buffer.append(EntityEncoder.encode(lang.getKeyName())); del = "|"; //$NON-NLS-1$ } buffer.append(IOConstants.LINE_SEP); } private void appendLocationLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_LOCATION).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.LOCATION))); buffer.append(IOConstants.LINE_SEP); } /** * Convenience Method * * <br>author: Thomas Behr 19-03-02 * * @param buffer */ private static void appendNewline(StringBuilder buffer) { buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * Character Notes Tab methods * ############################################################### */ private void appendNotesLines(StringBuilder buffer) { for (NoteItem ni : charDisplay.getNotesList()) { buffer.append(IOConstants.TAG_NOTE).append(':'); buffer.append(EntityEncoder.encode(ni.getName())); buffer.append('|'); buffer.append(IOConstants.TAG_ID).append(':'); buffer.append(ni.getId()); buffer.append('|'); buffer.append(IOConstants.TAG_PARENTID).append(':'); buffer.append(ni.getParentId()); buffer.append('|'); buffer.append(IOConstants.TAG_VALUE).append(':'); buffer.append(EntityEncoder.encode(ni.getValue())); buffer.append(IOConstants.LINE_SEP); } } private void appendPersonalityTrait1Line(StringBuilder buffer) { buffer.append(IOConstants.TAG_PERSONALITYTRAIT1).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.PERSONALITY1))); buffer.append(IOConstants.LINE_SEP); } private void appendPersonalityTrait2Line(StringBuilder buffer) { buffer.append(IOConstants.TAG_PERSONALITYTRAIT2).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.PERSONALITY2))); buffer.append(IOConstants.LINE_SEP); } private void appendPhobiasLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_PHOBIAS).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.PHOBIAS))); buffer.append(IOConstants.LINE_SEP); } //private void appendUnlimitedPoolCheckedLine(StringBuilder buffer) //{ //buffer.append(TAG_UNLIMITEDPOOLCHECKED).append(':'); //buffer.append((SettingsHandler.isStatPoolUnlimited()) ? "Y" : "N"); //buffer.append(LINE_SEP); //} private void appendPoolPointsLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_POOLPOINTS).append(':'); buffer.append(thePC.getPoolAmount()); buffer.append(IOConstants.LINE_SEP); buffer.append(IOConstants.TAG_POOLPOINTSAVAIL).append(':'); buffer.append(thePC.getPointBuyPoints()); buffer.append(IOConstants.LINE_SEP); } private static void appendTabLabelLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_TABLABEL).append(':'); buffer.append(SettingsHandler.getNameDisplayStyle()); buffer.append(IOConstants.LINE_SEP); } private void appendAutoSortLines(StringBuilder buffer) { buffer.append(IOConstants.TAG_AUTOSORTGEAR).append(':'); buffer.append(thePC.isAutoSortGear() ? 'Y' : 'N'); buffer.append(IOConstants.LINE_SEP); buffer.append(IOConstants.TAG_SKILLSOUTPUTORDER).append(':'); buffer.append(thePC.getSkillsOutputOrder().ordinal()); buffer.append(IOConstants.LINE_SEP); } private void appendSkillFilterLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_SKILLFILTER).append(':'); buffer.append(thePC.getSkillFilter().getValue()); buffer.append(IOConstants.LINE_SEP); } private void appendGearCostSizeLines(StringBuilder buffer) { buffer.append(IOConstants.TAG_IGNORECOST).append(':'); buffer.append(thePC.isIgnoreCost() ? 'Y' : 'N'); buffer.append(IOConstants.LINE_SEP); buffer.append(IOConstants.TAG_ALLOWDEBT).append(':'); buffer.append(thePC.isAllowDebt() ? 'Y' : 'N'); buffer.append(IOConstants.LINE_SEP); buffer.append(IOConstants.TAG_AUTORESIZEGEAR).append(':'); buffer.append(thePC.isAutoResize() ? 'Y' : 'N'); buffer.append(IOConstants.LINE_SEP); } private void appendAutoSpellsLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_AUTOSPELLS).append(':'); buffer.append(thePC.getAutoSpells() ? 'Y' : 'N'); buffer.append(IOConstants.LINE_SEP); } /** * Append the settings related to higher level slot use for spells. * @param buffer The buffer to append to. */ private void appendUseHigherSpellSlotsLines(StringBuilder buffer) { buffer.append(IOConstants.TAG_USEHIGHERKNOWN).append(':'); buffer.append(thePC.getUseHigherKnownSlots() ? 'Y' : 'N'); buffer.append(IOConstants.LINE_SEP); buffer.append(IOConstants.TAG_USEHIGHERPREPPED).append(':'); buffer.append(thePC.getUseHigherPreppedSlots() ? 'Y' : 'N'); buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * Character Bio methods * ############################################################### */ private void appendCharacterNameLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_CHARACTERNAME).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getName())); buffer.append(IOConstants.LINE_SEP); } private void appendHeightLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_HEIGHT).append(':'); buffer.append(charDisplay.getHeight()); buffer.append(IOConstants.LINE_SEP); } private void appendLoadCompanionLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_LOADCOMPANIONS).append(':'); buffer.append(thePC.getLoadCompanion() ? 'Y' : 'N'); buffer.append(IOConstants.LINE_SEP); } private void appendOutputSheetsLines(StringBuilder buffer) { if (SettingsHandler.getSaveOutputSheetWithPC()) { buffer.append(IOConstants.TAG_HTMLOUTPUTSHEET).append(':'); buffer.append(EntityEncoder.encode(SettingsHandler .getSelectedCharacterHTMLOutputSheet(null))); buffer.append(IOConstants.LINE_SEP); buffer.append(IOConstants.TAG_PDFOUTPUTSHEET).append(':'); buffer.append(EntityEncoder.encode(SettingsHandler .getSelectedCharacterPDFOutputSheet(null))); buffer.append(IOConstants.LINE_SEP); } } private void appendPlayerNameLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_PLAYERNAME).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getPlayersName())); buffer.append(IOConstants.LINE_SEP); } private void appendPortraitLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_PORTRAIT).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getPortraitPath())); buffer.append(IOConstants.LINE_SEP); Rectangle rect = charDisplay.getPortraitThumbnailRect(); if (rect != null) { buffer.append(IOConstants.TAG_PORTRAIT_THUMBNAIL_RECT).append(':'); buffer.append(rect.x).append(','); buffer.append(rect.y).append(','); buffer.append(rect.width).append(','); buffer.append(rect.height); buffer.append(IOConstants.LINE_SEP); } } /** * @param buffer */ private void appendRaceLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_RACE).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getRace().getKeyName())); List<String> assocList = thePC.getAssociationList(charDisplay.getRace()); if (assocList != null && !assocList.isEmpty()) { buffer.append(IOConstants.TAG_SEPARATOR); buffer.append(IOConstants.TAG_APPLIEDTO).append(IOConstants.TAG_END); boolean first = true; for (String assoc : assocList) { if (!first) { buffer.append(Constants.COMMA); } first = false; buffer.append(EntityEncoder.encode(assoc)); } } appendAddTokenInfo(buffer, charDisplay.getRace()); buffer.append(IOConstants.LINE_SEP); } private void appendFavoredClassLine(StringBuilder buffer) { PCClass sfc = thePC.getLegacyFavoredClass(); if (sfc != null) { buffer.append(IOConstants.TAG_FAVOREDCLASS).append(':'); buffer.append(EntityEncoder.encode(sfc.getKeyName())); buffer.append(IOConstants.LINE_SEP); } } private void appendResidenceLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_CITY).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.RESIDENCE))); buffer.append(IOConstants.LINE_SEP); } private void appendSkinColorLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_SKINCOLOR).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.SKINCOLOR))); buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * Miscellaneous methods * ############################################################### */ /* * currently source is either empty or * PCCLASS|classname|classlevel (means it's a chosen special ability) * PCCLASS=classname|classlevel (means it's a defined special ability) * DEITY=deityname|totallevels */ private static void appendSourceInTaggedFormat(StringBuilder buffer, String source) { final StringTokenizer tokens = new StringTokenizer(source, "|="); //$NON-NLS-1$ buffer.append(IOConstants.TAG_SOURCE).append(':'); buffer.append('['); buffer.append(IOConstants.TAG_TYPE).append(':'); buffer.append(tokens.nextToken()); buffer.append('|'); buffer.append(IOConstants.TAG_NAME).append(':'); buffer.append(tokens.nextToken()); if (tokens.hasMoreTokens()) { buffer.append('|'); buffer.append(IOConstants.TAG_LEVEL).append(':'); buffer.append(tokens.nextToken()); } if (source.indexOf('=') >= 0) { buffer.append('|'); buffer.append(IOConstants.TAG_DEFINED).append(':'); buffer.append('Y'); } buffer.append(']'); } /* * currently source is either empty or * PCCLASS|classname|classlevel (means it's a chosen special ability) * PCCLASS=classname|classlevel (means it's a defined special ability) * DEITY=deityname|totallevels */ private static void appendSourceInTaggedFormat(StringBuilder buffer, CDOMObject source) { buffer.append(IOConstants.TAG_SOURCE).append(':'); buffer.append('['); buffer.append(IOConstants.TAG_TYPE).append(':'); // I love reflection :-) final Class<? extends CDOMObject> srcClass = source.getClass(); final String pckName = srcClass.getPackage().getName(); final String srcName = srcClass.getName().substring(pckName.length() + 1); buffer.append(srcName.toUpperCase()); buffer.append('|'); buffer.append(IOConstants.TAG_NAME).append(':'); buffer.append(source.getKeyName()); buffer.append(']'); } private static void appendSpecials(StringBuilder buffer, List<String> specials, String tag_group, String tag_item, int lvl) { if ((specials != null) && (!specials.isEmpty())) { buffer.append('|'); buffer.append(tag_group).append(':'); buffer.append('['); String del = Constants.EMPTY_STRING; for (String special : specials) { buffer.append(del); buffer.append(tag_item).append(':'); buffer.append(EntityEncoder.encode(special)); if (lvl == -1) { buffer.append(":-1"); //$NON-NLS-1$ } del = "|"; //$NON-NLS-1$ } buffer.append(']'); } } /* * ############################################################### * Character Experience methods * ############################################################### */ private void appendExperienceLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_EXPERIENCE).append(':'); buffer.append(charDisplay.getXP()); buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * Character XP table methods * ############################################################### */ private void appendExperienceTableLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_EXPERIENCETABLE).append(':'); buffer.append(charDisplay.getXPTableName()); buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * Character Region method * ############################################################### */ private void appendRegionLine(StringBuilder buffer) { final String r = charDisplay.getRegionString(); if (r != null) { buffer.append(IOConstants.TAG_REGION).append(':').append(r).append(IOConstants.LINE_SEP); } } /* * ############################################################### * Character Skills methods * ############################################################### */ private void appendSkillLines(StringBuilder buffer) { List<Skill> skillList = new ArrayList<>(charDisplay.getSkillSet()); Collections.sort(skillList); for (Skill skill : skillList) { Integer outputIndex = thePC.getSkillOrder(skill); if ((thePC.getRank(skill).doubleValue() > 0) || (outputIndex != null && outputIndex != 0)) { buffer.append(IOConstants.TAG_SKILL).append(':'); buffer.append(EntityEncoder.encode(skill.getKeyName())); buffer.append('|'); if (outputIndex != null && outputIndex != 0) { buffer.append(IOConstants.TAG_OUTPUTORDER).append(':'); buffer.append(outputIndex == null ? 0 : outputIndex); buffer.append('|'); } for (PCClass pcc : thePC.getSkillRankClasses(skill)) { if (pcc != null) { Double rank = thePC.getSkillRankForClass(skill, pcc); buffer.append(IOConstants.TAG_CLASSBOUGHT).append(':'); buffer.append('['); buffer.append(IOConstants.TAG_CLASS).append(':'); buffer.append(EntityEncoder.encode(pcc == null ? "None" : pcc.getKeyName())); buffer.append('|'); buffer.append(IOConstants.TAG_RANKS).append(':'); buffer.append(rank); buffer.append('|'); buffer.append(IOConstants.TAG_COST).append(':'); buffer.append(Integer.toString(thePC .getSkillCostForClass(skill, pcc).getCost())); buffer.append('|'); buffer.append(IOConstants.TAG_CLASSSKILL).append(':'); buffer.append((thePC.isClassSkill(pcc, skill)) ? 'Y' : 'N'); buffer.append(']'); } } for (String assoc : thePC.getAssociationList(skill)) { buffer.append('|'); buffer.append(IOConstants.TAG_ASSOCIATEDDATA).append(':'); buffer.append(EntityEncoder.encode(assoc)); } appendLevelAbilityInfo(buffer, skill); buffer.append(IOConstants.LINE_SEP); } } } private void appendSpeechPatternLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_SPEECHPATTERN).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.SPEECHTENDENCY))); buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * Spell List Information methods * ############################################################### */ /* * #Spell List Information * SPELLLIST:sourceclassname|spelllistentry|spelllistentry */ private void appendSpellBookLines(StringBuilder buffer) { for (SpellBook book : charDisplay.getSpellBooks()) { String bookName = book.getName(); if (!bookName.equals(Globals.getDefaultSpellBook()) && !bookName.equals(Constants.INNATE_SPELL_BOOK_NAME)) { buffer.append(IOConstants.TAG_SPELLBOOK).append(':'); buffer.append(book.getName()); buffer.append('|'); buffer.append(IOConstants.TAG_TYPE).append(':'); buffer.append(book.getType()); if (book.getName().equals( thePC.getSpellBookNameToAutoAddKnown())) { buffer.append('|'); buffer.append(IOConstants.TAG_AUTOADDKNOWN).append(':'); buffer.append('Y'); } buffer.append(IOConstants.LINE_SEP); } } } /* * ############################################################### * Character Spells Information methods * ############################################################### */ /* * #Character Spells Information * CLASS:Wizard|CANCASTPERDAY:2,4(Totals the levels all up + includes attribute bonuses) * SPELLNAME:Blah|SCHOOL:blah|SUBSCHOOL:blah|Etc * * completely changed due to new Spell API */ private void appendSpellLines(StringBuilder buffer) { String del; for (PCClass pcClass : charDisplay.getClassSet()) { Collection<? extends CharacterSpell> sp = charDisplay.getCharacterSpells(pcClass); List<CharacterSpell> classSpells = new ArrayList<>(sp); // Add in the spells granted by objects thePC.addBonusKnownSpellsToList(pcClass, classSpells); Collections.sort(classSpells); for (CharacterSpell cSpell : classSpells) { for (SpellInfo spellInfo : cSpell.getInfoList()) { CDOMObject owner = cSpell.getOwner(); List<? extends CDOMList<Spell>> lists = charDisplay.getSpellLists(owner); if (SpellLevel.getFirstLevelForKey( cSpell.getSpell(), lists, thePC) < 0) { Logging.errorPrint("Ignoring unqualified spell " + cSpell.getSpell() + " in list for class " + pcClass + "."); continue; } if (spellInfo.getBook().equals( Globals.getDefaultSpellBook()) && thePC.getSpellSupport(pcClass).isAutoKnownSpell(cSpell.getSpell(), SpellLevel.getFirstLevelForKey( cSpell.getSpell(), lists, thePC), false, thePC) && thePC.getAutoSpells()) { continue; } buffer.append(IOConstants.TAG_SPELLNAME).append(':'); buffer.append(EntityEncoder.encode(cSpell.getSpell() .getKeyName())); buffer.append('|'); buffer.append(IOConstants.TAG_TIMES).append(':'); buffer.append(spellInfo.getTimes()); buffer.append('|'); buffer.append(IOConstants.TAG_CLASS).append(':'); buffer.append(EntityEncoder.encode(pcClass.getKeyName())); buffer.append('|'); buffer.append(IOConstants.TAG_SPELL_BOOK).append(':'); buffer.append(EntityEncoder.encode(spellInfo.getBook())); buffer.append('|'); buffer.append(IOConstants.TAG_SPELLLEVEL).append(':'); buffer.append(spellInfo.getActualLevel()); if (spellInfo.getNumPages() > 0) { buffer.append('|'); buffer.append(IOConstants.TAG_SPELLNUMPAGES).append(':'); buffer.append(spellInfo.getNumPages()); } final List<Ability> metaFeats = spellInfo.getFeatList(); if ((metaFeats != null) && (!metaFeats.isEmpty())) { buffer.append('|'); buffer.append(IOConstants.TAG_FEATLIST).append(':'); buffer.append('['); del = Constants.EMPTY_STRING; for (Ability feat : metaFeats) { buffer.append(del); buffer.append(IOConstants.TAG_FEAT).append(':'); buffer.append(EntityEncoder.encode(feat .getKeyName())); del = "|"; //$NON-NLS-1$ } buffer.append(']'); } buffer.append('|'); appendSourceInTaggedFormat(buffer, StringPClassUtil.getStringFor(owner.getClass()) + "|" + owner.getKeyName()); buffer.append(IOConstants.LINE_SEP); } } } } /* * ############################################################### * Spell List Information methods * ############################################################### */ /* * #Spell List Information * SPELLLIST:sourceclassname|spelllistentry|spelllistentry */ private void appendSpellListLines(StringBuilder buffer) { for (PCClass pcClass : charDisplay.getClassSet()) { TransitionChoice<CDOMListObject<Spell>> csc = pcClass.get(ObjectKey.SPELLLIST_CHOICE); if (csc != null) { List<? extends CDOMList<Spell>> assocList = charDisplay.getSpellLists(pcClass); buffer.append(IOConstants.TAG_SPELLLIST).append(':'); buffer.append(pcClass.getKeyName()); for (CDOMList<Spell> spell : assocList) { buffer.append('|'); if (ClassSpellList.class.equals(spell.getClass())) { buffer.append("CLASS"); } else { buffer.append("DOMAIN"); } buffer.append('.').append(spell.getLSTformat()); } buffer.append(IOConstants.LINE_SEP); } } } /* * ############################################################### * Character Attributes methods * ############################################################### */ private void appendStatLines(StringBuilder buffer) { for (PCStat aStat : charDisplay.getStatSet()) { buffer.append(IOConstants.TAG_STAT).append(':'); buffer.append(aStat.getKeyName()); buffer.append('|'); buffer.append(IOConstants.TAG_SCORE).append(':'); buffer.append(charDisplay.getStat(aStat)); buffer.append(IOConstants.LINE_SEP); } } private void appendTabNameLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_TABNAME).append(':'); buffer.append(EntityEncoder.encode(charDisplay.getSafeStringFor(PCStringKey.TABNAME))); buffer.append(IOConstants.LINE_SEP); } private void appendTempBonuses(StringBuilder buffer) { final List<String> trackList = new ArrayList<>(); TreeSet<Map.Entry<BonusObj, BonusManager.TempBonusInfo>> sortedbonus = new TreeSet<>( new Comparator<Map.Entry<BonusObj, BonusManager.TempBonusInfo>>() { @Override public int compare(Map.Entry<BonusObj, BonusManager.TempBonusInfo> a, Map.Entry<BonusObj, BonusManager.TempBonusInfo> b) { BonusObj keyA = a.getKey(); BonusObj keyB = b.getKey(); if (!keyA.getBonusName().equals(keyB.getBonusName())) { return keyA.getBonusName().compareTo(keyB.getBonusName()); } if (!keyA.getBonusInfo().equals(keyB.getBonusInfo())) { return keyA.getBonusInfo().compareTo(keyB.getBonusInfo()); } return keyA.getPCCText().compareTo(keyB.getPCCText()); } }); sortedbonus.addAll(thePC.getTempBonusMap().entrySet()); //for (BonusManager.TempBonusInfo tbi : thePC.getTempBonusMap().values()) for (Map.Entry<BonusObj, BonusManager.TempBonusInfo> me : sortedbonus) { BonusObj bonus = me.getKey(); TempBonusInfo tbi = me.getValue(); Object creObj = tbi.source; Object tarObj = tbi.target; final String outString = tempBonusName(creObj, tarObj); if (trackList.contains(outString)) { continue; } trackList.add(outString); buffer.append(outString); String bonusName = BonusDisplay.getBonusDisplayName(tbi); if (thePC.getTempBonusFilters().contains(bonusName)) { buffer.append('|'); buffer.append(IOConstants.TAG_TEMPBONUSACTIVE).append(":N"); } /* * Why do we loop through the bonuses again? It is looped through * again so that only items associated with this source (e.g. * Template and Target object) are written, but that ALL of the * items are written on one line. */ for (Map.Entry<BonusObj, BonusManager.TempBonusInfo> subme : sortedbonus) { BonusObj subBonus = subme.getKey(); TempBonusInfo subtbi = subme.getValue(); Object cObj = subtbi.source; Object tObj = subtbi.target; final String inString = tempBonusName(cObj, tObj); if (inString.equals(outString)) { buffer.append('|'); buffer.append(IOConstants.TAG_TEMPBONUSBONUS).append(':'); buffer.append(EntityEncoder.encode(subBonus.getPCCText())); } } buffer.append(IOConstants.LINE_SEP); } } /* * ############################################################### * Character Templates methods * ############################################################### */ private void appendTemplateLines(StringBuilder buffer) { for (PCTemplate template : charDisplay.getTemplateSet()) { // // TEMPLATESAPPLIED:[NAME:<template_name>] // TEMPLATESAPPLIED:[NAME:<template_name>|CHOSENFEAT:[KEY:<key>|VALUE:<value>]CHOSENFEAT:[KEY:<key>|VALUE:<value>]...CHOSENFEAT:[KEY:<key>|VALUE:<value>]] // buffer.append(IOConstants.TAG_TEMPLATESAPPLIED).append(':').append('['); buffer.append(IOConstants.TAG_NAME).append(':').append( EntityEncoder.encode(template.getKeyName())); final String chosenFeats = chosenFeats(template); if (!chosenFeats.isEmpty()) { buffer.append('|').append(chosenFeats); } // // Save list of template names 'owned' by current template // Collection<PCTemplate> templatesAdded = thePC.getTemplatesAdded(template); if (templatesAdded != null) { for (PCTemplate ownedTemplate : templatesAdded) { buffer.append('|').append(IOConstants.TAG_CHOSENTEMPLATE).append(':') .append('['); buffer.append(IOConstants.TAG_NAME).append(':').append( EntityEncoder.encode(ownedTemplate.getKeyName())); buffer.append(']'); } } List<String> assocList = thePC.getAssociationList(template); if (assocList != null && !assocList.isEmpty()) { buffer.append(IOConstants.TAG_SEPARATOR); buffer.append(IOConstants.TAG_APPLIEDTO).append(IOConstants.TAG_END); boolean first = true; for (String assoc : assocList) { if (!first) { buffer.append(Constants.COMMA); } first = false; buffer.append(EntityEncoder.encode(assoc)); } } buffer.append(']'); appendAddTokenInfo(buffer, template); buffer.append(IOConstants.LINE_SEP); } } private void appendUseTempModsLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_USETEMPMODS).append(':'); buffer.append(thePC.getUseTempMods() ? 'Y' : 'N'); buffer.append(IOConstants.LINE_SEP); } /* * ############################################################### * Character Weapon proficiencies methods * ############################################################### */ private void appendWeaponProficiencyLines(StringBuilder buffer) { final int size = charDisplay.getWeaponProfSet().size(); if (size > 0) { /* * since aPC.getWeaponProfList() returns a TreeSet, * we have to put them into an array first. * we do not use TreeSet's toArray()-method since it * makes no guarantees on element order. * * author: Thomas Behr 08-09-02 */ final String[] weaponProficiencies = new String[size]; int j = 0; for (WeaponProf wp : charDisplay.getSortedWeaponProfs()) { weaponProficiencies[j++] = wp.getKeyName(); } // as per Mynex's request do not write more than 10 weapons per line final int step = 10; final int times = (size / step) + (((size % step) > 0) ? 1 : 0); for (int k = 0; k < times; ++k) { buffer.append(IOConstants.TAG_WEAPONPROF).append(':'); buffer.append('['); String del = Constants.EMPTY_STRING; int stop = Math.min(size, (k * step) + 10); for (int i = k * step; i < stop; ++i) { buffer.append(del); buffer.append(IOConstants.TAG_WEAPON).append(':'); buffer.append(EntityEncoder.encode(weaponProficiencies[i])); del = "|"; //$NON-NLS-1$ } buffer.append(']'); buffer.append(IOConstants.LINE_SEP); } } // // Save any selected racial bonus weapons // appendWeaponProficiencyLines(buffer, charDisplay.getRace()); // // Save any selected template bonus weapons // for (PCTemplate pct : charDisplay.getTemplateSet()) { appendWeaponProficiencyLines(buffer, pct); } // // Save any selected class bonus weapons // for (final PCClass pcClass : charDisplay.getClassSet()) { appendWeaponProficiencyLines(buffer, pcClass); } } private void appendWeaponProficiencyLines(StringBuilder buffer, CDOMObject source) { if (source == null) { return; } final List<? extends WeaponProf> profs = thePC.getBonusWeaponProfs(source); if (profs == null || profs.isEmpty()) { return; } // TODO refactor this section and the code above that calls it so share this // As per Mynex's request do not write more than 10 weapons per line final int step = 10; final int times = (profs.size() / step) + 1; for (int k = 0; k < times; ++k) { buffer.append(IOConstants.TAG_WEAPONPROF).append(':'); buffer.append('['); String del = Constants.EMPTY_STRING; int stop = Math.min(profs.size(), (k * step) + 10); for (int i = k * step; i < stop; ++i) { buffer.append(del); buffer.append(IOConstants.TAG_WEAPON).append(':'); buffer.append(EntityEncoder.encode(profs.get(i).getLSTformat())); del = "|"; //$NON-NLS-1$ } buffer.append(']'); buffer.append('|'); appendSourceInTaggedFormat(buffer, source); buffer.append(IOConstants.LINE_SEP); } } /* * ############################################################### * Character Equipment methods * ############################################################### */ private void appendMoneyLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_MONEY).append(':'); buffer.append(thePC.getGold().toString()); buffer.append(IOConstants.LINE_SEP); } private void appendWeightLine(StringBuilder buffer) { buffer.append(IOConstants.TAG_WEIGHT).append(':'); buffer.append(charDisplay.getWeight()); buffer.append(IOConstants.LINE_SEP); } private String chosenFeats(PCTemplate pct) { final StringBuilder aString = new StringBuilder(50); for (PCTemplate rlt : pct.getSafeListFor(ListKey.REPEATLEVEL_TEMPLATES)) { for (PCTemplate lt : rlt.getSafeListFor(ListKey.LEVEL_TEMPLATES)) { List<? extends CNAbilitySelection> featList = thePC .getTemplateFeatList(lt); if (featList != null) { writeTemplateFeat(aString, lt, featList); } } } for (PCTemplate lt : pct.getSafeListFor(ListKey.LEVEL_TEMPLATES)) { List<? extends CNAbilitySelection> featList = thePC .getTemplateFeatList(lt); if (featList != null) { writeTemplateFeat(aString, lt, featList); } } for (PCTemplate lt : pct.getSafeListFor(ListKey.HD_TEMPLATES)) { List<? extends CNAbilitySelection> featList = thePC .getTemplateFeatList(lt); if (featList != null) { writeTemplateFeat(aString, lt, featList); } } return aString.toString(); } private void writeTemplateFeat(StringBuilder aString, PCTemplate pct, List<? extends CNAbilitySelection> featList) { for (CNAbilitySelection s : featList) { if (aString.length() != 0) { aString.append('|'); } String featKey = Compatibility.getKeyFor(pct); aString.append(IOConstants.TAG_CHOSENFEAT).append(':'); aString.append('['); aString.append(IOConstants.TAG_MAPKEY).append(':').append( EntityEncoder.encode(featKey)).append('|'); aString.append(IOConstants.TAG_MAPVALUE).append(':').append( EntityEncoder.encode(s.getPersistentFormat())); aString.append(']'); } } /** * Convenience Method * * <br>author: Thomas Behr 19-03-02 * * @param s the String which will be converted into a comment; * i.e. '#','\r' will be removed, * '\t','\f' will be replaced with ' ', * and each line will start with "# " * @return the newly created comment */ private static String createComment(String s) { String work = s + IOConstants.LINE_SEP; work = work.replace('\t', ' '); work = work.replace('\f', ' '); StringBuilder buffer = new StringBuilder(work.length() + 100); StringTokenizer tokens = new StringTokenizer(work, "#"); //$NON-NLS-1$ while (tokens.hasMoreTokens()) { buffer.append(tokens.nextToken()); } work = buffer.toString(); buffer.setLength(0); /* * Need to keep the Windows line separator as newline delimiter to ensure * cross-platform portability. * * author: Thomas Behr 2002-11-13 */ tokens = new StringTokenizer(work, "\r\n"); //$NON-NLS-1$ while (tokens.hasMoreTokens()) { buffer.append("# ").append(tokens.nextToken()).append(IOConstants.LINE_SEP); //$NON-NLS-1$ } return buffer.toString(); } /** * creates a unique tuple based on the creator and target getName() * @param creator * @param target * @return temp bonus name **/ private String tempBonusName(final Object creator, Object target) { final StringBuilder cb = new StringBuilder(100); cb.append(IOConstants.TAG_TEMPBONUS).append(':'); if (creator instanceof CDOMObject) { final CDOMObject oCreator = (CDOMObject) creator; if (oCreator instanceof Ability) { cb.append(IOConstants.TAG_FEAT).append('='); } else if (oCreator instanceof Spell) { cb.append(IOConstants.TAG_SPELL).append('='); } else if (oCreator instanceof Equipment) { cb.append(IOConstants.TAG_EQUIPMENT).append('='); } else if (oCreator instanceof PCClass) { cb.append(IOConstants.TAG_CLASS).append('='); } else if (oCreator instanceof PCTemplate) { cb.append(IOConstants.TAG_TEMPLATE).append('='); } else if (oCreator instanceof Skill) { cb.append(IOConstants.TAG_SKILL).append('='); } else { cb.append(IOConstants.TAG_ERROR).append('='); } cb.append(EntityEncoder.encode(oCreator.getKeyName())); // Hmm, need to get the Type of oCreater also? // Might be required so the PCGVer2Parser can search correct type to re-create } else { return Constants.EMPTY_STRING; } cb.append('|'); cb.append(IOConstants.TAG_TEMPBONUSTARGET).append(':'); if (target instanceof PlayerCharacter) { cb.append(IOConstants.TAG_PC); } else if (target instanceof Equipment) { cb.append(EntityEncoder.encode(((Equipment) target).getName())); } return cb.toString(); } // // Remember what choices were made for each of the ADD: tags // private void appendLevelAbilityInfo(StringBuilder buffer, CDOMObject pObj) { appendAddTokenInfo(buffer, pObj); } private void appendAddTokenInfo(StringBuilder buffer, CDOMObject pObj) { List<PersistentTransitionChoice<?>> addList = pObj.getListFor(ListKey.ADD); if (addList == null) { return; } for (PersistentTransitionChoice<?> tc : addList) { addChoices(buffer, tc); } } private <T> void addChoices(StringBuilder buffer, PersistentTransitionChoice<T> tc) { List<Object> assocList = thePC.getAssocList(tc, AssociationListKey.ADD); if (assocList == null) { return; } // // |ADD:[PROMPT:SUBTOKEN|blah|CHOICE:choice1|CHOICE:choice2|CHOICE:choice3...] // SelectableSet<?> choices = tc.getChoices(); buffer.append('|').append(IOConstants.TAG_ADDTOKEN).append(':').append('['); buffer.append(EntityEncoder.encode(choices.getName())).append(':'); buffer.append(EntityEncoder.encode(choices.getLSTformat())); for (Object assoc : assocList) { buffer.append('|').append(IOConstants.TAG_CHOICE).append(':') .append(EntityEncoder.encode(tc.encodeChoice(tc .castChoice(assoc)))); } buffer.append(']'); } }