@Override public String[] unparse(LoadContext context, PCClass obj) { Changes<BonusObj> changes = context.getObjectContext().getListChanges(obj, ListKey.BONUS); if (changes == null || changes.isEmpty()) { // Empty indicates no token present return null; } // CONSIDER need to deal with removed... Collection<BonusObj> added = changes.getAdded(); String tokenName = getTokenName(); Set<String> bonusSet = new TreeSet<String>(); for (BonusObj bonus : added) { if (tokenName.equals(bonus.getTokenSource())) { StringBuilder sb = new StringBuilder(); sb.append(bonus.getValue()); List<Prerequisite> prereqList = new ArrayList<Prerequisite>(bonus.getPrerequisiteList()); Prerequisite prereq = getPrerequisite("PRELEVELMAX:1"); prereqList.remove(prereq); if (!prereqList.isEmpty()) { sb.append('|'); sb.append(getPrerequisiteString(context, prereqList)); } bonusSet.add(sb.toString()); } } if (bonusSet.isEmpty()) { // This is okay - just no BONUSes from this token return null; } return bonusSet.toArray(new String[bonusSet.size()]); }
/** * Add a CLASS via a BONUS * * @return true if successful */ public static boolean addBonusClass(Class bonusClass) throws InstantiationException, IllegalAccessException { if (BonusObj.class.isAssignableFrom(bonusClass)) { final BonusObj bonusObj = (BonusObj) bonusClass.newInstance(); BONUS_TAG_MAP.put(bonusObj.getBonusHandled(), bonusClass); return true; } return false; }
private static boolean bonusForThisSkill(BonusObj bonus, String keyName) { for (Object target : bonus.getBonusInfoList()) { if (String.valueOf(target).equalsIgnoreCase(keyName)) { return true; } } return false; }
@Override protected ParseResult parseNonEmptyToken(LoadContext context, PCClass pcc, String value) { BonusObj bon = Bonus.newBonus(context, "MONSKILLPTS|NUMBER|" + value); if (bon == null) { return new ParseResult.Fail( getTokenName() + " was given invalid bonus value: " + value, context); } Prerequisite prereq = getPrerequisite("PRELEVELMAX:1"); if (prereq == null) { return new ParseResult.Fail( "Internal Error: " + getTokenName() + " had invalid prerequisite", context); } bon.addPrerequisite(prereq); bon.setTokenSource(getTokenName()); context.getObjectContext().addToList(pcc, ListKey.BONUS, bon); return ParseResult.SUCCESS; }
public static String getSituationModifierExplanation( Skill sk, String situation, PlayerCharacter aPC, boolean shortForm) { List<String> explanation = new ArrayList<>(); String keyName = sk.getKeyName(); String bonusKey = ("SITUATION." + keyName + "=" + situation).toUpperCase(); for (BonusObj bonus : aPC.getActiveBonusList()) { // calculate bonus and add to activeBonusMap if (aPC.isApplied(bonus) && "SITUATION".equals(bonus.getBonusName())) { boolean include = bonusForThisSkill(bonus, keyName); if (!include) { for (BonusPair bp : aPC.getStringListFromBonus(bonus)) { String bpKey = bp.fullyQualifiedBonusType.toUpperCase(); if (bpKey.equals(bonusKey)) { include = true; break; } } } if (include) { double iBonus = 0; for (BonusPair bp : aPC.getStringListFromBonus(bonus)) { String bpKey = bp.fullyQualifiedBonusType.toUpperCase(); if (bpKey.startsWith(bonusKey)) { iBonus += bp.resolve(aPC).doubleValue(); } } if (!CoreUtility.doublesEqual(iBonus, 0.0)) { explanation.add(Delta.toString((int) iBonus) + aPC.getBonusContext(bonus, shortForm)); } } } } return StringUtil.join(explanation, " "); }
/** * Builds up a string describing what makes up the misc modifier for a skill for a character. This * can either be in long form '+2[skill TUMBLE gteq 5|TYPE=SYNERGY.STACK]' or in short form * '+2[TUMBLE]'. Any modifiers that cannot be determined will be displayed as a single entry of * 'OTHER'. * * @param aPC The character associated with this skill. * @param shortForm True if the abbreviated form should be used. * @return The explanation of the misc modifier's make-up. */ public static String getModifierExplanation(Skill sk, PlayerCharacter aPC, boolean shortForm) { double bonusObjTotal = 0.0; List<String> explanation = new ArrayList<>(); String keyName = sk.getKeyName(); String bonusKey = ("SKILL." + keyName).toUpperCase(); for (BonusObj bonus : aPC.getActiveBonusList()) { // calculate bonus and add to activeBonusMap if (aPC.isApplied(bonus) && "SKILL".equals(bonus.getBonusName())) { boolean include = bonusForThisSkill(bonus, keyName); if (!include) { for (BonusPair bp : aPC.getStringListFromBonus(bonus)) { String bpKey = bp.fullyQualifiedBonusType.toUpperCase(); if (bpKey.equals(bonusKey)) { include = true; break; } } } if (include) { double iBonus = 0; for (BonusPair bp : aPC.getStringListFromBonus(bonus)) { String bpKey = bp.fullyQualifiedBonusType.toUpperCase(); if (bpKey.startsWith(bonusKey)) { iBonus += bp.resolve(aPC).doubleValue(); } } if (!CoreUtility.doublesEqual(iBonus, 0.0)) { explanation.add(Delta.toString((int) iBonus) + aPC.getBonusContext(bonus, shortForm)); bonusObjTotal += iBonus; } } } } StringBuilder bonusDetails = new StringBuilder(); bonusDetails.append(StringUtil.joinToStringBuilder(explanation, " ")); // TODO: Need to add other bonuses which are not encoded as bonus // objects // - familiars, racial, feats - and add them to bonusObjTotal double bonus; CDOMSingleRef<PCStat> statref = sk.get(ObjectKey.KEY_STAT); if (statref != null) { PCStat stat = statref.get(); bonus = aPC.getStatModFor(stat); bonus += aPC.getTotalBonusTo("SKILL", "STAT." + stat.getKeyName()); SkillCostDisplay.appendBonusDesc(bonusDetails, bonus, "STAT"); } // The catch-all for non-bonusObj modifiers. bonus = aPC.getTotalBonusTo("SKILL", keyName) - bonusObjTotal; SkillCostDisplay.appendBonusDesc(bonusDetails, bonus, "OTHER"); // loop through all current skill types checking for boni for (Type singleType : sk.getTrueTypeList(false)) { bonus = aPC.getTotalBonusTo("SKILL", "TYPE." + singleType); SkillCostDisplay.appendBonusDesc(bonusDetails, bonus, "TYPE." + singleType); } // now check for any lists of skills, etc bonus = aPC.getTotalBonusTo("SKILL", "LIST"); SkillCostDisplay.appendBonusDesc(bonusDetails, bonus, "LIST"); // now check for ALL bonus = aPC.getTotalBonusTo("SKILL", "ALL"); SkillCostDisplay.appendBonusDesc(bonusDetails, bonus, "ALL"); // these next two if-blocks try to get BONUS:[C]CSKILL|TYPE=xxx|y to // function if (aPC.isClassSkill(sk)) { bonus = aPC.getTotalBonusTo("CSKILL", keyName); SkillCostDisplay.appendBonusDesc(bonusDetails, bonus, "CSKILL"); // loop through all current skill types checking for boni for (Type singleType : sk.getTrueTypeList(false)) { bonus = aPC.getTotalBonusTo("CSKILL", "TYPE." + singleType); SkillCostDisplay.appendBonusDesc(bonusDetails, bonus, "CSKILL"); } bonus = aPC.getTotalBonusTo("CSKILL", "LIST"); SkillCostDisplay.appendBonusDesc(bonusDetails, bonus, "CSKILL"); } if (!aPC.isClassSkill(sk) && !sk.getSafe(ObjectKey.EXCLUSIVE)) { bonus = aPC.getTotalBonusTo("CCSKILL", keyName); SkillCostDisplay.appendBonusDesc(bonusDetails, bonus, "CCSKILL"); // loop through all current skill types checking for boni for (Type singleType : sk.getTrueTypeList(false)) { bonus = aPC.getTotalBonusTo("CCSKILL", "TYPE." + singleType); SkillCostDisplay.appendBonusDesc(bonusDetails, bonus, "CCSKILL"); } bonus = aPC.getTotalBonusTo("CCSKILL", "LIST"); SkillCostDisplay.appendBonusDesc(bonusDetails, bonus, "CCSKILL"); } // Encumbrance int aCheckMod = sk.getSafe(ObjectKey.ARMOR_CHECK).calculateBonus(aPC); SkillCostDisplay.appendBonusDesc(bonusDetails, aCheckMod, "ARMOR"); String aString = SettingsHandler.getGame().getRankModFormula(); if (!aString.isEmpty()) { aString = aString.replaceAll( Pattern.quote("$$RANK$$"), SkillRankControl.getTotalRank(aPC, sk).toString()); bonus = aPC.getVariableValue(aString, "").intValue(); SkillCostDisplay.appendBonusDesc(bonusDetails, bonus, "RANKS"); } return bonusDetails.toString(); }
/** * Sets all the BonusObj's to "active" * * @param aPC */ @Override public void activateBonuses(final PlayerCharacter aPC) { for (BonusObj bonus : getBonuses()) { aPC.setApplied(bonus, bonus.qualifies(aPC, null)); } }
/* * REFACTOR There is potentially redundant information here - level and PC... * is this ever out of sync or can this method be removed/made private?? */ public double getBonusTo( final String argType, final String argMname, final int asLevel, final PlayerCharacter aPC) { double i = 0; List<BonusObj> rawBonusList = getRawBonusList(aPC); for (int lvl = 1; lvl < asLevel; lvl++) { rawBonusList.addAll(aPC.getActiveClassLevel(this, lvl).getRawBonusList(aPC)); } if ((asLevel == 0) || rawBonusList.isEmpty()) { return 0; } final String type = argType.toUpperCase(); final String mname = argMname.toUpperCase(); for (final BonusObj bonus : rawBonusList) { final StringTokenizer breakOnPipes = new StringTokenizer(bonus.toString().toUpperCase(), Constants.PIPE, false); final String theType = breakOnPipes.nextToken(); if (!theType.equals(type)) { continue; } final String str = breakOnPipes.nextToken(); final StringTokenizer breakOnCommas = new StringTokenizer(str, Constants.COMMA, false); while (breakOnCommas.hasMoreTokens()) { final String theName = breakOnCommas.nextToken(); if (theName.equals(mname)) { final String aString = breakOnPipes.nextToken(); final List<Prerequisite> localPreReqList = new ArrayList<>(); if (bonus.hasPrerequisites()) { localPreReqList.addAll(bonus.getPrerequisiteList()); } // TODO: This code should be removed after the 5.8 release // as the prereqs are processed by the bonus loading code. while (breakOnPipes.hasMoreTokens()) { final String bString = breakOnPipes.nextToken(); if (PreParserFactory.isPreReqString(bString)) { Logging.debugPrint( "Why is this prerequisite '" + bString + "' parsed in '" + getClass().getName() + ".getBonusTo(String,String,int)' rather than in the persistence layer?"); //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ try { final PreParserFactory factory = PreParserFactory.getInstance(); localPreReqList.add(factory.parse(bString)); } catch (PersistenceLayerException ple) { Logging.errorPrint(ple.getMessage(), ple); } } } // must meet criteria for bonuses before adding them in // TODO: This is a hack to avoid VARs etc in class defs // being qualified for when Bypass class prereqs is // selected. // Should we be passing in the BonusObj here to allow it to // be referenced in Qualifies statements? if (PrereqHandler.passesAll(localPreReqList, aPC, null)) { final double j = aPC.getVariableValue(aString, getQualifiedKey()).doubleValue(); i += j; } } } } return i; }