Files
MonsterCards/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java
Tom Hicks 1e1cf1309d Fixes default values for array/set properties of monsters in db.
Removes individual senses properties and replaces with a Set<String>.
2021-06-20 02:14:48 -07:00

777 lines
30 KiB
Java

package com.majinnaibu.monstercards.models;
import android.annotation.SuppressLint;
import androidx.annotation.NonNull;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
import com.majinnaibu.monstercards.data.enums.AbilityScore;
import com.majinnaibu.monstercards.data.enums.AdvantageType;
import com.majinnaibu.monstercards.data.enums.ArmorType;
import com.majinnaibu.monstercards.data.enums.ChallengeRating;
import com.majinnaibu.monstercards.data.enums.ProficiencyType;
import com.majinnaibu.monstercards.helpers.StringHelper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
@Entity(tableName = "monsters")
@SuppressLint("DefaultLocale")
@SuppressWarnings("unused")
public class Monster {
@PrimaryKey
@NonNull
public UUID id;
@NonNull
@ColumnInfo(defaultValue = "")
public String name;
@NonNull()
@ColumnInfo(defaultValue = "")
public String size;
@NonNull()
@ColumnInfo(defaultValue = "")
public String type;
@NonNull()
@ColumnInfo(defaultValue = "")
public String subtype;
@NonNull()
@ColumnInfo(defaultValue = "")
public String alignment;
@ColumnInfo(name = "strength_score", defaultValue = "10")
public int strengthScore;
@ColumnInfo(name = "strength_saving_throw_advantage", defaultValue = "none")
public AdvantageType strengthSavingThrowAdvantage;
@ColumnInfo(name = "strength_saving_throw_proficiency", defaultValue = "none")
public ProficiencyType strengthSavingThrowProficiency;
@ColumnInfo(name = "dexterity_score", defaultValue = "10")
public int dexterityScore;
@ColumnInfo(name = "dexterity_saving_throw_advantage", defaultValue = "none")
public AdvantageType dexteritySavingThrowAdvantage;
@ColumnInfo(name = "dexterity_saving_throw_proficiency", defaultValue = "none")
public ProficiencyType dexteritySavingThrowProficiency;
@ColumnInfo(name = "constitution_score", defaultValue = "10")
public int constitutionScore;
@ColumnInfo(name = "constitution_saving_throw_advantage", defaultValue = "none")
public AdvantageType constitutionSavingThrowAdvantage;
@ColumnInfo(name = "constitution_saving_throw_proficiency", defaultValue = "none")
public ProficiencyType constitutionSavingThrowProficiency;
@ColumnInfo(name = "intelligence_score", defaultValue = "10")
public int intelligenceScore;
@ColumnInfo(name = "intelligence_saving_throw_advantage", defaultValue = "none")
public AdvantageType intelligenceSavingThrowAdvantage;
@ColumnInfo(name = "intelligence_saving_throw_proficiency", defaultValue = "none")
public ProficiencyType intelligenceSavingThrowProficiency;
@ColumnInfo(name = "wisdom_score", defaultValue = "10")
public int wisdomScore;
@ColumnInfo(name = "wisdom_saving_throw_advantage", defaultValue = "none")
public AdvantageType wisdomSavingThrowAdvantage;
@ColumnInfo(name = "wisdom_saving_throw_proficiency", defaultValue = "none")
public ProficiencyType wisdomSavingThrowProficiency;
@ColumnInfo(name = "charisma_score", defaultValue = "10")
public int charismaScore;
@ColumnInfo(name = "charisma_saving_throw_advantage", defaultValue = "none")
public AdvantageType charismaSavingThrowAdvantage;
@ColumnInfo(name = "charisma_saving_throw_proficiency", defaultValue = "none")
public ProficiencyType charismaSavingThrowProficiency;
@ColumnInfo(name = "armor_type", defaultValue = "none"/* ArmorType.NONE.stringValue */)
public ArmorType armorType;
@ColumnInfo(name = "shield_bonus", defaultValue = "0")
public int shieldBonus;
@ColumnInfo(name = "natural_armor_bonus", defaultValue = "0")
public int naturalArmorBonus;
@ColumnInfo(name = "other_armor_description", defaultValue = "")
public String otherArmorDescription;
@ColumnInfo(name = "hit_dice", defaultValue = "1")
public int hitDice;
@ColumnInfo(name = "has_custom_hit_points", defaultValue = "")
public boolean hasCustomHP;
@ColumnInfo(name = "custom_hit_points_description", defaultValue = "")
public String customHPDescription;
@ColumnInfo(name = "walk_speed", defaultValue = "0")
public int walkSpeed;
@ColumnInfo(name = "burrow_speed", defaultValue = "0")
public int burrowSpeed;
@ColumnInfo(name = "climb_speed", defaultValue = "0")
public int climbSpeed;
@ColumnInfo(name = "fly_speed", defaultValue = "0")
public int flySpeed;
@ColumnInfo(name = "can_hover", defaultValue = "false")
public boolean canHover;
@ColumnInfo(name = "swim_speed", defaultValue = "0")
public int swimSpeed;
@ColumnInfo(name = "has_custom_speed", defaultValue = "false")
public boolean hasCustomSpeed;
@ColumnInfo(name = "custom_speed_description")
public String customSpeedDescription;
@ColumnInfo(name = "challenge_rating", defaultValue = "1")
public ChallengeRating challengeRating;
@ColumnInfo(name = "custom_challenge_rating_description", defaultValue = "")
public String customChallengeRatingDescription;
@ColumnInfo(name = "custom_proficiency_bonus", defaultValue = "0")
public int customProficiencyBonus;
@ColumnInfo(name = "telepathy_range", defaultValue = "0")
public int telepathyRange;
@ColumnInfo(name = "understands_but_description", defaultValue = "")
public String understandsButDescription;
@ColumnInfo(name = "senses", defaultValue = "[]")
public Set<String> senses;
@ColumnInfo(name = "skills", defaultValue = "[]")
public Set<Skill> skills;
@ColumnInfo(name = "damage_immunities", defaultValue = "[]")
public Set<String> damageImmunities;
@ColumnInfo(name = "damage_resistances", defaultValue = "[]")
public Set<String> damageResistances;
@ColumnInfo(name = "damage_vulnerabilities", defaultValue = "[]")
public Set<String> damageVulnerabilities;
@ColumnInfo(name = "condition_immunities", defaultValue = "[]")
public Set<String> conditionImmunities;
@ColumnInfo(name = "languages", defaultValue = "[]")
public Set<Language> languages;
@ColumnInfo(name = "abilities", defaultValue = "[]")
public Set<Trait> abilities;
@ColumnInfo(name = "actions", defaultValue = "[]")
public Set<Trait> actions;
@ColumnInfo(name = "reactions", defaultValue = "[]")
public Set<Trait> reactions;
@ColumnInfo(name = "lair_actions", defaultValue = "[]")
public Set<Trait> lairActions;
@ColumnInfo(name = "legendary_actions", defaultValue = "[]")
public Set<Trait> legendaryActions;
@ColumnInfo(name = "regional_actions", defaultValue = "[]")
public Set<Trait> regionalActions;
public Monster() {
id = UUID.randomUUID();
name = "";
size = "";
type = "";
subtype = "";
alignment = "";
strengthScore = 10;
dexterityScore = 10;
constitutionScore = 10;
intelligenceScore = 10;
wisdomScore = 10;
charismaScore = 10;
armorType = ArmorType.NONE;
shieldBonus = 0;
naturalArmorBonus = 0;
otherArmorDescription = "";
hitDice = 1;
hasCustomHP = false;
customHPDescription = "";
walkSpeed = 0;
burrowSpeed = 0;
climbSpeed = 0;
flySpeed = 0;
canHover = false;
swimSpeed = 0;
hasCustomSpeed = false;
customSpeedDescription = "";
challengeRating = ChallengeRating.ONE;
customChallengeRatingDescription = "";
customProficiencyBonus = 0;
telepathyRange = 0;
understandsButDescription = "";
strengthSavingThrowAdvantage = AdvantageType.NONE;
strengthSavingThrowProficiency = ProficiencyType.NONE;
dexteritySavingThrowAdvantage = AdvantageType.NONE;
dexteritySavingThrowProficiency = ProficiencyType.NONE;
constitutionSavingThrowAdvantage = AdvantageType.NONE;
constitutionSavingThrowProficiency = ProficiencyType.NONE;
intelligenceSavingThrowAdvantage = AdvantageType.NONE;
intelligenceSavingThrowProficiency = ProficiencyType.NONE;
wisdomSavingThrowAdvantage = AdvantageType.NONE;
wisdomSavingThrowProficiency = ProficiencyType.NONE;
charismaSavingThrowAdvantage = AdvantageType.NONE;
charismaSavingThrowProficiency = ProficiencyType.NONE;
skills = new HashSet<>();
senses = new HashSet<>();
damageImmunities = new HashSet<>();
damageResistances = new HashSet<>();
damageVulnerabilities = new HashSet<>();
conditionImmunities = new HashSet<>();
languages = new HashSet<>();
abilities = new HashSet<>();
actions = new HashSet<>();
reactions = new HashSet<>();
lairActions = new HashSet<>();
legendaryActions = new HashSet<>();
regionalActions = new HashSet<>();
}
public String getMeta() {
StringBuilder sb = new StringBuilder();
boolean isFirstOutput = true;
if (!StringHelper.isNullOrEmpty(size)) {
sb.append(size);
isFirstOutput = false;
}
if (!StringHelper.isNullOrEmpty(type)) {
if (!isFirstOutput) {
sb.append(" ");
}
sb.append(type);
isFirstOutput = false;
}
if (!StringHelper.isNullOrEmpty(subtype)) {
if (!isFirstOutput) {
sb.append(" ");
}
sb.append("(");
sb.append(subtype);
sb.append(")");
isFirstOutput = false;
}
if (!StringHelper.isNullOrEmpty(alignment)) {
if (!isFirstOutput) {
sb.append(", ");
}
sb.append(alignment);
}
return sb.toString();
}
public int getAbilityScore(AbilityScore abilityScore) {
switch (abilityScore) {
case STRENGTH:
return strengthScore;
case DEXTERITY:
return dexterityScore;
case CONSTITUTION:
return constitutionScore;
case INTELLIGENCE:
return intelligenceScore;
case WISDOM:
return wisdomScore;
case CHARISMA:
return charismaScore;
default:
return 10;
}
}
public static int getAbilityModifierForScore(int score) {
return (int) Math.floor((score - 10) / 2.0);
}
public int getAbilityModifier(AbilityScore abilityScore) {
switch (abilityScore) {
case STRENGTH:
return getStrengthModifier();
case DEXTERITY:
return getDexterityModifier();
case CONSTITUTION:
return getConstitutionModifier();
case INTELLIGENCE:
return getIntelligenceModifier();
case WISDOM:
return getWisdomModifier();
case CHARISMA:
return getCharismaModifier();
default:
return 0;
}
}
public AdvantageType getSavingThrowAdvantageType(AbilityScore abilityScore) {
switch (abilityScore) {
case STRENGTH:
return strengthSavingThrowAdvantage;
case DEXTERITY:
return dexteritySavingThrowAdvantage;
case CONSTITUTION:
return constitutionSavingThrowAdvantage;
case INTELLIGENCE:
return intelligenceSavingThrowAdvantage;
case WISDOM:
return wisdomSavingThrowAdvantage;
case CHARISMA:
return charismaSavingThrowAdvantage;
default:
return AdvantageType.NONE;
}
}
public ProficiencyType getSavingThrowProficiencyType(AbilityScore abilityScore) {
switch (abilityScore) {
case STRENGTH:
return strengthSavingThrowProficiency;
case DEXTERITY:
return dexteritySavingThrowProficiency;
case CONSTITUTION:
return constitutionSavingThrowProficiency;
case INTELLIGENCE:
return intelligenceSavingThrowProficiency;
case WISDOM:
return wisdomSavingThrowProficiency;
case CHARISMA:
return charismaSavingThrowProficiency;
default:
return ProficiencyType.NONE;
}
}
public int getStrengthModifier() {
return getAbilityModifierForScore(strengthScore);
}
public int getDexterityModifier() {
return getAbilityModifierForScore(dexterityScore);
}
public int getConstitutionModifier() {
return getAbilityModifierForScore(constitutionScore);
}
public int getIntelligenceModifier() {
return getAbilityModifierForScore(intelligenceScore);
}
public int getWisdomModifier() {
return getAbilityModifierForScore(wisdomScore);
}
public int getCharismaModifier() {
return getAbilityModifierForScore(charismaScore);
}
public String getArmorClass() {
boolean hasShield = shieldBonus != 0;
ArmorType armorType = this.armorType != null ? this.armorType : ArmorType.NONE;
switch (armorType) {
case NONE:
// 10 + dexMod + 2 for shieldBonus "15" or "17 (shield)"
return String.format("%d%s", armorType.baseArmorClass + getDexterityModifier() + shieldBonus, hasShield ? " (shield)" : "");
case NATURAL_ARMOR:
// 10 + dexMod + naturalArmorBonus + 2 for shieldBonus "16 (natural armor)" or "18 (natural armor, shield)"
return String.format("%d (natural armor%s)", armorType.baseArmorClass + getDexterityModifier() + naturalArmorBonus + shieldBonus, hasShield ? ", shield" : "");
case MAGE_ARMOR:
// 10 + dexMod + 2 for shield + 3 for mage armor "15 (18 with mage armor)" or 17 (shield, 20 with mage armor)
return String.format("%d (%s%d with mage armor)", armorType.baseArmorClass + getDexterityModifier() + shieldBonus, hasShield ? "shield, " : "", armorType.baseArmorClass + 3 + getDexterityModifier() + shieldBonus);
case PADDED:
// 11 + dexMod + 2 for shield "18 (padded armor, shield)"
return String.format("%d (padded%s)", armorType.baseArmorClass + getDexterityModifier() + shieldBonus, hasShield ? ", shield" : "");
case LEATHER:
// 11 + dexMod + 2 for shield "18 (leather, shield)"
return String.format("%d (leather%s)", armorType.baseArmorClass + getDexterityModifier() + shieldBonus, hasShield ? ", shield" : "");
case STUDDED_LEATHER:
// 12 + dexMod +2 for shield "17 (studded leather)"
return String.format("%d (studded leather%s)", armorType.baseArmorClass + getDexterityModifier() + shieldBonus, hasShield ? ", shield" : "");
case HIDE:
// 12 + Min(2, dexMod) + 2 for shield "12 (hide armor)"
return String.format("%d (hide%s)", armorType.baseArmorClass + Math.min(2, getDexterityModifier()) + shieldBonus, hasShield ? ", shield" : "");
case CHAIN_SHIRT:
// 13 + Min(2, dexMod) + 2 for shield "12 (chain shirt)"
return String.format("%d (chain shirt%s)", armorType.baseArmorClass + Math.min(2, getDexterityModifier()) + shieldBonus, hasShield ? ", shield" : "");
case SCALE_MAIL:
// 14 + Min(2, dexMod) + 2 for shield "14 (scale mail)"
return String.format("%d (scale mail%s)", armorType.baseArmorClass + Math.min(2, getDexterityModifier()) + shieldBonus, hasShield ? ", shield" : "");
case BREASTPLATE:
// 14 + Min(2, dexMod) + 2 for shield "16 (breastplate)"
return String.format("%d (breastplate%s)", armorType.baseArmorClass + Math.min(2, getDexterityModifier()) + shieldBonus, hasShield ? ", shield" : "");
case HALF_PLATE:
// 15 + Min(2, dexMod) + 2 for shield "17 (half plate)"
return String.format("%d (half plate%s)", armorType.baseArmorClass + Math.min(2, getDexterityModifier()) + shieldBonus, hasShield ? ", shield" : "");
case RING_MAIL:
// 14 + 2 for shield "14 (ring mail)
return String.format("%d (ring mail%s)", armorType.baseArmorClass + shieldBonus, hasShield ? ", shield" : "");
case CHAIN_MAIL:
// 16 + 2 for shield "16 (chain mail)"
return String.format("%d (chain mail%s)", armorType.baseArmorClass + shieldBonus, hasShield ? ", shield" : "");
case SPLINT_MAIL:
// 17 + 2 for shield "17 (splint)"
return String.format("%d (splint%s)", armorType.baseArmorClass + shieldBonus, hasShield ? ", shield" : "");
case PLATE_MAIL:
// 18 + 2 for shield "18 (plate)"
return String.format("%d (plate%s)", armorType.baseArmorClass + shieldBonus, hasShield ? ", shield" : "");
case OTHER:
// pure string value shield check does nothing just copies the string from otherArmorDesc
return otherArmorDescription;
default:
return "";
}
}
public String getHitPoints() {
if (hasCustomHP) {
return customHPDescription;
} else {
int dieSize = getHitDieForSize(size);
int conMod = getConstitutionModifier();
// For PC style calculations use this
//int hpTotal = (int) Math.max(1, Math.ceil(dieSize + conMod + (hitDice - 1) * ((dieSize + 1) / 2.0 + conMod)));
// For monster style calculations use this
int hpTotal = (int) Math.max(1, Math.ceil(hitDice * ((dieSize + 1) / 2.0 + conMod)));
return String.format("%d (%dd%d %+d)", hpTotal, hitDice, dieSize, conMod * hitDice);
}
}
private static int getHitDieForSize(String size) {
if ("tiny".equals(size)) {
return 4;
} else if ("small".equals(size)) {
return 6;
} else if ("medium".equals(size)) {
return 8;
} else if ("large".equals(size)) {
return 10;
} else if ("huge".equals(size)) {
return 12;
} else if ("gargantuan".equals(size)) {
return 20;
} else {
return 8;
}
}
public String getSpeedText() {
if (hasCustomSpeed) {
return customSpeedDescription;
} else {
ArrayList<String> speedParts = new ArrayList<>();
if (walkSpeed > 0) {
speedParts.add(String.format("%d ft.", walkSpeed));
}
if (burrowSpeed > 0) {
speedParts.add(String.format("burrow %d ft.", burrowSpeed));
}
if (climbSpeed > 0) {
speedParts.add(String.format("climb %d ft.", climbSpeed));
}
if (flySpeed > 0) {
speedParts.add(String.format("fly %d ft.%s", flySpeed, canHover ? " (hover)" : ""));
}
if (swimSpeed > 0) {
speedParts.add(String.format("swim %d ft.", swimSpeed));
}
return StringHelper.join(", ", speedParts);
}
}
public String getStrengthDescription() {
return String.format("%d (%+d)", strengthScore, getStrengthModifier());
}
public String getDexterityDescription() {
return String.format("%d (%+d)", dexterityScore, getDexterityModifier());
}
public String getConstitutionDescription() {
return String.format("%d (%+d)", constitutionScore, getConstitutionModifier());
}
public String getIntelligenceDescription() {
return String.format("%d (%+d)", intelligenceScore, getIntelligenceModifier());
}
public String getWisdomDescription() {
return String.format("%d (%+d)", wisdomScore, getWisdomModifier());
}
public String getCharismaDescription() {
return String.format("%d (%+d)", charismaScore, getCharismaModifier());
}
public String getSavingThrowsDescription() {
List<String> parts = new ArrayList<>();
for (AbilityScore abilityScore : AbilityScore.values()) {
AdvantageType advantage = getSavingThrowAdvantageType(abilityScore);
ProficiencyType proficiency = getSavingThrowProficiencyType(abilityScore);
if (advantage != AdvantageType.NONE || proficiency != ProficiencyType.NONE) {
int bonus = getAbilityModifier(abilityScore) + getProficiencyBonus(proficiency);
String part = String.format("%s %+d%s", abilityScore.displayName, bonus, advantage != AdvantageType.NONE ? " " + advantage.label : "");
parts.add(part);
}
}
return StringHelper.join(", ", parts);
}
public int getProficiencyBonus() {
ChallengeRating challengeRating = this.challengeRating != null ? this.challengeRating : ChallengeRating.ONE;
if (challengeRating == ChallengeRating.CUSTOM) {
return customProficiencyBonus;
} else {
return challengeRating.proficiencyBonus;
}
}
public int getProficiencyBonus(ProficiencyType proficiencyType) {
switch (proficiencyType) {
case PROFICIENT:
return getProficiencyBonus();
case EXPERTISE:
return getProficiencyBonus() * 2;
case NONE:
default:
return 0;
}
}
public String getSkillsDescription() {
Skill[] elements = new Skill[skills.size()];
elements = skills.toArray(elements);
Arrays.sort(elements);
StringBuilder sb = new StringBuilder();
boolean isFirst = true;
for (Skill skill : elements) {
if (!isFirst) {
sb.append(", ");
}
sb.append(skill.getText(this));
isFirst = false;
}
return sb.toString();
}
public String getDamageVulnerabilitiesDescription() {
ArrayList<String> vulnerabilities = new ArrayList<>();
for (String damageType : damageVulnerabilities) {
if (!StringHelper.isNullOrEmpty(damageType)) {
vulnerabilities.add(damageType);
}
}
Collections.sort(vulnerabilities);
return StringHelper.oxfordJoin(", ", ", and ", " and ", vulnerabilities);
}
public String getDamageResistancesDescription() {
ArrayList<String> resistances = new ArrayList<>();
for (String damageType : damageResistances) {
if (!StringHelper.isNullOrEmpty(damageType)) {
resistances.add(damageType);
}
}
Collections.sort(resistances);
return StringHelper.oxfordJoin(", ", ", and ", " and ", resistances);
}
public String getDamageImmunitiesDescription() {
ArrayList<String> immunities = new ArrayList<>();
for (String damageType : damageImmunities) {
if (!StringHelper.isNullOrEmpty(damageType)) {
immunities.add(damageType);
}
}
Collections.sort(immunities);
return StringHelper.oxfordJoin(", ", ", and ", " and ", immunities);
}
public String getConditionImmunitiesDescription() {
ArrayList<String> immunities = new ArrayList<>(conditionImmunities);
Collections.sort(immunities);
return StringHelper.oxfordJoin(", ", ", and ", " and ", immunities);
}
public String getSensesDescription() {
ArrayList<String> parts = new ArrayList<>(senses);
parts.add(String.format("passive Perception %d", 10 + getWisdomModifier()));
return StringHelper.join(", ", parts);
}
public String getLanguagesDescription() {
ArrayList<String> spokenLanguages = new ArrayList<>();
ArrayList<String> understoodLanguages = new ArrayList<>();
for (Language language : languages) {
if (language != null) {
if (language.getSpeaks()) {
spokenLanguages.add(language.getName());
} else {
understoodLanguages.add(language.getName());
}
}
}
Collections.sort(spokenLanguages);
Collections.sort(understoodLanguages);
String spokenLanguagesString = StringHelper.oxfordJoin(", ", ", and ", " and ", spokenLanguages);
String understoodLanguagesString = StringHelper.oxfordJoin(", ", ", and ", " and ", understoodLanguages);
boolean hasUnderstandsBut = understandsButDescription.length() > 0;
boolean hasTelepathy = telepathyRange > 0;
String telepathyString = String.format(", telepathy %d ft.", telepathyRange);
if (spokenLanguages.size() > 0) {
if (understoodLanguages.size() > 0) {
return String.format(
"%s, understands %s%s%s",
spokenLanguagesString,
understoodLanguagesString,
hasUnderstandsBut ? " but " + understandsButDescription : "",
hasTelepathy ? telepathyString : "");
} else {
return String.format(
"%s%s%s",
spokenLanguagesString,
hasUnderstandsBut ? " but " + understandsButDescription : "",
hasTelepathy ? telepathyString : "");
}
} else {
if (understoodLanguages.size() > 0) {
return String.format(
"understands %s%s%s",
understoodLanguagesString,
hasUnderstandsBut ? " but " + understandsButDescription : "",
hasTelepathy ? telepathyString : "");
} else {
return String.format(
"%S%s",
hasUnderstandsBut ? "none but " + understandsButDescription : "",
hasTelepathy ? telepathyString : "");
}
}
}
public String getChallengeRatingDescription() {
ChallengeRating challengeRating = this.challengeRating != null ? this.challengeRating : ChallengeRating.ONE;
if (challengeRating == ChallengeRating.CUSTOM) {
return customChallengeRatingDescription;
} else {
return challengeRating.displayName;
}
}
public List<String> getAbilityDescriptions() {
ArrayList<String> abilityDescriptions = new ArrayList<>();
for (Trait ability : abilities) {
abilityDescriptions.add(getPlaceholderReplacedText(String.format("__%s__ %s", ability.name, ability.description)));
}
return abilityDescriptions;
}
public String getPlaceholderReplacedText(String rawText) {
return rawText
.replaceAll("\\[STR SAVE]", String.format("%+d", getSpellSaveDC(AbilityScore.STRENGTH)))
.replaceAll("\\[STR ATK]", String.format("%+d", getAttackBonus(AbilityScore.STRENGTH)))
.replaceAll("\\[DEX SAVE]", String.format("%+d", getSpellSaveDC(AbilityScore.DEXTERITY)))
.replaceAll("\\[DEX ATK]", String.format("%+d", getAttackBonus(AbilityScore.DEXTERITY)))
.replaceAll("\\[CON SAVE]", String.format("%+d", getSpellSaveDC(AbilityScore.CONSTITUTION)))
.replaceAll("\\[CON ATK]", String.format("%+d", getAttackBonus(AbilityScore.CONSTITUTION)))
.replaceAll("\\[INT SAVE]", String.format("%+d", getSpellSaveDC(AbilityScore.INTELLIGENCE)))
.replaceAll("\\[INT ATK]", String.format("%+d", getAttackBonus(AbilityScore.INTELLIGENCE)))
.replaceAll("\\[WIS SAVE]", String.format("%+d", getSpellSaveDC(AbilityScore.WISDOM)))
.replaceAll("\\[WIS ATK]", String.format("%+d", getAttackBonus(AbilityScore.WISDOM)))
.replaceAll("\\[CHA SAVE]", String.format("%+d", getSpellSaveDC(AbilityScore.CHARISMA)))
.replaceAll("\\[CHA ATK]", String.format("%+d", getAttackBonus(AbilityScore.CHARISMA)));
}
public int getSpellSaveDC(AbilityScore abilityScore) {
return 8 + getProficiencyBonus() + getAbilityModifier(abilityScore);
}
public int getAttackBonus(AbilityScore abilityScore) {
return getProficiencyBonus() + getAbilityModifier(abilityScore);
}
public List<String> getActionDescriptions() {
ArrayList<String> actionDescriptions = new ArrayList<>();
for (Trait action : actions) {
actionDescriptions.add(getPlaceholderReplacedText(String.format("__%s__ %s", action.name, action.description)));
}
return actionDescriptions;
}
public List<String> getReactionDescriptions() {
ArrayList<String> actionDescriptions = new ArrayList<>();
for (Trait action : reactions) {
actionDescriptions.add(getPlaceholderReplacedText(String.format("__%s__ %s", action.name, action.description)));
}
return actionDescriptions;
}
public List<String> getLegendaryActionDescriptions() {
ArrayList<String> actionDescriptions = new ArrayList<>();
for (Trait action : legendaryActions) {
actionDescriptions.add(getPlaceholderReplacedText(String.format("__%s__ %s", action.name, action.description)));
}
return actionDescriptions;
}
public List<String> getLairActionDescriptions() {
ArrayList<String> actionDescriptions = new ArrayList<>();
for (Trait action : lairActions) {
actionDescriptions.add(getPlaceholderReplacedText(String.format("__%s__ %s", action.name, action.description)));
}
return actionDescriptions;
}
public List<String> getRegionalActionDescriptions() {
ArrayList<String> actionDescriptions = new ArrayList<>();
for (Trait action : regionalActions) {
actionDescriptions.add(getPlaceholderReplacedText(String.format("__%s__ %s", action.name, action.description)));
}
return actionDescriptions;
}
}