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();
  }