/* * PCLevelInfo.java * Copyright 2001 (C) Greg Bingleman <byngl@hotmail.com> * * 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 November 29, 2002, 10:38 PM * * $Id$ */ package pcgen.core.pclevelinfo; import java.util.ArrayList; import java.util.List; import pcgen.base.lang.ObjectUtil; import pcgen.core.Globals; import pcgen.core.PCClass; import pcgen.core.PCStat; import pcgen.core.PlayerCharacter; import pcgen.core.PointBuyMethod; import pcgen.core.SettingsHandler; import pcgen.core.bonus.BonusObj; import pcgen.core.bonus.BonusUtilities; /** * {@code PCLevelInfo}. * * Represents the data kept about a level that a PC has added. * * @author Greg Bingleman <byngl@hotmail.com> */ public final class PCLevelInfo implements Cloneable { private List<PCLevelInfoStat> statsPostModified = null; private List<PCLevelInfoStat> statsPreModified = null; private String classKeyName = ""; private int classLevel = 0; private int skillPointsGained = Integer.MIN_VALUE; private int skillPointsRemaining = 0; /** * Creates a new PCLevelInfo object. * * @param argClassKeyName The KeyName of the class taken at this level */ public PCLevelInfo(final String argClassKeyName) { super(); classKeyName = argClassKeyName; } /** * Set the Class at this level * * @param argClassKeyName the KeyName of the class */ public void setClassKeyName(final String argClassKeyName) { classKeyName = argClassKeyName; } /** * @return the Keyname of the Class at this level */ public String getClassKeyName() { return classKeyName; } /** * Set the level that this represents * * @param arg an int representing the level */ public void setClassLevel(final int arg) { classLevel = arg; } /** * @return an int representing the level */ public int getClassLevel() { return classLevel; } /** * Get a list of character stats * * @param preMod Whether any increment gaind at this level should be * applied * * @return a list of character stats at this level */ public List<PCLevelInfoStat> getModifiedStats(final boolean preMod) { List<PCLevelInfoStat> result = statsPostModified; if (preMod) { result = statsPreModified; } return result; } /** * Set the number of kill points gained at this level * * @param arg the number of skill points gained */ public void setSkillPointsGained(PlayerCharacter aPC, final int arg) { final int bonusPoints = getBonusSkillPool(aPC); setFixedSkillPointsGained(arg + bonusPoints); } /** * @param pc TODO * @return the number of skill points gained */ public int getSkillPointsGained(PlayerCharacter pc) { // If this information in not saved on PCG, then try to recalc it if ((skillPointsGained == Integer.MIN_VALUE) && (!classKeyName.isEmpty())) { final PCClass aClass = Globals.getContext().getReferenceContext().silentlyGetConstructedCDOMObject(PCClass.class, classKeyName); skillPointsGained = pc.recalcSkillPointMod(aClass, classLevel) + getBonusSkillPool(pc); } return skillPointsGained; } /** * Set the number of skill points gained at this level that have not been * spent yet. * * @param points skill points remaining for this level */ public void setSkillPointsRemaining(final int points) { skillPointsRemaining = points; } /** * @return The number of skill points remaining at this level */ public int getSkillPointsRemaining() { return skillPointsRemaining; } /** * Get the value of a character stat at this level * * @param aStat the Abbreviation of the stat (STR, DEX, etc) * @param includePost whether to include any stat increases gained at * this level * * @return the value of the stat at this level. */ public int getTotalStatMod(final PCStat aStat, final boolean includePost) { int mod = 0; if (statsPreModified != null) { for ( PCLevelInfoStat stat : statsPreModified ) { if (stat.getStat().equals(aStat)) { mod += stat.getStatMod(); } } } if (includePost && (statsPostModified != null)) { for ( PCLevelInfoStat stat : statsPostModified ) { if (stat.getStat().equals(aStat)) { mod += stat.getStatMod(); } } } return mod; } /** * Modify a character stat at this level. Only works with one of the two * stat lists pre or post depending on the value of isPreMod. If the list * doesn't exist yet, an empty one is created, then we search for the stat * which has an abbreviation matching statABB. If we find a match we adjust * it by mod, if we don't find a match set it to mod. If we cant find a * stat matching statABB, make a new on, set its value to mod and store it * in the list. * * @param stat The abbreviation of the stat to modifiy * @param mod The adjustment to make * @param isPreMod Whether the increment should be pre or post the * calculation of other benefits gained at this level. */ public void addModifiedStat( final PCStat stat, final int mod, final boolean isPreMod) { final List<PCLevelInfoStat> statList; if (isPreMod) { if (statsPreModified == null) { statsPreModified = new ArrayList<>(); } statList = statsPreModified; } else { if (statsPostModified == null) { statsPostModified = new ArrayList<>(); } statList = statsPostModified; } PCLevelInfoStat aStat; for (int i = 0; i < statList.size(); ++i) { aStat = statList.get(i); if (stat.equals(aStat.getStat())) { aStat.modifyStat(mod); if (aStat.getStatMod() == 0) { statList.remove(aStat); } return; } } statList.add(new PCLevelInfoStat(stat, mod)); } /** * Calculate the number of bonus skill points added by this level. * * @return the number of bonus skill points added by this level */ private int getBonusSkillPool(PlayerCharacter aPC) { int returnValue = 0; final PCClass aClass = aPC.getClassKeyed(classKeyName); final String purchaseName = SettingsHandler.getGame().getPurchaseModeMethodName(); if (purchaseName != null) { PointBuyMethod pbm = SettingsHandler.getGame().getContext().getReferenceContext() .silentlyGetConstructedCDOMObject(PointBuyMethod.class, purchaseName); List<BonusObj> bonusList = BonusUtilities.getBonusFromList(pbm.getBonuses(), "SKILLPOOL", "NUMBER"); returnValue += (int) aPC.calcBonusFromList(bonusList, null); } if (aClass != null) { // These bonuses apply to the level or higher. We have to add and then remove // the previous to get the effective level bonus returnValue += (int) aClass.getBonusTo("SKILLPOOL", "NUMBER", classLevel, aPC); returnValue -= (int) aClass.getBonusTo("SKILLPOOL", "NUMBER", classLevel - 1, aPC); } if (classLevel == 1) { returnValue += (int) aPC.getTotalBonusTo("SKILLPOOL", "CLASS." + classKeyName); } returnValue += (int) aPC.getTotalBonusTo( "SKILLPOOL", "CLASS." + classKeyName + ";LEVEL." + Integer.toString(classLevel)); returnValue += (int) aPC.getTotalBonusTo( "SKILLPOOL", "LEVEL." + aPC.getCharacterLevel(this)); return returnValue; } @Override public PCLevelInfo clone() { PCLevelInfo clone = new PCLevelInfo(classKeyName); if (statsPostModified != null) { for ( PCLevelInfoStat stat : statsPostModified ) { if (clone.statsPostModified == null) { clone.statsPostModified = new ArrayList<>(); } clone.statsPostModified.add(stat); } } if (statsPreModified != null) { for ( PCLevelInfoStat stat : statsPreModified ) { if (clone.statsPreModified == null) { clone.statsPreModified = new ArrayList<>(); } clone.statsPreModified.add(stat); } } clone.classLevel = classLevel; clone.skillPointsGained = skillPointsGained; clone.skillPointsRemaining = skillPointsRemaining; return clone; } public void setFixedSkillPointsGained(int arg) { skillPointsGained = arg; } @Override public int hashCode() { return classLevel * 17 + classKeyName.hashCode(); } @Override public boolean equals(Object o) { if (o instanceof PCLevelInfo) { PCLevelInfo other = (PCLevelInfo) o; return classLevel == other.classLevel && skillPointsGained == other.skillPointsGained && skillPointsRemaining == other.skillPointsRemaining && classKeyName.equals(other.classKeyName) && ObjectUtil.compareWithNull(statsPreModified, other.statsPreModified) && ObjectUtil.compareWithNull(statsPreModified, other.statsPreModified); } return false; } }