@Override
  public String evaluate(PlayerCharacter pc) {
    Skill skill = Globals.getContext().ref.silentlyGetConstructedCDOMObject(Skill.class, rank);
    if (skill == null || !pc.hasSkill(skill)) {
      return "0.0";
    }

    return SkillRankControl.getRank(pc, skill).toString();
  }
Пример #2
0
  /**
   * Needs documentation.
   *
   * @param pc update skills for this PC
   * @param aSkill Skill to update
   * @param aRank Number of ranks to add
   * @param aCost Cost of added ranks
   * @param langList Languages to be selected for a language skill
   * @param pcClass skills apply to this class
   * @return <code>true</code> for success TODO What about throwing on failure?
   */
  private boolean updatePCSkills(
      final PlayerCharacter pc,
      final Skill aSkill,
      final int aRank,
      final double aCost,
      List<Language> langList,
      final PCClass pcClass) {
    pc.addSkill(aSkill);

    boolean oldImporting = pc.isImporting();
    pc.setImporting(true);
    final String aString = SkillRankControl.modRanks(aRank, pcClass, true, pc, aSkill);
    pc.setImporting(oldImporting);

    if (aString.length() > 0) {
      Logging.errorPrint("SKILL: " + aString);
      return false;
    }

    // Add any supplied languages
    ChoiceManagerList<Language> controller =
        ChooserUtilities.getConfiguredController(aSkill, pc, null, new ArrayList<String>());
    for (Language lang : langList) {
      if (!controller.conditionallyApply(pc, lang)) {
        Logging.errorPrint("Failed to apply Language into Skill: " + lang.getLSTformat());
      }
    }

    //
    // Fix up the skill pools to reflect what we just spent.
    //
    double ptsToSpend = aCost;
    if (ptsToSpend >= 0.0) {
      for (PCLevelInfo info : pc.getLevelInfo()) {
        if (info.getClassKeyName().equals(pcClass.getKeyName())) {
          // We are spending this class' points.
          int remaining = info.getSkillPointsRemaining();
          if (remaining == 0) {
            continue;
          }
          int left = remaining - (int) Math.min(remaining, ptsToSpend);
          info.setSkillPointsRemaining(left);
          ptsToSpend -= (remaining - left);
          if (ptsToSpend <= 0) {
            break;
          }
        }
      }
    }
    return true;
  }
Пример #3
0
  /* (non-Javadoc)
   * @see junit.framework.TestCase#setUp()
   */
  @Override
  protected void setUp() throws Exception {
    super.setUp();
    final PlayerCharacter character = getCharacter();

    myClass = new PCClass();
    myClass.setName("My Class");

    knowledge = new Skill();
    Globals.getContext().unconditionallyProcess(knowledge, "CLASSES", "My Class");
    knowledge.setName("KNOWLEDGE (ARCANA)");
    TestHelper.addType(knowledge, "KNOWLEDGE.INT");
    character.addSkill(knowledge);
    SkillRankControl.modRanks(8.0, myClass, true, character, knowledge);
  }
Пример #4
0
  /**
   * Test to ensure that a number of skills test will correctly require a number of separate skills
   * at the required level.
   *
   * @throws Exception
   */
  public void testMultiSkills() throws Exception {
    final PreSkillParser producer = new PreSkillParser();

    final Prerequisite prereq = producer.parse("SKILL", "2,TYPE.Knowledge=4", false, false);
    final PlayerCharacter character = getCharacter();
    boolean passes = PrereqHandler.passes(prereq, character, null);
    assertFalse("Should not pass 2 knowledge skill test with 1 skill", passes);

    final Skill extraKnow = new Skill();
    Globals.getContext().unconditionallyProcess(extraKnow, "CLASSES", "MyClass");
    extraKnow.setName("KNOWLEDGE (RELIGION)");
    TestHelper.addType(extraKnow, "KNOWLEDGE.INT");
    character.addSkill(extraKnow);
    SkillRankControl.modRanks(5.0, myClass, true, character, extraKnow);

    passes = PrereqHandler.passes(prereq, character, null);
    assertTrue("Should pass 2 knowledge skill test with 2 skills", passes);

    character.removeSkill(knowledge);
    character.calcActiveBonuses();
  }
Пример #5
0
  public static String getRanksExplanation(PlayerCharacter pc, Skill sk) {
    StringBuilder sb = new StringBuilder(100);
    boolean needComma = false;
    for (PCClass pcc : pc.getSkillRankClasses(sk)) {
      if (needComma) {
        sb.append(", ");
      }
      sb.append(pcc == null ? "None" : pcc.getKeyName());
      sb.append(':');
      Double rank = pc.getSkillRankForClass(sk, pcc);
      sb.append(rank == null ? 0 : rank);
      needComma = true;
    }
    double bonus = SkillRankControl.getSkillRankBonusTo(pc, sk);
    if (bonus != 0d) {
      if (sb.length() > 0) {
        sb.append("; ");
      }

      sb.append("Skillrank bonus ");
      sb.append(NumberFormat.getNumberInstance().format(bonus));
    }
    return sb.toString();
  }
Пример #6
0
  /**
   * 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();
  }
Пример #7
0
  void subLevel(final PlayerCharacter aPC) {

    if (aPC != null) {
      int total = aPC.getTotalLevels();

      int oldLevel = aPC.getLevel(this);
      int spMod = 0;
      final PCLevelInfo pcl = aPC.getLevelInfoFor(getKeyName(), oldLevel);

      if (pcl != null) {
        spMod = pcl.getSkillPointsGained(aPC);
      } else {
        Logging.errorPrint(
            "ERROR: could not find class/level info for " + getDisplayName() + "/" + oldLevel);
      }

      final int newLevel = oldLevel - 1;

      if (oldLevel > 0) {
        PCClassLevel classLevel = aPC.getActiveClassLevel(this, oldLevel - 1);
        aPC.removeHP(classLevel);
      }

      //			aPC.adjustFeats(-aPC.getBonusFeatsForNewLevel(this));
      setLevel(newLevel, aPC);
      aPC.removeKnownSpellsForClassLevel(this);

      doMinusLevelMods(aPC, newLevel + 1);

      DomainApplication.removeDomainsForLevel(this, newLevel + 1, aPC);

      if (newLevel == 0) {
        SubClassApplication.setSubClassKey(aPC, this, Constants.NONE);

        //
        // Remove all skills associated with this class
        //
        for (Skill skill : aPC.getSkillSet()) {
          SkillRankControl.setZeroRanks(this, aPC, skill);
        }

        Integer currentPool = aPC.getSkillPool(this);
        spMod = currentPool == null ? 0 : currentPool;
      }

      if (!isMonster() && (total > aPC.getTotalLevels())) {
        total = aPC.getTotalLevels();

        // Roll back any stat changes that were made as part of the
        // level

        final List<PCLevelInfoStat> moddedStats = new ArrayList<>();
        if (pcl.getModifiedStats(true) != null) {
          moddedStats.addAll(pcl.getModifiedStats(true));
        }
        if (pcl.getModifiedStats(false) != null) {
          moddedStats.addAll(pcl.getModifiedStats(false));
        }
        if (!moddedStats.isEmpty()) {
          for (PCLevelInfoStat statToRollback : moddedStats) {
            for (PCStat aStat : aPC.getStatSet()) {
              if (aStat.equals(statToRollback.getStat())) {
                aPC.setStat(aStat, aPC.getStat(aStat) - statToRollback.getStatMod());
                break;
              }
            }
          }
        }
      }

      aPC.setLevelWithoutConsequence(this, newLevel);

      if (isMonster() || (total != 0)) {
        Integer currentPool = aPC.getSkillPool(this);
        int newSkillPool = (currentPool == null ? 0 : currentPool) - spMod;
        aPC.setSkillPool(this, newSkillPool);
        aPC.setDirty(true);
      }

      if (aPC.getLevel(this) == 0) {
        aPC.removeClass(this);
      }

      aPC.validateCharacterDomains();

      if (!aPC.isImporting()) {
        final int maxxp = aPC.minXPForNextECL();
        if (aPC.getXP() >= maxxp) {
          aPC.setXP(Math.max(maxxp - 1, 0));
        }
      }
    } else {
      Logging.errorPrint("No current pc in subLevel()? How did this happen?");

      return;
    }
  }
Пример #8
0
  private KitSkillAdd addRanks(
      PlayerCharacter pc,
      PCClass pcClass,
      Skill aSkill,
      double ranksLeftToAdd,
      boolean isFree,
      List<String> warnings) {
    if (!isFree && pcClass.getSkillPool(pc) == 0) {
      return null;
    }

    double curRank = 0.0;
    if (pc.hasSkill(aSkill)) {
      curRank = pc.getRank(aSkill).doubleValue();
    }
    double ranksToAdd = ranksLeftToAdd;
    if (!Globals.checkRule(RuleConstants.SKILLMAX) && (ranksToAdd > 0.0)) {
      ranksToAdd = Math.min(pc.getMaxRank(aSkill, pcClass).doubleValue(), curRank + ranksLeftToAdd);
      ranksToAdd -= curRank;
      if (!CoreUtility.doublesEqual(ranksToAdd, ranksLeftToAdd)) {
        warnings.add(
            "SKILL: Could not add "
                + (ranksLeftToAdd - ranksToAdd)
                + " to "
                + aSkill.getDisplayName()
                + ". Exceeds MAXRANK of "
                + pc.getMaxRank(aSkill, pcClass)
                + ".");
      }
    }
    int ptsToSpend = 0;
    int[] points = new int[pc.getLevelInfoSize()];
    if (!isFree) {
      double ranksAdded = 0.0;
      int skillCost = pc.getSkillCostForClass(aSkill, pcClass).getCost();
      ptsToSpend = (int) (ranksToAdd * skillCost);
      for (int i = 0; i < pc.getLevelInfoSize(); i++) {
        PCLevelInfo info = pc.getLevelInfo(i);
        if (info.getClassKeyName().equals(pcClass.getKeyName())) {
          // We are spending this class' points.
          points[i] = info.getSkillPointsRemaining();
        } else {
          points[i] = -1;
        }
      }
      for (int i = 0; i < points.length; i++) {
        int remaining = points[i];
        if (remaining <= 0) {
          continue;
        }
        int left = remaining - Math.min(remaining, ptsToSpend);
        points[i] = left;
        int spent = (remaining - left);
        ptsToSpend -= spent;
        ranksAdded += ((double) spent / (double) skillCost);
        if (ranksAdded == ranksToAdd || ptsToSpend <= 0) {
          break;
        }
      }

      ranksToAdd = ranksAdded;
      ptsToSpend = (int) (ranksToAdd * skillCost);
    }
    pc.addSkill(aSkill);

    String ret = SkillRankControl.modRanks(ranksToAdd, pcClass, false, pc, aSkill);
    if (ret.length() > 0) {
      if (isFree && ret.indexOf("You do not have enough skill points.") != -1) {
        SkillRankControl.modRanks(ranksToAdd, pcClass, true, pc, aSkill);
      } else {
        warnings.add(ret);
        return null;
      }
    }
    if (!isFree) {
      for (int i = 0; i < pc.getLevelInfoSize(); i++) {
        PCLevelInfo info = pc.getLevelInfo(i);
        if (points[i] >= 0) {
          info.setSkillPointsRemaining(points[i]);
        }
      }
    }
    List<Language> langList = new ArrayList<Language>();
    if (ChooseActivation.hasChooseToken(aSkill) && !selection.isEmpty()) {
      ChoiceManagerList<Language> controller =
          ChooserUtilities.getConfiguredController(aSkill, pc, null, new ArrayList<String>());
      int limit = (int) ranksToAdd;
      for (CDOMSingleRef<Language> ref : selection) {
        Language lang = ref.resolvesTo();
        if (controller.conditionallyApply(pc, lang)) {
          langList.add(lang);
          limit--;
        }
        if (limit <= 0) {
          break;
        }
      }
    }
    return new KitSkillAdd(aSkill, ranksToAdd, ptsToSpend, langList, pcClass);
  }