From c6e8be3bd1fb6f328917afb7288f68ee578d967d Mon Sep 17 00:00:00 2001 From: Tom Hicks Date: Sat, 17 Apr 2021 20:43:19 -0700 Subject: [PATCH] Migrates Monster class to be storable in roomdb. --- .gitignore | 1 + .idea/saveactions_settings.xml | 16 + app/build.gradle | 1 + .../1.json | 405 ++++- .../schema-notes.md | 73 + .../majinnaibu/monstercards/AppDatabase.java | 23 +- .../data/converters/ArmorTypeConverter.java | 18 + .../converters/ChallengeRatingConverter.java | 18 + .../converters/SetOfLanguageConverter.java | 28 + .../converters/SetOfSavingThrowConverter.java | 31 + .../data/converters/SetOfSkillConverter.java | 28 + .../data/converters/SetOfStringConverter.java | 27 + .../data/converters/SetOfTraitConverter.java | 27 + .../{ => data}/converters/UUIDConverter.java | 2 +- .../monstercards/data/enums/AbilityScore.java | 31 + .../data/enums/AdvantageType.java | 27 + .../monstercards/data/enums/ArmorType.java | 41 + .../data/enums/ChallengeRating.java | 60 + .../data/enums/ProficiencyType.java | 27 + .../monstercards/models/Ability.java | 29 - .../monstercards/models/Action.java | 29 - .../monstercards/models/DamageType.java | 41 - .../monstercards/models/Monster.java | 1391 ++++++----------- .../majinnaibu/monstercards/models/Skill.java | 79 +- .../majinnaibu/monstercards/models/Trait.java | 12 + .../ui/monster/MonsterFragment.java | 439 +++--- 26 files changed, 1613 insertions(+), 1291 deletions(-) create mode 100644 .idea/saveactions_settings.xml create mode 100644 app/schemas/com.majinnaibu.monstercards.AppDatabase/schema-notes.md create mode 100644 app/src/main/java/com/majinnaibu/monstercards/data/converters/ArmorTypeConverter.java create mode 100644 app/src/main/java/com/majinnaibu/monstercards/data/converters/ChallengeRatingConverter.java create mode 100644 app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfLanguageConverter.java create mode 100644 app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfSavingThrowConverter.java create mode 100644 app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfSkillConverter.java create mode 100644 app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfStringConverter.java create mode 100644 app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfTraitConverter.java rename app/src/main/java/com/majinnaibu/monstercards/{ => data}/converters/UUIDConverter.java (85%) create mode 100644 app/src/main/java/com/majinnaibu/monstercards/data/enums/AbilityScore.java create mode 100644 app/src/main/java/com/majinnaibu/monstercards/data/enums/AdvantageType.java create mode 100644 app/src/main/java/com/majinnaibu/monstercards/data/enums/ArmorType.java create mode 100644 app/src/main/java/com/majinnaibu/monstercards/data/enums/ChallengeRating.java create mode 100644 app/src/main/java/com/majinnaibu/monstercards/data/enums/ProficiencyType.java delete mode 100644 app/src/main/java/com/majinnaibu/monstercards/models/Ability.java delete mode 100644 app/src/main/java/com/majinnaibu/monstercards/models/Action.java delete mode 100644 app/src/main/java/com/majinnaibu/monstercards/models/DamageType.java create mode 100644 app/src/main/java/com/majinnaibu/monstercards/models/Trait.java diff --git a/.gitignore b/.gitignore index 87de309..a840822 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ /.idea/workspace.xml /.idea/navEditor.xml /.idea/assetWizardSettings.xml +/.idea/dictionaries .DS_Store /build /captures diff --git a/.idea/saveactions_settings.xml b/.idea/saveactions_settings.xml new file mode 100644 index 0000000..57dd97c --- /dev/null +++ b/.idea/saveactions_settings.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 5ee600d..8d8816b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -87,4 +87,5 @@ dependencies { // optional - Test helpers //testImplementation "androidx.room:room-testing:$room_version" + implementation 'com.google.code.gson:gson:2.8.6' } \ No newline at end of file diff --git a/app/schemas/com.majinnaibu.monstercards.AppDatabase/1.json b/app/schemas/com.majinnaibu.monstercards.AppDatabase/1.json index f92e587..83ab2bc 100644 --- a/app/schemas/com.majinnaibu.monstercards.AppDatabase/1.json +++ b/app/schemas/com.majinnaibu.monstercards.AppDatabase/1.json @@ -2,11 +2,11 @@ "formatVersion": 1, "database": { "version": 1, - "identityHash": "a9371223372fb64522cc40f5529ada09", + "identityHash": "db1293d2f490940b55ca1f4f56b21b1a", "entities": [ { "tableName": "Monster", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL DEFAULT '', PRIMARY KEY(`id`))", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL DEFAULT '', `size` TEXT NOT NULL DEFAULT '', `type` TEXT NOT NULL DEFAULT '', `subtype` TEXT NOT NULL DEFAULT '', `alignment` TEXT NOT NULL DEFAULT '', `strength_score` INTEGER NOT NULL DEFAULT 10, `strength_saving_throw_advantage` TEXT DEFAULT 'none', `strength_saving_throw_proficiency` TEXT DEFAULT 'none', `dexterity_score` INTEGER NOT NULL DEFAULT 10, `dexterity_saving_throw_advantage` TEXT DEFAULT 'none', `dexterity_saving_throw_proficiency` TEXT DEFAULT 'none', `constitution_score` INTEGER NOT NULL DEFAULT 10, `constitution_saving_throw_advantage` TEXT DEFAULT 'none', `constitution_saving_throw_proficiency` TEXT DEFAULT 'none', `intelligence_score` INTEGER NOT NULL DEFAULT 10, `intelligence_saving_throw_advantage` TEXT DEFAULT 'none', `intelligence_saving_throw_proficiency` TEXT DEFAULT 'none', `wisdom_score` INTEGER NOT NULL DEFAULT 10, `wisdom_saving_throw_advantage` TEXT DEFAULT 'none', `wisdom_saving_throw_proficiency` TEXT DEFAULT 'none', `charisma_score` INTEGER NOT NULL DEFAULT 10, `charisma_saving_throw_advantage` TEXT DEFAULT 'none', `charisma_saving_throw_proficiency` TEXT DEFAULT 'none', `armor_type` TEXT DEFAULT 'none', `shield_bonus` INTEGER NOT NULL DEFAULT 0, `natural_armor_bonus` INTEGER NOT NULL DEFAULT 0, `other_armor_description` TEXT DEFAULT '', `hit_dice` INTEGER NOT NULL DEFAULT 1, `has_custom_hit_points` INTEGER NOT NULL, `custom_hit_points_description` TEXT DEFAULT '', `walk_speed` INTEGER NOT NULL DEFAULT 0, `burrow_speed` INTEGER NOT NULL DEFAULT 0, `climb_speed` INTEGER NOT NULL DEFAULT 0, `fly_speed` INTEGER NOT NULL DEFAULT 0, `can_hover` INTEGER NOT NULL DEFAULT false, `swim_speed` INTEGER NOT NULL DEFAULT 0, `has_custom_speed` INTEGER NOT NULL DEFAULT false, `custom_speed_description` TEXT, `challenge_rating` TEXT DEFAULT '1', `custom_challenge_rating_description` TEXT DEFAULT '', `custom_proficiency_bonus` INTEGER NOT NULL DEFAULT 0, `blindsight_range` INTEGER NOT NULL DEFAULT 0, `is_blind_beyond_blindsight_range` INTEGER NOT NULL DEFAULT false, `darkvision_range` INTEGER NOT NULL DEFAULT 0, `tremorsense_range` INTEGER NOT NULL DEFAULT 0, `truesight_range` INTEGER NOT NULL DEFAULT 0, `telepathy_range` INTEGER NOT NULL DEFAULT 0, `understands_but_description` TEXT DEFAULT '', `skills` TEXT, `damage_immunities` TEXT, `damage_resistances` TEXT, `damage_vulnerabilities` TEXT, `condition_immunities` TEXT, `languages` TEXT, `abilities` TEXT, `actions` TEXT, `reactions` TEXT, `lair_actions` TEXT, `legendary_actions` TEXT, `regional_actions` TEXT, PRIMARY KEY(`id`))", "fields": [ { "fieldPath": "id", @@ -20,6 +20,405 @@ "affinity": "TEXT", "notNull": true, "defaultValue": "''" + }, + { + "fieldPath": "size", + "columnName": "size", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "subtype", + "columnName": "subtype", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "alignment", + "columnName": "alignment", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "strengthScore", + "columnName": "strength_score", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "10" + }, + { + "fieldPath": "strengthSavingThrowAdvantage", + "columnName": "strength_saving_throw_advantage", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'none'" + }, + { + "fieldPath": "strengthSavingThrowProficiency", + "columnName": "strength_saving_throw_proficiency", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'none'" + }, + { + "fieldPath": "dexterityScore", + "columnName": "dexterity_score", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "10" + }, + { + "fieldPath": "dexteritySavingThrowAdvantage", + "columnName": "dexterity_saving_throw_advantage", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'none'" + }, + { + "fieldPath": "dexteritySavingThrowProficiency", + "columnName": "dexterity_saving_throw_proficiency", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'none'" + }, + { + "fieldPath": "constitutionScore", + "columnName": "constitution_score", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "10" + }, + { + "fieldPath": "constitutionSavingThrowAdvantage", + "columnName": "constitution_saving_throw_advantage", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'none'" + }, + { + "fieldPath": "constitutionSavingThrowProficiency", + "columnName": "constitution_saving_throw_proficiency", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'none'" + }, + { + "fieldPath": "intelligenceScore", + "columnName": "intelligence_score", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "10" + }, + { + "fieldPath": "intelligenceSavingThrowAdvantage", + "columnName": "intelligence_saving_throw_advantage", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'none'" + }, + { + "fieldPath": "intelligenceSavingThrowProficiency", + "columnName": "intelligence_saving_throw_proficiency", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'none'" + }, + { + "fieldPath": "wisdomScore", + "columnName": "wisdom_score", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "10" + }, + { + "fieldPath": "wisdomSavingThrowAdvantage", + "columnName": "wisdom_saving_throw_advantage", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'none'" + }, + { + "fieldPath": "wisdomSavingThrowProficiency", + "columnName": "wisdom_saving_throw_proficiency", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'none'" + }, + { + "fieldPath": "charismaScore", + "columnName": "charisma_score", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "10" + }, + { + "fieldPath": "charismaSavingThrowAdvantage", + "columnName": "charisma_saving_throw_advantage", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'none'" + }, + { + "fieldPath": "charismaSavingThrowProficiency", + "columnName": "charisma_saving_throw_proficiency", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'none'" + }, + { + "fieldPath": "armorType", + "columnName": "armor_type", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'none'" + }, + { + "fieldPath": "shieldBonus", + "columnName": "shield_bonus", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "naturalArmorBonus", + "columnName": "natural_armor_bonus", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "otherArmorDescription", + "columnName": "other_armor_description", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "hitDice", + "columnName": "hit_dice", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + }, + { + "fieldPath": "hasCustomHP", + "columnName": "has_custom_hit_points", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "customHPDescription", + "columnName": "custom_hit_points_description", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "walkSpeed", + "columnName": "walk_speed", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "burrowSpeed", + "columnName": "burrow_speed", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "climbSpeed", + "columnName": "climb_speed", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "flySpeed", + "columnName": "fly_speed", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "canHover", + "columnName": "can_hover", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "false" + }, + { + "fieldPath": "swimSpeed", + "columnName": "swim_speed", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "hasCustomSpeed", + "columnName": "has_custom_speed", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "false" + }, + { + "fieldPath": "customSpeedDescription", + "columnName": "custom_speed_description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "challengeRating", + "columnName": "challenge_rating", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'1'" + }, + { + "fieldPath": "customChallengeRatingDescription", + "columnName": "custom_challenge_rating_description", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "customProficiencyBonus", + "columnName": "custom_proficiency_bonus", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "blindsightRange", + "columnName": "blindsight_range", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "isBlindBeyondBlindsightRange", + "columnName": "is_blind_beyond_blindsight_range", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "false" + }, + { + "fieldPath": "darkvisionRange", + "columnName": "darkvision_range", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "tremorsenseRange", + "columnName": "tremorsense_range", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "truesightRange", + "columnName": "truesight_range", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "telepathyRange", + "columnName": "telepathy_range", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "understandsButDescription", + "columnName": "understands_but_description", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "skills", + "columnName": "skills", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "damageImmunities", + "columnName": "damage_immunities", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "damageResistances", + "columnName": "damage_resistances", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "damageVulnerabilities", + "columnName": "damage_vulnerabilities", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "conditionImmunities", + "columnName": "condition_immunities", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "languages", + "columnName": "languages", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "abilities", + "columnName": "abilities", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "actions", + "columnName": "actions", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "reactions", + "columnName": "reactions", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lairActions", + "columnName": "lair_actions", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "legendaryActions", + "columnName": "legendary_actions", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "regionalActions", + "columnName": "regional_actions", + "affinity": "TEXT", + "notNull": false } ], "primaryKey": { @@ -35,7 +434,7 @@ "views": [], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a9371223372fb64522cc40f5529ada09')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'db1293d2f490940b55ca1f4f56b21b1a')" ] } } \ No newline at end of file diff --git a/app/schemas/com.majinnaibu.monstercards.AppDatabase/schema-notes.md b/app/schemas/com.majinnaibu.monstercards.AppDatabase/schema-notes.md new file mode 100644 index 0000000..24e4113 --- /dev/null +++ b/app/schemas/com.majinnaibu.monstercards.AppDatabase/schema-notes.md @@ -0,0 +1,73 @@ +## Monster +id: UUID as TEXT // doesn't exist in the iOS model +abilities: Set converted to JSON as TEXT +actions: Set converted to JSON as TEXT +alignment: String as TEXT +armor_type: Enum as TEXT +blindsight_range: int as INTEGER +burrow_speed: int as INTEGER +can_hover: boolean as INTEGER +challenge_rating: Enum as TEXT +charisma_saving_throw_advantage +charisma_saving_throw_proficiency +charisma_score: int as INTEGER +climb_speed: int as INTEGER +condition_immunities: Set converted to JSON as TEXT +constitution_saving_throw_advantage +constitution_saving_throw_proficiency +constitution_score: int as INTEGER +//other_armor_description: String as TEXT +custom_challenge_rating_description: String as TEXT +custom_hit_points_description: String +custom_proficiency_bonus: int as INTEGER +custom_speed_description: String as TEXT +damage_immunities: Set converted to JSON as TEXT +damage_resistances: Set converted to JSON as TEXT +damage_vulnerabilities: Set converted to JSON as TEXT +darkvision_range: int as INTEGER +dexterity_saving_throw_advantage +dexterity_saving_throw_proficiency +dexterity_score: int as INTEGER +fly_speed: int as INTEGER +has_custom_hit_points: boolean as INTEGER +has_custom_speed: boolean as INTEGER +// has_shield +hit_dice: int as INTEGER +intelligence_saving_throw_advantage +intelligence_saving_throw_proficiency +intelligence_score: int as INTEGER +is_blind_beyond_blindsight_range: boolean as INTEGER +lair_actions +languages: Set converted to JSON as TEXT +legendary_actions +name: String as TEXT +natural_armor_bonus: int as INTEGER +other_armor_description: String as TEXT +reactions +regional_actions +// senses +shield_bonus: int as INTEGER +size: String as TEXT +strength_saving_throw_advantage +strength_saving_throw_proficiency +strength_score: int as INTEGER +tag: String as TEXT // subtype || tag +swim_speed: int as INTEGER +telepathy_range: int as INTEGER +tremorsense_range: int as INTEGER +truesight_range: int as INTEGER +type: String as TEXT +understands_but_description: String as TEXT +walk_speed: int as INTEGER +wisdom_saving_throw_advantage +wisdom_saving_throw_proficiency +wisdom_score: int as INTEGER + +// tracked as relationship (don't do this) +skills: Set converted to JSON as TEXT + +## Skill +// ability_score_name String defaults to "strength" +// advantage String defaults to "none" +// name String defaults to "" +// proficiency String defaults to "none" diff --git a/app/src/main/java/com/majinnaibu/monstercards/AppDatabase.java b/app/src/main/java/com/majinnaibu/monstercards/AppDatabase.java index fc44923..3d21f3f 100644 --- a/app/src/main/java/com/majinnaibu/monstercards/AppDatabase.java +++ b/app/src/main/java/com/majinnaibu/monstercards/AppDatabase.java @@ -4,12 +4,29 @@ import androidx.room.Database; import androidx.room.RoomDatabase; import androidx.room.TypeConverters; -import com.majinnaibu.monstercards.converters.UUIDConverter; import com.majinnaibu.monstercards.data.MonsterDAO; +import com.majinnaibu.monstercards.data.converters.ArmorTypeConverter; +import com.majinnaibu.monstercards.data.converters.ChallengeRatingConverter; +import com.majinnaibu.monstercards.data.converters.SetOfLanguageConverter; +import com.majinnaibu.monstercards.data.converters.SetOfSavingThrowConverter; +import com.majinnaibu.monstercards.data.converters.SetOfSkillConverter; +import com.majinnaibu.monstercards.data.converters.SetOfStringConverter; +import com.majinnaibu.monstercards.data.converters.SetOfTraitConverter; +import com.majinnaibu.monstercards.data.converters.UUIDConverter; import com.majinnaibu.monstercards.models.Monster; -@Database(entities = {Monster.class}, version=1) -@TypeConverters({UUIDConverter.class}) +@SuppressWarnings("unused") +@Database(entities = {Monster.class}, version = 1) +@TypeConverters({ + ArmorTypeConverter.class, + ChallengeRatingConverter.class, + SetOfLanguageConverter.class, + SetOfSavingThrowConverter.class, + SetOfSkillConverter.class, + SetOfStringConverter.class, + SetOfTraitConverter.class, + UUIDConverter.class, +}) public abstract class AppDatabase extends RoomDatabase { public abstract MonsterDAO monsterDAO(); } diff --git a/app/src/main/java/com/majinnaibu/monstercards/data/converters/ArmorTypeConverter.java b/app/src/main/java/com/majinnaibu/monstercards/data/converters/ArmorTypeConverter.java new file mode 100644 index 0000000..d3b63a3 --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/data/converters/ArmorTypeConverter.java @@ -0,0 +1,18 @@ +package com.majinnaibu.monstercards.data.converters; + +import androidx.room.TypeConverter; + +import com.majinnaibu.monstercards.data.enums.ArmorType; + +public class ArmorTypeConverter { + + @TypeConverter + public static String fromArmorType(ArmorType armorType) { + return armorType.stringValue; + } + + @TypeConverter + public static ArmorType armorTypeFromStringValue(String stringValue) { + return ArmorType.valueOfString(stringValue); + } +} diff --git a/app/src/main/java/com/majinnaibu/monstercards/data/converters/ChallengeRatingConverter.java b/app/src/main/java/com/majinnaibu/monstercards/data/converters/ChallengeRatingConverter.java new file mode 100644 index 0000000..47b375b --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/data/converters/ChallengeRatingConverter.java @@ -0,0 +1,18 @@ +package com.majinnaibu.monstercards.data.converters; + +import androidx.room.TypeConverter; + +import com.majinnaibu.monstercards.data.enums.ChallengeRating; + +public class ChallengeRatingConverter { + + @TypeConverter + public static String fromChallengeRating(ChallengeRating challengeRating) { + return challengeRating.stringValue; + } + + @TypeConverter + public static ChallengeRating challengeRatingFromStringValue(String stringValue) { + return ChallengeRating.valueOfString(stringValue); + } +} diff --git a/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfLanguageConverter.java b/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfLanguageConverter.java new file mode 100644 index 0000000..b076a4d --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfLanguageConverter.java @@ -0,0 +1,28 @@ +package com.majinnaibu.monstercards.data.converters; + +import androidx.room.TypeConverter; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.majinnaibu.monstercards.models.Language; + +import java.lang.reflect.Type; +import java.util.HashSet; +import java.util.Set; + +public class SetOfLanguageConverter { + + @TypeConverter + public static String fromSetOfLanguage(Set languages) { + Gson gson = new Gson(); + return gson.toJson(languages); + } + + @TypeConverter + public static Set setOfLanguageFromString(String string) { + Gson gson = new Gson(); + Type setType = new TypeToken>() { + }.getType(); + return gson.fromJson(string, setType); + } +} diff --git a/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfSavingThrowConverter.java b/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfSavingThrowConverter.java new file mode 100644 index 0000000..a2ee9b6 --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfSavingThrowConverter.java @@ -0,0 +1,31 @@ +package com.majinnaibu.monstercards.data.converters; + + +import androidx.room.TypeConverter; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.majinnaibu.monstercards.models.SavingThrow; + +import java.lang.reflect.Type; +import java.util.HashSet; +import java.util.Set; + +public class SetOfSavingThrowConverter { + + @TypeConverter + public static String fromSetOfSavingThrow(Set savingThrows) { + Gson gson = new Gson(); + SavingThrow[] saves = new SavingThrow[savingThrows.size()]; + savingThrows.toArray(saves); + return gson.toJson(saves); + } + + @TypeConverter + public static Set setOfSavingThrowFromString(String string) { + Gson gson = new Gson(); + Type setType = new TypeToken>() { + }.getType(); + return gson.fromJson(string, setType); + } +} diff --git a/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfSkillConverter.java b/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfSkillConverter.java new file mode 100644 index 0000000..6f2ee90 --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfSkillConverter.java @@ -0,0 +1,28 @@ +package com.majinnaibu.monstercards.data.converters; + +import androidx.room.TypeConverter; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.majinnaibu.monstercards.models.Skill; + +import java.lang.reflect.Type; +import java.util.HashSet; +import java.util.Set; + +public class SetOfSkillConverter { + + @TypeConverter + public static String fromSetOfSkill(Set skills) { + Gson gson = new Gson(); + return gson.toJson(skills); + } + + @TypeConverter + public static Set setOfSkillFromString(String string) { + Gson gson = new Gson(); + Type setType = new TypeToken>() { + }.getType(); + return gson.fromJson(string, setType); + } +} diff --git a/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfStringConverter.java b/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfStringConverter.java new file mode 100644 index 0000000..c09dcaa --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfStringConverter.java @@ -0,0 +1,27 @@ +package com.majinnaibu.monstercards.data.converters; + +import androidx.room.TypeConverter; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.HashSet; +import java.util.Set; + +public class SetOfStringConverter { + + @TypeConverter + public static String fromSetOfString(Set strings) { + Gson gson = new Gson(); + return gson.toJson(strings); + } + + @TypeConverter + public static Set setOfStringFromString(String string) { + Gson gson = new Gson(); + Type setType = new TypeToken>() { + }.getType(); + return gson.fromJson(string, setType); + } +} diff --git a/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfTraitConverter.java b/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfTraitConverter.java new file mode 100644 index 0000000..029b102 --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/data/converters/SetOfTraitConverter.java @@ -0,0 +1,27 @@ +package com.majinnaibu.monstercards.data.converters; + +import androidx.room.TypeConverter; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.majinnaibu.monstercards.models.Trait; + +import java.lang.reflect.Type; +import java.util.HashSet; +import java.util.Set; + +public class SetOfTraitConverter { + @TypeConverter + public static String fromSetOfTrait(Set traits) { + Gson gson = new Gson(); + return gson.toJson(traits); + } + + @TypeConverter + public static Set setOfTraitFromString(String string) { + Gson gson = new Gson(); + Type setType = new TypeToken>() { + }.getType(); + return gson.fromJson(string, setType); + } +} diff --git a/app/src/main/java/com/majinnaibu/monstercards/converters/UUIDConverter.java b/app/src/main/java/com/majinnaibu/monstercards/data/converters/UUIDConverter.java similarity index 85% rename from app/src/main/java/com/majinnaibu/monstercards/converters/UUIDConverter.java rename to app/src/main/java/com/majinnaibu/monstercards/data/converters/UUIDConverter.java index b1effc8..07d5375 100644 --- a/app/src/main/java/com/majinnaibu/monstercards/converters/UUIDConverter.java +++ b/app/src/main/java/com/majinnaibu/monstercards/data/converters/UUIDConverter.java @@ -1,4 +1,4 @@ -package com.majinnaibu.monstercards.converters; +package com.majinnaibu.monstercards.data.converters; import androidx.room.TypeConverter; diff --git a/app/src/main/java/com/majinnaibu/monstercards/data/enums/AbilityScore.java b/app/src/main/java/com/majinnaibu/monstercards/data/enums/AbilityScore.java new file mode 100644 index 0000000..a155d8a --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/data/enums/AbilityScore.java @@ -0,0 +1,31 @@ +package com.majinnaibu.monstercards.data.enums; + +@SuppressWarnings("unused") +public enum AbilityScore { + STRENGTH("strength", "Strength", "STR"), + DEXTERITY("dexterity", "Dexterity", "DEX"), + CONSTITUTION("constitution", "Constitution", "CON"), + INTELLIGENCE("intellligence", "Intelligence", "INT"), + WISDOM("wisdom", "Wisdom", "WIS"), + CHARISMA("charisma", "Charisma", "CHA"), + ; + + public final String displayName; + public final String shortDisplayName; + public final String stringValue; + + AbilityScore(String stringValue, String displayName, String shortDisplayName) { + this.displayName = displayName; + this.stringValue = stringValue; + this.shortDisplayName = shortDisplayName; + } + + public static AbilityScore valueOfString(String string) { + for (AbilityScore abilityScore : values()) { + if (abilityScore.stringValue.equals(string)) { + return abilityScore; + } + } + return AbilityScore.STRENGTH; + } +} diff --git a/app/src/main/java/com/majinnaibu/monstercards/data/enums/AdvantageType.java b/app/src/main/java/com/majinnaibu/monstercards/data/enums/AdvantageType.java new file mode 100644 index 0000000..1405696 --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/data/enums/AdvantageType.java @@ -0,0 +1,27 @@ +package com.majinnaibu.monstercards.data.enums; + +public enum AdvantageType { + NONE("none", "None", ""), + ADVANTAGE("advantage", "Advantage", "A"), + DISADVANTAGE("disadvantage", "Disadvantage", "D"), + ; + + public final String displayName; + public final String stringValue; + public final String label; + + AdvantageType(String stringValue, String displayName, String label) { + this.displayName = displayName; + this.stringValue = stringValue; + this.label = label; + } + + public static AdvantageType valueOfString(String string) { + for (AdvantageType advantageType : values()) { + if (advantageType.stringValue.equals(string)) { + return advantageType; + } + } + return AdvantageType.NONE; + } +} diff --git a/app/src/main/java/com/majinnaibu/monstercards/data/enums/ArmorType.java b/app/src/main/java/com/majinnaibu/monstercards/data/enums/ArmorType.java new file mode 100644 index 0000000..67cf8ae --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/data/enums/ArmorType.java @@ -0,0 +1,41 @@ +package com.majinnaibu.monstercards.data.enums; + +@SuppressWarnings("unused") +public enum ArmorType { + NONE("none", "None", 10), + NATURAL_ARMOR("natural armor", "Natural Armor", 10), + MAGE_ARMOR("mage armor", "Mage Armor", 10), + PADDED("padded", "Padded", 11), + LEATHER("leather", "Leather", 11), + STUDDED_LEATHER("studded", "Studded Leather", 12), + HIDE("hide", "Hide", 12), + CHAIN_SHIRT("chain shirt", "Chain Shirt", 13), + SCALE_MAIL("scale mail", "Scale Mail", 14), + BREASTPLATE("breastplate", "Breastplate", 14), + HALF_PLATE("half plate", "Half Plate", 15), + RING_MAIL("ring mail", "Ring Mail", 14), + CHAIN_MAIL("chain mail", "Chain Mail", 16), + SPLINT_MAIL("splint", "Splint Mail", 17), + PLATE_MAIL("plate", "Plate Mail", 18), + OTHER("other", "Other", 10), + ; + + public final String displayName; + public final String stringValue; + public final int baseArmorClass; + + ArmorType(String stringValue, String displayName, int baseArmorClass) { + this.displayName = displayName; + this.stringValue = stringValue; + this.baseArmorClass = baseArmorClass; + } + + public static ArmorType valueOfString(String string) { + for (ArmorType armorType : values()) { + if (armorType.stringValue.equals(string)) { + return armorType; + } + } + return ArmorType.NONE; + } +} diff --git a/app/src/main/java/com/majinnaibu/monstercards/data/enums/ChallengeRating.java b/app/src/main/java/com/majinnaibu/monstercards/data/enums/ChallengeRating.java new file mode 100644 index 0000000..be8d87c --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/data/enums/ChallengeRating.java @@ -0,0 +1,60 @@ +package com.majinnaibu.monstercards.data.enums; + +@SuppressWarnings("unused") +public enum ChallengeRating { + CUSTOM("custom", "Custom", 0), + ZERO("zero", "0 (10 XP)", 2), + ONE_EIGHTH("1/8", "1/8 (25 XP)", 2), + ONE_QUARTER("1/4", "1/4 (50 XP)", 2), + ONE_HALF("1/2", "1/2 (100 XP)", 2), + ONE("1", "1 (200 XP)", 2), + TWO("2", "2 (450 XP)", 2), + THREE("3", "3 (700 XP)", 2), + FOUR("4", "4 (1,100 XP)", 2), + FIVE("5", "5 (1,800 XP)", 3), + SIX("6", "6 (2,300 XP)", 3), + SEVEN("7", "7 (2,900 XP)", 3), + EIGHT("8", "8 (3,900 XP)", 3), + NINE("9", "9 (5,000 XP)", 4), + TEN("10", "10 (5,900 XP)", 4), + ELEVEN("11", "11 (7,200 XP)", 4), + TWELVE("12", "12 (8,400 XP)", 4), + THIRTEEN("13", "13 (10,000 XP)", 5), + FOURTEEN("14", "14 (11,500 XP)", 5), + FIFTEEN("15", "15 (13,000 XP)", 5), + SIXTEEN("16", "16 (15,000 XP)", 5), + SEVENTEEN("17", "17 (18,000 XP)", 6), + EIGHTEEN("18", "18 (20,000 XP)", 6), + NINETEEN("19", "19 (22,000 XP)", 6), + TWENTY("20", "20 (25,000 XP)", 6), + TWENTY_ONE("21", "21 (33,000 XP)", 7), + TWENTY_TWO("22", "22 (41,000 XP)", 7), + TWENTY_THREE("23", "23 (50,000 XP)", 7), + TWENTY_FOUR("24", "24 (62,000 XP)", 7), + TWENTY_FIVE("25", "25 (75,000 XP)", 8), + TWENTY_SIX("26", "26 (90,000 XP)", 8), + TWENTY_SEVEN("27", "27 (105,000 XP)", 8), + TWENTY_EIGHT("28", "28 (120,000 XP)", 8), + TWENTY_NINE("29", "29 (135,000 XP)", 9), + THIRTY("30", "30 (155,000 XP)", 9), + ; + + public final String displayName; + public final String stringValue; + public final int proficiencyBonus; + + ChallengeRating(String stringValue, String displayName, int proficiencyBonus) { + this.displayName = displayName; + this.stringValue = stringValue; + this.proficiencyBonus = proficiencyBonus; + } + + public static ChallengeRating valueOfString(String string) { + for (ChallengeRating challengeRating : values()) { + if (challengeRating.stringValue.equals(string)) { + return challengeRating; + } + } + return ChallengeRating.ONE; + } +} diff --git a/app/src/main/java/com/majinnaibu/monstercards/data/enums/ProficiencyType.java b/app/src/main/java/com/majinnaibu/monstercards/data/enums/ProficiencyType.java new file mode 100644 index 0000000..76754bc --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/data/enums/ProficiencyType.java @@ -0,0 +1,27 @@ +package com.majinnaibu.monstercards.data.enums; + +public enum ProficiencyType { + NONE("none", "None", ""), + PROFICIENT("proficient", "Proficient", "P"), + EXPERTISE("experties", "Expertise", "Ex"), + ; + + public final String displayName; + public final String stringValue; + public final String label; + + ProficiencyType(String stringValue, String displayName, String label) { + this.displayName = displayName; + this.stringValue = stringValue; + this.label = label; + } + + public static ProficiencyType valueOfString(String string) { + for (ProficiencyType proficiencyType : values()) { + if (proficiencyType.stringValue.equals(string)) { + return proficiencyType; + } + } + return ProficiencyType.NONE; + } +} diff --git a/app/src/main/java/com/majinnaibu/monstercards/models/Ability.java b/app/src/main/java/com/majinnaibu/monstercards/models/Ability.java deleted file mode 100644 index 9921b92..0000000 --- a/app/src/main/java/com/majinnaibu/monstercards/models/Ability.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.majinnaibu.monstercards.models; - -public class Ability { - - public Ability(String name, String description) { - mName = name; - mDescription = description; - } - - private String mName; - - public String getName() { - return mName; - } - - public void setName(String name) { - mName = name; - } - - private String mDescription; - - public String getDescription() { - return mDescription; - } - - public void setDescription(String description) { - mDescription = description; - } -} diff --git a/app/src/main/java/com/majinnaibu/monstercards/models/Action.java b/app/src/main/java/com/majinnaibu/monstercards/models/Action.java deleted file mode 100644 index abb5036..0000000 --- a/app/src/main/java/com/majinnaibu/monstercards/models/Action.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.majinnaibu.monstercards.models; - -public class Action { - - public Action(String name, String description) { - mName = name; - mDescription = description; - } - - private String mName; - - public String getName() { - return mName; - } - - public void setName(String name) { - mName = name; - } - - private String mDescription; - - public String getDescription() { - return mDescription; - } - - public void setDescription(String description) { - mDescription = description; - } -} diff --git a/app/src/main/java/com/majinnaibu/monstercards/models/DamageType.java b/app/src/main/java/com/majinnaibu/monstercards/models/DamageType.java deleted file mode 100644 index 73333b2..0000000 --- a/app/src/main/java/com/majinnaibu/monstercards/models/DamageType.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.majinnaibu.monstercards.models; - -public class DamageType { - - public DamageType(String name, String note, String type) { - mName = name; - mNote = note; - mType = type; - } - - private String mName; - - public String getName() { - return mName; - } - - public void setName(String value) { - mName = value; - } - - private String mNote; - - public String getNote() { - return mNote; - } - - public void setNote(String value) { - mNote = value; - } - - private String mType; - - public String getType() { - return mType; - } - - public void setType(String value) { - mType = value; - } - -} diff --git a/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java b/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java index e755fed..630f0ea 100644 --- a/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java +++ b/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java @@ -1,11 +1,17 @@ package com.majinnaibu.monstercards.models; +import android.annotation.SuppressLint; + import androidx.annotation.NonNull; import androidx.room.ColumnInfo; import androidx.room.Entity; -import androidx.room.Ignore; 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; @@ -13,11 +19,12 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Set; import java.util.UUID; @Entity +@SuppressLint("DefaultLocale") +@SuppressWarnings("unused") public class Monster { @PrimaryKey @@ -28,71 +35,240 @@ public class Monster { @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 = "blindsight_range", defaultValue = "0") + public int blindsightRange; + + @ColumnInfo(name = "is_blind_beyond_blindsight_range", defaultValue = "false") + public boolean isBlindBeyondBlindsightRange; + + @ColumnInfo(name = "darkvision_range", defaultValue = "0") + public int darkvisionRange; + + @ColumnInfo(name = "tremorsense_range", defaultValue = "0") + public int tremorsenseRange; + + @ColumnInfo(name = "truesight_range", defaultValue = "0") + public int truesightRange; + + @ColumnInfo(name = "telepathy_range", defaultValue = "0") + public int telepathyRange; + + @ColumnInfo(name = "understands_but_description", defaultValue = "") + public String understandsButDescription; + + @ColumnInfo(name = "skills") + public Set skills; + + @ColumnInfo(name = "damage_immunities") + public Set damageImmunities; + + @ColumnInfo(name = "damage_resistances") + public Set damageResistances; + + @ColumnInfo(name = "damage_vulnerabilities") + public Set damageVulnerabilities; + + @ColumnInfo(name = "condition_immunities") + public Set conditionImmunities; + + @ColumnInfo(name = "languages") + public Set languages; + + @ColumnInfo(name = "abilities") + public Set abilities; + + @ColumnInfo(name = "actions") + public Set actions; + + @ColumnInfo(name = "reactions") + public Set reactions; + + @ColumnInfo(name = "lair_actions") + public Set lairActions; + + @ColumnInfo(name = "legendary_actions") + public Set legendaryActions; + + @ColumnInfo(name = "regional_actions") + public Set regionalActions; + public Monster() { + id = UUID.randomUUID(); name = ""; - mAbilities = new ArrayList<>(); - mActions = new ArrayList<>(); - mConditionImmunities = new HashSet<>(); - mDamageTypes = new HashSet<>(); - mLanguages = new HashSet<>(); - mSavingThrows = new HashSet<>(); - mSkills = new HashSet<>(); - } + 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 = ""; - @Ignore() - private String mSize; - - public String getSize() { - return mSize; - } - - public void setSize(String value) { - mSize = value; - } - - @Ignore() - private String mType; - - public String getType() { - return mType; - } - - public void setType(String value) { - mType = value; - } - - @Ignore() - private String mTag; - - public String getTag() { - return mTag; - } - - public void setTag(String value) { - mTag = value; - } - - @Ignore() - private String mAlignment; - - public String getAlignment() { - return mAlignment; - } - - public void setAlignment(String value) { - mAlignment = value; + skills = 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; - String size = getSize(); if (!StringHelper.isNullOrEmpty(size)) { sb.append(size); isFirstOutput = false; } - String type = getType(); if (!StringHelper.isNullOrEmpty(type)) { if (!isFirstOutput) { sb.append(" "); @@ -101,18 +277,16 @@ public class Monster { isFirstOutput = false; } - String tag = getTag(); - if (!StringHelper.isNullOrEmpty(tag)) { + if (!StringHelper.isNullOrEmpty(subtype)) { if (!isFirstOutput) { sb.append(" "); } sb.append("("); - sb.append(tag); + sb.append(subtype); sb.append(")"); isFirstOutput = false; } - String alignment = getAlignment(); if (!StringHelper.isNullOrEmpty(alignment)) { if (!isFirstOutput) { sb.append(", "); @@ -123,21 +297,22 @@ public class Monster { return sb.toString(); } - public int getAbilityScore(String abilityScoreName) { - if ("strength".equals(abilityScoreName) || "str".equals(abilityScoreName)) { - return getStrengthScore(); - } else if ("dexterity".equals(abilityScoreName) || "dex".equals(abilityScoreName)) { - return getDexterityScore(); - } else if ("constitution".equals(abilityScoreName) || "con".equals(abilityScoreName)) { - return getConstitutionScore(); - } else if ("intelligence".equals(abilityScoreName) || "int".equals(abilityScoreName)) { - return getIntelligenceScore(); - } else if ("wisdom".equals(abilityScoreName) || "wis".equals(abilityScoreName)) { - return getWisdomScore(); - } else if ("charisma".equals(abilityScoreName) || "cha".equals(abilityScoreName)) { - return getCharismaScore(); - } else { - return 10; + 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; } } @@ -145,261 +320,155 @@ public class Monster { return (int) Math.floor((score - 10) / 2.0); } - public int getAbilityModifier(String abilityScoreName) { - int score = getAbilityScore(abilityScoreName); - return getAbilityModifierForScore(score); - } - - @Ignore() - private int mStrengthScore; - - public int getStrengthScore() { - return mStrengthScore; - } - - public void setStrengthScore(int value) { - mStrengthScore = value; - } - - public int getStrengthModifier() { - return getAbilityModifierForScore(getStrengthScore()); - } - - @Ignore() - private int mDexterityScore; - - public int getDexterityScore() { - return mDexterityScore; - } - - public void setDexterityScore(int value) { - mDexterityScore = value; - } - - public int getDexterityModifier() { - return getAbilityModifierForScore(getDexterityScore()); - } - - @Ignore() - private int mConstitutionScore; - - public int getConstitutionScore() { - return mConstitutionScore; - } - - public void setConstitutionScore(int value) { - mConstitutionScore = value; - } - - public int getConstitutionModifier() { - return getAbilityModifierForScore(getConstitutionScore()); - } - - @Ignore() - private int mIntelligenceScore; - - public int getIntelligenceScore() { - return mIntelligenceScore; - } - - public void setIntelligenceScore(int value) { - mIntelligenceScore = value; - } - - public int getIntelligenceModifier() { - return getAbilityModifierForScore(getIntelligenceScore()); - } - - @Ignore() - private int mWisdomScore; - - public int getWisdomScore() { - return mWisdomScore; - } - - public void setWisdomScore(int value) { - mWisdomScore = value; - } - - public int getWisdomModifier() { - return getAbilityModifierForScore(getWisdomScore()); - } - - @Ignore() - private int mCharismaScore; - - public int getCharismaScore() { - return mCharismaScore; - } - - public void setCharismaScore(int value) { - mCharismaScore = value; - } - - public int getCharismaModifier() { - return getAbilityModifierForScore(getCharismaScore()); - } - - @Ignore() - private String mArmorName; - - public String getArmorName() { - return mArmorName; - } - - public void setArmorName(String value) { - mArmorName = value; - } - - @Ignore() - private int mShieldBonus; - - public int getShieldBonus() { - return mShieldBonus; - } - - public void setShieldBonus(int value) { - mShieldBonus = value; - } - - @Ignore() - private int mNaturalArmorBonus; - - public int getNaturalArmorBonus() { - return mNaturalArmorBonus; - } - - public void setNaturalArmorBonus(int value) { - mNaturalArmorBonus = value; - } - - @Ignore() - private String mOtherArmorDescription; - - public String getOtherArmorDescription() { - return mOtherArmorDescription; - } - - public void setOtherArmorDescription(String value) { - mOtherArmorDescription = value; - } - - public String getArmorClass() { - boolean hasShield = getShieldBonus() != 0; - String armorName = getArmorName(); - if (StringHelper.isNullOrEmpty(armorName) || "none".equals(armorName)) { - // 10 + dexMod + 2 for shieldBonus "15" or "17 (shield)" - return String.format(Locale.US, "%d%s", BASE_ARMOR_CLASS + getDexterityModifier() + getShieldBonus(), hasShield ? " (shield)" : ""); - } else if ("natural armor".equals(armorName)) { - // 10 + dexMod + naturalArmorBonus + 2 for shieldBonus "16 (natural armor)" or "18 (natural armor, shield)" - return String.format(Locale.US, "%d (natural armor%s)", BASE_ARMOR_CLASS + getDexterityModifier() + getNaturalArmorBonus() + getShieldBonus(), hasShield ? ", shield" : ""); - } else if ("mage armor".equals(armorName)) { - // 10 + dexMod + 2 for shield + 3 for mage armor "15 (18 with mage armor)" or 17 (shield, 20 with mage armor) - return String.format(Locale.US, "%d (%s%d with mage armor)", BASE_ARMOR_CLASS + getDexterityModifier() + getShieldBonus(), hasShield ? "shield, " : "", MAGE_ARMOR_ARMOR_CLASS + getDexterityModifier() + getShieldBonus()); - } else if ("padded".equals(armorName)) { - // 11 + dexMod + 2 for shield "18 (padded armor, shield)" - return String.format(Locale.US, "%d (padded%s)", PADDED_ARMOR_ARMOR_CLASS + getDexterityModifier() + getShieldBonus(), hasShield ? ", shield" : ""); - } else if ("leather".equals(armorName)) { - // 11 + dexMod + 2 for shield "18 (leather, shield)" - return String.format(Locale.US, "%d (leather%s)", LEATHER_ARMOR_CLASS + getDexterityModifier() + getShieldBonus(), hasShield ? ", shield" : ""); - } else if ("studded".equals(armorName)) { - // 12 + dexMod +2 for shield "17 (studded leather)" - return String.format(Locale.US, "%d (studded leather%s)", STUDDED_LEATHER_ARMOR_CLASS + getDexterityModifier() + getShieldBonus(), hasShield ? ", shield" : ""); - } else if ("hide".equals(armorName)) { - // 12 + Min(2, dexMod) + 2 for shield "12 (hide armor)" - return String.format(Locale.US, "%d (hide%s)", HIDE_ARMOR_CLASS + Math.min(2, getDexterityModifier()) + getShieldBonus(), hasShield ? ", shield" : ""); - } else if ("chain shirt".equals(armorName)) { - // 13 + Min(2, dexMod) + 2 for shield "12 (chain shirt)" - return String.format(Locale.US, "%d (chain shirt%s)", CHAIN_SHIRT_ARMOR_CLASS + Math.min(2, getDexterityModifier()) + getShieldBonus(), hasShield ? ", shield" : ""); - } else if ("scale mail".equals(armorName)) { - // 14 + Min(2, dexMod) + 2 for shield "14 (scale mail)" - return String.format(Locale.US, "%d (scale mail%s)", SCALE_MAIL_ARMOR_CLASS + Math.min(2, getDexterityModifier()) + getShieldBonus(), hasShield ? ", shield" : ""); - } else if ("breastplate".equals(armorName)) { - // 14 + Min(2, dexMod) + 2 for shield "16 (breastplate)" - return String.format(Locale.US, "%d (breastplate%s)", BREASTPLATE_ARMOR_CLASS + Math.min(2, getDexterityModifier()) + getShieldBonus(), hasShield ? ", shield" : ""); - } else if ("half plate".equals(armorName)) { - // 15 + Min(2, dexMod) + 2 for shield "17 (half plate)" - return String.format(Locale.US, "%d (half plate%s)", HALF_PLATE_ARMOR_CLASS + Math.min(2, getDexterityModifier()) + getShieldBonus(), hasShield ? ", shield" : ""); - } else if ("ring mail".equals(armorName)) { - // 14 + 2 for shield "14 (ring mail) - return String.format(Locale.US, "%d (ring mail%s)", RING_MAIL_ARMOR_CLASS + getShieldBonus(), hasShield ? ", shield" : ""); - } else if ("chain mail".equals(armorName)) { - // 16 + 2 for shield "16 (chain mail)" - return String.format(Locale.US, "%d (chain mail%s)", CHAIN_MAIL_ARMOR_CLASS + getShieldBonus(), hasShield ? ", shield" : ""); - } else if ("splint".equals(armorName)) { - // 17 + 2 for shield "17 (splint)" - return String.format(Locale.US, "%d (splint%s)", SPLINT_ARMOR_CLASS + getShieldBonus(), hasShield ? ", shield" : ""); - } else if ("plate".equals(armorName)) { - // 18 + 2 for shield "18 (plate)" - return String.format(Locale.US, "%d (plate%s)", PLATE_ARMOR_CLASS + getShieldBonus(), hasShield ? ", shield" : ""); - } else if ("other".equals(armorName)) { - // pure string value shield check does nothing just copies the string from otherArmorDesc - return getOtherArmorDescription(); - } else { - return ""; + 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; } } - private static final int BASE_ARMOR_CLASS = 10; - private static final int MAGE_ARMOR_ARMOR_CLASS = BASE_ARMOR_CLASS + 3; - private static final int PADDED_ARMOR_ARMOR_CLASS = BASE_ARMOR_CLASS + 1; - private static final int LEATHER_ARMOR_CLASS = BASE_ARMOR_CLASS + 1; - private static final int STUDDED_LEATHER_ARMOR_CLASS = BASE_ARMOR_CLASS + 2; - private static final int HIDE_ARMOR_CLASS = BASE_ARMOR_CLASS + 2; - private static final int CHAIN_SHIRT_ARMOR_CLASS = BASE_ARMOR_CLASS + 3; - private static final int SCALE_MAIL_ARMOR_CLASS = BASE_ARMOR_CLASS + 4; - private static final int BREASTPLATE_ARMOR_CLASS = BASE_ARMOR_CLASS + 4; - private static final int HALF_PLATE_ARMOR_CLASS = BASE_ARMOR_CLASS + 5; - private static final int RING_MAIL_ARMOR_CLASS = BASE_ARMOR_CLASS + 4; - private static final int CHAIN_MAIL_ARMOR_CLASS = BASE_ARMOR_CLASS + 6; - private static final int SPLINT_ARMOR_CLASS = BASE_ARMOR_CLASS + 7; - private static final int PLATE_ARMOR_CLASS = BASE_ARMOR_CLASS + 8; - - @Ignore() - private int mHitDice; - - public int getHitDice() { - return mHitDice; + 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 void setHitDice(int value) { - mHitDice = value; + 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; + } } - @Ignore() - private boolean mCustomHP; - - public boolean getCustomHP() { - return mCustomHP; + public int getStrengthModifier() { + return getAbilityModifierForScore(strengthScore); } - public void setCustomHP(boolean value) { - mCustomHP = value; + public int getDexterityModifier() { + return getAbilityModifierForScore(dexterityScore); } - @Ignore() - private String mHPText; - - public String getHPText() { - return mHPText; + public int getConstitutionModifier() { + return getAbilityModifierForScore(constitutionScore); } - public void setHPText(String value) { - mHPText = value; + 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 (getCustomHP()) { - return getHPText(); + if (hasCustomHP) { + return customHPDescription; } else { - int hitDice = getHitDice(); - int dieSize = getHitDieForSize(getSize()); + 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(Locale.US, "%d (%dd%d %+d)", hpTotal, hitDice, dieSize, conMod * hitDice); + return String.format("%d (%dd%d %+d)", hpTotal, hitDice, dieSize, conMod * hitDice); } } @@ -421,308 +490,93 @@ public class Monster { } } - @Ignore() - private String mSpeed; - - public String getSpeed() { - return mSpeed; - } - - public void setSpeed(String value) { - mSpeed = value; - } - - @Ignore() - private String mBurrowSpeed; - - public String getBurrowSpeed() { - return mBurrowSpeed; - } - - public void setBurrowSpeed(String value) { - mBurrowSpeed = value; - } - - @Ignore() - private String mClimbSpeed; - - public String getClimbSpeed() { - return mClimbSpeed; - } - - public void setClimbSpeed(String value) { - mClimbSpeed = value; - } - - @Ignore() - private String mFlySpeed; - - public String getFlySpeed() { - return mFlySpeed; - } - - public void setFlySpeed(String value) { - mFlySpeed = value; - } - - @Ignore() - private boolean mHover; - - public boolean getHover() { - return mHover; - } - - public void setHover(boolean value) { - mHover = value; - } - - @Ignore() - private String mSwimSpeed; - - public String getSwimSpeed() { - return mSwimSpeed; - } - - public void setSwimSpeed(String value) { - mSwimSpeed = value; - } - - @Ignore() - private boolean mCustomSpeed; - - public boolean getCustomSpeed() { - return mCustomSpeed; - } - - public void setCustomSpeed(boolean value) { - mCustomSpeed = value; - } - - @Ignore() - private String mSpeedDescription; - - public String getSpeedDescription() { - return mSpeedDescription; - } - - public void setSpeedDescription(String value) { - mSpeedDescription = value; - } - public String getSpeedText() { - if (getCustomSpeed()) { - return getSpeedDescription(); + if (hasCustomSpeed) { + return customSpeedDescription; } else { ArrayList speedParts = new ArrayList<>(); - speedParts.add(String.format("%s ft.", getSpeed())); - String burrowSpeed = getBurrowSpeed(); - if (!StringHelper.isNullOrEmpty(burrowSpeed) && !"0".equals(burrowSpeed)) { - speedParts.add(String.format("burrow %s ft.", burrowSpeed)); + if (walkSpeed > 0) { + speedParts.add(String.format("%d ft.", walkSpeed)); } - - String climbSpeed = getClimbSpeed(); - if (!StringHelper.isNullOrEmpty(climbSpeed) && !"0".equals(climbSpeed)) { - speedParts.add(String.format("climb %s ft.", climbSpeed)); + if (burrowSpeed > 0) { + speedParts.add(String.format("burrow %d ft.", burrowSpeed)); } - - String flySpeed = getFlySpeed(); - if (!StringHelper.isNullOrEmpty(flySpeed) && !"0".equals(flySpeed)) { - speedParts.add(String.format("fly %s ft.%s", flySpeed, getHover() ? " (hover)" : "")); + if (climbSpeed > 0) { + speedParts.add(String.format("climb %d ft.", climbSpeed)); } - - String swimSpeed = getSwimSpeed(); - if (!StringHelper.isNullOrEmpty(swimSpeed) && !"0".equals(swimSpeed)) { - speedParts.add(String.format("swim %s ft.", swimSpeed)); + 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(Locale.US, "%d (%+d)", getStrengthScore(), getStrengthModifier()); + return String.format("%d (%+d)", strengthScore, getStrengthModifier()); } public String getDexterityDescription() { - return String.format(Locale.US, "%d (%+d)", getDexterityScore(), getDexterityModifier()); + return String.format("%d (%+d)", dexterityScore, getDexterityModifier()); } public String getConstitutionDescription() { - return String.format(Locale.US, "%d (%+d)", getConstitutionScore(), getConstitutionModifier()); + return String.format("%d (%+d)", constitutionScore, getConstitutionModifier()); } public String getIntelligenceDescription() { - return String.format(Locale.US, "%d (%+d)", getIntelligenceScore(), getIntelligenceModifier()); + return String.format("%d (%+d)", intelligenceScore, getIntelligenceModifier()); } public String getWisdomDescription() { - return String.format(Locale.US, "%d (%+d)", getWisdomScore(), getWisdomModifier()); + return String.format("%d (%+d)", wisdomScore, getWisdomModifier()); } public String getCharismaDescription() { - return String.format(Locale.US, "%d (%+d)", getCharismaScore(), getCharismaModifier()); - } - - @Ignore() - private HashSet mSavingThrows; - - public Set getSavingThrows() { - return mSavingThrows; - } - - public void addSavingThrow(SavingThrow savingThrow) { - mSavingThrows.add(savingThrow); - } - - public void removeSavingThrow(SavingThrow savingThrow) { - mSavingThrows.remove(savingThrow); - } - - public void clearSavingThrows() { - mSavingThrows.clear(); + return String.format("%d (%+d)", charismaScore, getCharismaModifier()); } public String getSavingThrowsDescription() { - SavingThrow[] elements = new SavingThrow[mSavingThrows.size()]; - elements = mSavingThrows.toArray(elements); - Arrays.sort(elements); - StringBuilder sb = new StringBuilder(); - boolean isFirst = true; - for (SavingThrow st : elements) { - if (!isFirst) { - sb.append(", "); + List 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); } - String name = st.getName(); - - sb.append(String.format(Locale.US, "%s%s %+d", name.substring(0, 1).toUpperCase(Locale.US), name.substring(1), getAbilityModifier(name) + getProficiencyBonus())); - isFirst = false; } - return sb.toString(); + return StringHelper.join(", ", parts); } public int getProficiencyBonus() { - String challengeRating = getChallengeRating(); - if ("*".equals(challengeRating)) { - return getCustomProficiencyBonus(); - } else if ( - "0".equals(challengeRating) || - "1/8".equals(challengeRating) || - "1/4".equals(challengeRating) || - "1/2".equals(challengeRating) || - "1".equals(challengeRating) || - "2".equals(challengeRating) || - "3".equals(challengeRating) || - "4".equals(challengeRating) - ) { - return 2; - } else if ( - "5".equals(challengeRating) || - "6".equals(challengeRating) || - "7".equals(challengeRating) || - "8".equals(challengeRating) - ) { - return 3; - } else if ( - "9".equals(challengeRating) || - "10".equals(challengeRating) || - "11".equals(challengeRating) || - "12".equals(challengeRating) - ) { - return 4; - } else if ( - "13".equals(challengeRating) || - "14".equals(challengeRating) || - "15".equals(challengeRating) || - "16".equals(challengeRating) - ) { - return 5; - } else if ( - "17".equals(challengeRating) || - "18".equals(challengeRating) || - "19".equals(challengeRating) || - "20".equals(challengeRating) - ) { - return 6; - } else if ( - "21".equals(challengeRating) || - "22".equals(challengeRating) || - "23".equals(challengeRating) || - "24".equals(challengeRating) - ) { - return 7; - } else if ( - "25".equals(challengeRating) || - "26".equals(challengeRating) || - "27".equals(challengeRating) || - "28".equals(challengeRating) - ) { - return 8; - } else if ( - "29".equals(challengeRating) || - "30".equals(challengeRating) - ) { - return 9; + ChallengeRating challengeRating = this.challengeRating != null ? this.challengeRating : ChallengeRating.ONE; + if (challengeRating == ChallengeRating.CUSTOM) { + return customProficiencyBonus; } else { - return 0; + return challengeRating.proficiencyBonus; } } - @Ignore() - private String mChallengeRating; + public int getProficiencyBonus(ProficiencyType proficiencyType) { + switch (proficiencyType) { + case PROFICIENT: + return getProficiencyBonus(); + case EXPERTISE: + return getProficiencyBonus() * 2; + case NONE: + default: + return 0; + } - public String getChallengeRating() { - return mChallengeRating; - } - - public void setChallengeRating(String challengeRating) { - mChallengeRating = challengeRating; - // TODO: update proficiency bonus based on CR - } - - @Ignore() - private String mCustomChallengeRating; - - public String getCustomChallengeRating() { - return mCustomChallengeRating; - } - - public void setCustomChallengeRating(String challengeRating) { - mCustomChallengeRating = challengeRating; - } - - @Ignore() - private int mCustomProficiencyBonus; - - public int getCustomProficiencyBonus() { - return mCustomProficiencyBonus; - } - - public void setCustomProficiencyBonus(int proficiencyBonus) { - mCustomProficiencyBonus = proficiencyBonus; - } - - @Ignore() - private HashSet mSkills; - - public Set getSkills() { - return mSkills; - } - - public void addSkill(Skill skill) { - mSkills.add(skill); - } - - public void removeSkill(Skill skill) { - mSkills.remove(skill); - } - - public void clearSkill(Skill skill) { - mSkills.clear(); } public String getSkillsDescription() { - Skill[] elements = new Skill[mSkills.size()]; - elements = mSkills.toArray(elements); + Skill[] elements = new Skill[skills.size()]; + elements = skills.toArray(elements); Arrays.sort(elements); StringBuilder sb = new StringBuilder(); boolean isFirst = true; @@ -730,38 +584,17 @@ public class Monster { if (!isFirst) { sb.append(", "); } - String name = skill.getName(); sb.append(skill.getText(this)); isFirst = false; } return sb.toString(); } - @Ignore() - private HashSet mDamageTypes; - - public Set getDamageTypes() { - return mDamageTypes; - } - - public void addDamageType(DamageType damageType) { - // TODO: make this remove the damage type with the same name if it exists first - mDamageTypes.add(damageType); - } - - public void removeDamageType(DamageType damageType) { - mDamageTypes.remove(damageType); - } - - public void clearDamageTypes() { - mDamageTypes.clear(); - } - public String getDamageVulnerabilitiesDescription() { ArrayList vulnerabilities = new ArrayList<>(); - for (DamageType damageType : mDamageTypes) { - if (damageType != null && "v".equals(damageType.getType()) && !StringHelper.isNullOrEmpty(damageType.getName())) { - vulnerabilities.add(damageType.getName()); + for (String damageType : damageVulnerabilities) { + if (!StringHelper.isNullOrEmpty(damageType)) { + vulnerabilities.add(damageType); } } Collections.sort(vulnerabilities); @@ -769,178 +602,56 @@ public class Monster { } public String getDamageResistancesDescription() { - ArrayList vulnerabilities = new ArrayList<>(); - for (DamageType damageType : mDamageTypes) { - if (damageType != null && "r".equals(damageType.getType()) && !StringHelper.isNullOrEmpty(damageType.getName())) { - vulnerabilities.add(damageType.getName()); + ArrayList resistances = new ArrayList<>(); + for (String damageType : damageResistances) { + if (!StringHelper.isNullOrEmpty(damageType)) { + resistances.add(damageType); } } - Collections.sort(vulnerabilities); - return StringHelper.oxfordJoin(", ", ", and ", " and ", vulnerabilities); + Collections.sort(resistances); + return StringHelper.oxfordJoin(", ", ", and ", " and ", resistances); } public String getDamageImmunitiesDescription() { - ArrayList vulnerabilities = new ArrayList<>(); - for (DamageType damageType : mDamageTypes) { - if (damageType != null && "i".equals(damageType.getType()) && !StringHelper.isNullOrEmpty(damageType.getName())) { - vulnerabilities.add(damageType.getName()); + ArrayList immunities = new ArrayList<>(); + for (String damageType : damageImmunities) { + if (!StringHelper.isNullOrEmpty(damageType)) { + immunities.add(damageType); } } - Collections.sort(vulnerabilities); - return StringHelper.oxfordJoin(", ", ", and ", " and ", vulnerabilities); - } - - @Ignore() - private HashSet mConditionImmunities; - - public Set getConditionImmunities() { - return mConditionImmunities; - } - - public void addConditionImmunity(String condition) { - // TODO: filter out duplicates - mConditionImmunities.add(condition); - } - - public void removeConditionImmunity(String condition) { - // TODO: make sure this works even though we're using strings - mConditionImmunities.remove(condition); - } - - public void clearConditionImmunities() { - mConditionImmunities.clear(); - } - - public String getConditionImmunitiesDescription() { - ArrayList immunities = new ArrayList<>(getConditionImmunities()); Collections.sort(immunities); return StringHelper.oxfordJoin(", ", ", and ", " and ", immunities); } - @Ignore() - private String mBlindsight; - - public String getBlindsight() { - return mBlindsight; - } - - public void setBlindsight(String value) { - mBlindsight = value; - } - - @Ignore() - private boolean mIsBlind; - - public boolean getIsBlind() { - return mIsBlind; - } - - public void setIsBlind(boolean value) { - mIsBlind = value; - } - - @Ignore() - private String mDarkvision; - - public String getDarkvision() { - return mDarkvision; - } - - public void setDarkvision(String value) { - mDarkvision = value; - } - - @Ignore() - private String mTremorsense; - - public String getTremorsense() { - return mTremorsense; - } - - public void setTremorsense(String value) { - mTremorsense = value; - } - - @Ignore() - private String mTruesight; - - public String getTruesight() { - return mTruesight; - } - - public void setTruesight(String value) { - mTruesight = value; + public String getConditionImmunitiesDescription() { + ArrayList immunities = new ArrayList<>(conditionImmunities); + Collections.sort(immunities); + return StringHelper.oxfordJoin(", ", ", and ", " and ", immunities); } public String getSensesDescription() { ArrayList parts = new ArrayList<>(); - - String blindsight = getBlindsight(); - if (!StringHelper.isNullOrEmpty(blindsight) && !"0".equals(blindsight)) { - parts.add(String.format(Locale.US, "blindsight %s ft.%s", blindsight, getIsBlind() ? " (blind beyond this radius)" : "")); + if (blindsightRange > 0) { + parts.add(String.format("blindsight %d ft.%s", blindsightRange, isBlindBeyondBlindsightRange ? " (blind beyond this radius)" : "")); } - String darkvision = getDarkvision(); - if (!StringHelper.isNullOrEmpty(darkvision) && !"0".equals(darkvision)) { - parts.add(String.format(Locale.US, "darkvision %s ft.", darkvision)); + if (darkvisionRange > 0) { + parts.add(String.format("darkvision %d ft.", darkvisionRange)); } - String tremorsense = getTremorsense(); - if (!StringHelper.isNullOrEmpty(tremorsense) && !"0".equals(tremorsense)) { - parts.add(String.format(Locale.US, "tremorsense %s ft.", tremorsense)); + if (tremorsenseRange > 0) { + parts.add(String.format("tremorsense %d ft.", tremorsenseRange)); } - String truesight = getTruesight(); - if (!StringHelper.isNullOrEmpty(truesight) && !"0".equals(truesight)) { - parts.add(String.format(Locale.US, "truesight %s ft.", truesight)); + if (truesightRange > 0) { + parts.add(String.format("truesight %d ft.", truesightRange)); } - parts.add(String.format(Locale.US, "passive Perception %d", 10 + getWisdomModifier())); + parts.add(String.format("passive Perception %d", 10 + getWisdomModifier())); return StringHelper.join(", ", parts); } - @Ignore() - private HashSet mLanguages; - - public Set getLanguages() { - return mLanguages; - } - - public void addLanguage(Language value) { - mLanguages.add(value); - } - - public void removeLanguage(Language value) { - mLanguages.remove(value); - } - - public void clearLanguages() { - mLanguages.clear(); - } - - @Ignore() - private int mTelepathy; - - public int getTelepathy() { - return mTelepathy; - } - - public void setTelepathy(int value) { - mTelepathy = value; - } - - @Ignore() - private String mUnderstandsBut; - - public String getUnderstandsBut() { - return mUnderstandsBut; - } - - public void setUnderstandsBut(String value) { - mUnderstandsBut = value; - } - public String getLanguagesDescription() { ArrayList spokenLanguages = new ArrayList<>(); ArrayList understoodLanguages = new ArrayList<>(); - for (Language language : mLanguages) { + for (Language language : languages) { if (language != null) { if (language.getSpeaks()) { spokenLanguages.add(language.getName()); @@ -955,11 +666,9 @@ public class Monster { String spokenLanguagesString = StringHelper.oxfordJoin(", ", ", and ", " and ", spokenLanguages); String understoodLanguagesString = StringHelper.oxfordJoin(", ", ", and ", " and ", understoodLanguages); - String understandsBut = getUnderstandsBut(); - boolean hasUnderstandsBut = understandsBut.length() > 0; - int telepathy = getTelepathy(); - boolean hasTelepathy = telepathy > 0; - String telepathyString = String.format(Locale.US, ", telepathy %d ft.", telepathy); + 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) { @@ -967,13 +676,13 @@ public class Monster { "%s, understands %s%s%s", spokenLanguagesString, understoodLanguagesString, - hasUnderstandsBut ? " but " + understandsBut : "", + hasUnderstandsBut ? " but " + understandsButDescription : "", hasTelepathy ? telepathyString : ""); } else { return String.format( "%s%s%s", spokenLanguagesString, - hasUnderstandsBut ? " but " + understandsBut : "", + hasUnderstandsBut ? " but " + understandsButDescription : "", hasTelepathy ? telepathyString : ""); } } else { @@ -981,185 +690,95 @@ public class Monster { return String.format( "understands %s%s%s", understoodLanguagesString, - hasUnderstandsBut ? " but " + understandsBut : "", + hasUnderstandsBut ? " but " + understandsButDescription : "", hasTelepathy ? telepathyString : ""); } else { return String.format( "%S%s", - hasUnderstandsBut ? "none but " + understandsBut : "", + hasUnderstandsBut ? "none but " + understandsButDescription : "", hasTelepathy ? telepathyString : ""); } } } public String getChallengeRatingDescription() { - String challengeRating = getChallengeRating(); - if ("*".equals(challengeRating)) { - // Custom CR - return getCustomChallengeRating(); - } else if ("0".equals(challengeRating)) { - return "0 (10 XP)"; - } else if ("1/8".equals(challengeRating)) { - return "1/8 (25 XP)"; - } else if ("1/4".equals(challengeRating)) { - return "1/4 (50 XP)"; - } else if ("1/2".equals(challengeRating)) { - return "1/2 (100 XP)"; - } else if ("1".equals(challengeRating)) { - return "1 (200 XP)"; - } else if ("2".equals(challengeRating)) { - return "2 (450 XP)"; - } else if ("3".equals(challengeRating)) { - return "3 (700 XP)"; - } else if ("4".equals(challengeRating)) { - return "4 (1,100 XP)"; - } else if ("5".equals(challengeRating)) { - return "5 (1,800 XP)"; - } else if ("6".equals(challengeRating)) { - return "6 (2,300 XP)"; - } else if ("7".equals(challengeRating)) { - return "7 (2,900 XP)"; - } else if ("8".equals(challengeRating)) { - return "8 (3,900 XP)"; - } else if ("9".equals(challengeRating)) { - return "9 (5,000 XP)"; - } else if ("10".equals(challengeRating)) { - return "10 (5,900 XP)"; - } else if ("11".equals(challengeRating)) { - return "11 (7,200 XP)"; - } else if ("12".equals(challengeRating)) { - return "12 (8,400 XP)"; - } else if ("13".equals(challengeRating)) { - return "13 (10,000 XP)"; - } else if ("14".equals(challengeRating)) { - return "14 (11,500 XP)"; - } else if ("15".equals(challengeRating)) { - return "15 (13,000 XP)"; - } else if ("16".equals(challengeRating)) { - return "16 (15,000 XP)"; - } else if ("17".equals(challengeRating)) { - return "17 (18,000 XP)"; - } else if ("18".equals(challengeRating)) { - return "18 (20,000 XP)"; - } else if ("19".equals(challengeRating)) { - return "19 (22,000 XP)"; - } else if ("20".equals(challengeRating)) { - return "20 (25,000 XP)"; - } else if ("21".equals(challengeRating)) { - return "21 (33,000 XP)"; - } else if ("22".equals(challengeRating)) { - return "22 (41,000 XP)"; - } else if ("23".equals(challengeRating)) { - return "23 (50,000 XP)"; - } else if ("24".equals(challengeRating)) { - return "24 (62,000 XP)"; - } else if ("25".equals(challengeRating)) { - return "25 (75,000 XP)"; - } else if ("26".equals(challengeRating)) { - return "26 (90,000 XP)"; - } else if ("27".equals(challengeRating)) { - return "27 (105,000 XP)"; - } else if ("28".equals(challengeRating)) { - return "28 (120,000 XP)"; - } else if ("29".equals(challengeRating)) { - return "29 (135,000 XP)"; - } else if ("30".equals(challengeRating)) { - return "30 (155,000 XP)"; + ChallengeRating challengeRating = this.challengeRating != null ? this.challengeRating : ChallengeRating.ONE; + if (challengeRating == ChallengeRating.CUSTOM) { + return customChallengeRatingDescription; } else { - return getCustomChallengeRating(); + return challengeRating.displayName; } } - @Ignore() - private ArrayList mAbilities; - - public List getAbilities() { - return mAbilities; - } - - public void addAbility(Ability ability) { - mAbilities.add(ability); - } - - public void removeAbility(Ability ability) { - mAbilities.remove(ability); - } - - public void clearAbilities() { - mAbilities.clear(); - } - public List getAbilityDescriptions() { - ArrayList abilities = new ArrayList<>(); - for (Ability ability : getAbilities()) { - abilities.add(getPlaceholderReplacedText(String.format("__%s__ %s", ability.getName(), ability.getDescription()))); + ArrayList abilityDescriptions = new ArrayList<>(); + for (Trait ability : abilities) { + abilityDescriptions.add(getPlaceholderReplacedText(String.format("__%s__ %s", ability.name, ability.description))); } - return abilities; + return abilityDescriptions; } public String getPlaceholderReplacedText(String rawText) { return rawText - .replaceAll("\\[STR SAVE]", String.format(Locale.US, "%+d", getSpellSaveDC("strength"))) - .replaceAll("\\[STR ATK]", String.format(Locale.US, "%+d", getAttackBonus("strength"))) - .replaceAll("\\[DEX SAVE]", String.format(Locale.US, "%+d", getSpellSaveDC("dexterity"))) - .replaceAll("\\[DEX ATK]", String.format(Locale.US, "%+d", getAttackBonus("dexterity"))) - .replaceAll("\\[CON SAVE]", String.format(Locale.US, "%+d", getSpellSaveDC("constitution"))) - .replaceAll("\\[CON ATK]", String.format(Locale.US, "%+d", getAttackBonus("constitution"))) - .replaceAll("\\[INT SAVE]", String.format(Locale.US, "%+d", getSpellSaveDC("intelligence"))) - .replaceAll("\\[INT ATK]", String.format(Locale.US, "%+d", getAttackBonus("intelligence"))) - .replaceAll("\\[WIS SAVE]", String.format(Locale.US, "%+d", getSpellSaveDC("wisdom"))) - .replaceAll("\\[WIS ATK]", String.format(Locale.US, "%+d", getAttackBonus("wisdom"))) - .replaceAll("\\[CHA SAVE]", String.format(Locale.US, "%+d", getSpellSaveDC("charisma"))) - .replaceAll("\\[CHA ATK]", String.format(Locale.US, "%+d", getAttackBonus("charisma"))); + .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 getSavingThrow(String name) { - Set sts = getSavingThrows(); - for (SavingThrow st : sts) { - if (name.equals(st.getName())) { - return getAbilityModifier(name) + getProficiencyBonus(); - } - } - return getAbilityModifier(name); + public int getSpellSaveDC(AbilityScore abilityScore) { + return 8 + getProficiencyBonus() + getAbilityModifier(abilityScore); } - public String getWisdomSave() { - return String.format(Locale.US, "%+d", getSavingThrow("wis")); - } - - public int getSpellSaveDC(String abilityScoreName) { - return 8 + getProficiencyBonus() + getAbilityModifier(abilityScoreName); - } - - public int getAttackBonus(String abilityScoreName) { - return getProficiencyBonus() + getAbilityModifier(abilityScoreName); + public int getAttackBonus(AbilityScore abilityScore) { + return getProficiencyBonus() + getAbilityModifier(abilityScore); } public List getActionDescriptions() { - ArrayList actions = new ArrayList<>(); - for (Action action : getActions()) { - actions.add(getPlaceholderReplacedText(String.format("__%s__ %s", action.getName(), action.getDescription()))); + ArrayList actionDescriptions = new ArrayList<>(); + for (Trait action : actions) { + actionDescriptions.add(getPlaceholderReplacedText(String.format("__%s__ %s", action.name, action.description))); } - return actions; + return actionDescriptions; } - @Ignore() - private ArrayList mActions; - - public List getActions() { - return mActions; + public List getReactionDescriptions() { + ArrayList actionDescriptions = new ArrayList<>(); + for (Trait action : reactions) { + actionDescriptions.add(getPlaceholderReplacedText(String.format("__%s__ %s", action.name, action.description))); + } + return actionDescriptions; } - public void addAction(Action ability) { - mActions.add(ability); + public List getLegendaryActionDescriptions() { + ArrayList actionDescriptions = new ArrayList<>(); + for (Trait action : legendaryActions) { + actionDescriptions.add(getPlaceholderReplacedText(String.format("__%s__ %s", action.name, action.description))); + } + return actionDescriptions; } - public void removeAction(Action ability) { - mActions.remove(ability); + public List getLairActionDescriptions() { + ArrayList actionDescriptions = new ArrayList<>(); + for (Trait action : lairActions) { + actionDescriptions.add(getPlaceholderReplacedText(String.format("__%s__ %s", action.name, action.description))); + } + return actionDescriptions; } - public void clearActions() { - mActions.clear(); + public List getRegionalActionDescriptions() { + ArrayList actionDescriptions = new ArrayList<>(); + for (Trait action : regionalActions) { + actionDescriptions.add(getPlaceholderReplacedText(String.format("__%s__ %s", action.name, action.description))); + } + return actionDescriptions; } - } diff --git a/app/src/main/java/com/majinnaibu/monstercards/models/Skill.java b/app/src/main/java/com/majinnaibu/monstercards/models/Skill.java index 3580f0e..6553657 100644 --- a/app/src/main/java/com/majinnaibu/monstercards/models/Skill.java +++ b/app/src/main/java/com/majinnaibu/monstercards/models/Skill.java @@ -1,70 +1,69 @@ package com.majinnaibu.monstercards.models; -import java.util.Comparator; -import java.util.Locale; +import android.annotation.SuppressLint; +import com.majinnaibu.monstercards.data.enums.AbilityScore; +import com.majinnaibu.monstercards.data.enums.AdvantageType; +import com.majinnaibu.monstercards.data.enums.ProficiencyType; + +import java.util.Comparator; + +@SuppressLint("DefaultLocale") public class Skill implements Comparator, Comparable { - private String mName; - private String mAbilityScoreName; - private String mNote; + public String name; + public AbilityScore abilityScore; + public AdvantageType advantageType; + public ProficiencyType proficiencyType; - public Skill(String name, String abilityScoreName) { - mName = name; - mAbilityScoreName = abilityScoreName; - mNote = ""; + public Skill(String name, AbilityScore abilityScore) { + this(name, abilityScore, AdvantageType.NONE, ProficiencyType.PROFICIENT); } - public Skill(String name, String abilityScoreName, String note) { - mName = name; - mAbilityScoreName = abilityScoreName; - mNote = note; + public Skill(String name, AbilityScore abilityScore, AdvantageType advantageType) { + this(name, abilityScore, advantageType, ProficiencyType.PROFICIENT); } - public String getName() { - return mName; - } - - public void setName(String name) { - mName = name; - } - - public String getAbilityScoreName() { - return mAbilityScoreName; - } - - public void setAbilityScoreName(String abilityScoreName) { - mAbilityScoreName = abilityScoreName; - } - - public String getNote() { - return mNote; + public Skill(String name, AbilityScore abilityScore, AdvantageType advantageType, ProficiencyType proficiencyType) { + this.name = name; + this.abilityScore = abilityScore; + this.advantageType = advantageType; + this.proficiencyType = proficiencyType; } public int getSkillBonus(Monster monster) { - int bonus = monster.getAbilityModifier(mAbilityScoreName); - if (" (ex)".equals(getNote())) { - bonus += 2 * monster.getProficiencyBonus(); - } else { - bonus += monster.getProficiencyBonus(); + int modifier = monster.getAbilityModifier(abilityScore); + switch (proficiencyType) { + case PROFICIENT: + return modifier + monster.getProficiencyBonus(); + case EXPERTISE: + return modifier + monster.getProficiencyBonus() * 2; + case NONE: + default: + return modifier; } - return bonus; } public String getText(Monster monster) { int bonus = getSkillBonus(monster); - return String.format(Locale.US, "%s%s %d", mName.substring(0, 1), mName.substring(1), bonus); + return String.format( + "%s%s %+d%s", + name.substring(0, 1), + name.substring(1), + bonus, + advantageType == AdvantageType.ADVANTAGE ? " A" : advantageType == AdvantageType.DISADVANTAGE ? " D" : "" + ); } @Override public int compareTo(Skill o) { - return this.getName().compareToIgnoreCase(o.getName()); + return this.name.compareToIgnoreCase(o.name); } @Override public int compare(Skill o1, Skill o2) { - return o1.getName().compareToIgnoreCase(o2.getName()); + return o1.name.compareToIgnoreCase(o2.name); } } diff --git a/app/src/main/java/com/majinnaibu/monstercards/models/Trait.java b/app/src/main/java/com/majinnaibu/monstercards/models/Trait.java new file mode 100644 index 0000000..61a5c55 --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/models/Trait.java @@ -0,0 +1,12 @@ +package com.majinnaibu.monstercards.models; + +public class Trait { + + public String name; + public String description; + + public Trait(String name, String description) { + this.name = name; + this.description = description; + } +} diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java b/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java index e587b77..d157ea2 100644 --- a/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java @@ -14,23 +14,21 @@ import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; import com.majinnaibu.monstercards.R; +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.CommonMarkHelper; import com.majinnaibu.monstercards.helpers.StringHelper; -import com.majinnaibu.monstercards.models.Ability; -import com.majinnaibu.monstercards.models.Action; -import com.majinnaibu.monstercards.models.DamageType; import com.majinnaibu.monstercards.models.Language; import com.majinnaibu.monstercards.models.Monster; -import com.majinnaibu.monstercards.models.SavingThrow; import com.majinnaibu.monstercards.models.Skill; - -import java.util.List; +import com.majinnaibu.monstercards.models.Trait; @SuppressWarnings("FieldCanBeLocal") public class MonsterFragment extends Fragment { @@ -43,83 +41,96 @@ public class MonsterFragment extends Fragment { // TODO: remove this block make the monster ID a parameter to the view and get the monster from saved data (sqlite) Monster monster = new Monster(); // Name - monster.name ="Pixie"; + monster.name = "Pixie"; // Meta - monster.setSize("tiny"); - monster.setType("fey"); - monster.setTag(""); - monster.setAlignment("neutral good"); + monster.size = "tiny"; + monster.type = "fey"; + monster.subtype = ""; + monster.alignment = "neutral good"; + monster.armorType = ArmorType.NONE; // Armor & Armor Class - monster.setArmorName("none"); - monster.setShieldBonus(0); - monster.setNaturalArmorBonus(7); - monster.setOtherArmorDescription("14"); + monster.shieldBonus = 0; + monster.naturalArmorBonus = 7; + monster.otherArmorDescription = "14"; // Hit Points - monster.setHitDice(1); - monster.setCustomHP(false); - monster.setHPText("11 (2d8 + 2)"); - monster.setSpeed("10"); - monster.setBurrowSpeed("0"); - monster.setClimbSpeed("0"); - monster.setFlySpeed("30"); - monster.setHover(false); - monster.setSwimSpeed("0"); - monster.setCustomSpeed(false); - monster.setSpeedDescription("30 ft., swim 30 ft."); + monster.hitDice = 1; + monster.hasCustomHP = false; + monster.customHPDescription = "11 (2d8 + 2)"; + monster.walkSpeed = 10; + monster.burrowSpeed = 0; + monster.climbSpeed = 0; + monster.flySpeed = 30; + monster.canHover = false; + monster.swimSpeed = 0; + monster.hasCustomSpeed = false; + monster.customSpeedDescription = "30 ft., swim 30 ft."; // Ability Scores - monster.setStrengthScore(Integer.parseInt("2")); - monster.setDexterityScore(Integer.parseInt("20")); - monster.setConstitutionScore(Integer.parseInt("8")); - monster.setIntelligenceScore(Integer.parseInt("10")); - monster.setWisdomScore(Integer.parseInt("14")); - monster.setCharismaScore(Integer.parseInt("15")); + monster.strengthScore = Integer.parseInt("2"); + monster.dexterityScore = Integer.parseInt("20"); + monster.constitutionScore = Integer.parseInt("8"); + monster.intelligenceScore = Integer.parseInt("10"); + monster.wisdomScore = Integer.parseInt("14"); + monster.charismaScore = Integer.parseInt("15"); +// monster.strengthScore = 10; +// monster.dexterityScore = 10; +// monster.constitutionScore = 10; +// monster.intelligenceScore = 10; +// monster.wisdomScore = 10; +// monster.charismaScore = 10; + // Saving Throws - monster.addSavingThrow(new SavingThrow("str", 0)); - monster.addSavingThrow(new SavingThrow("dex", 1)); - monster.addSavingThrow(new SavingThrow("con", 2)); - monster.addSavingThrow(new SavingThrow("int", 3)); - monster.addSavingThrow(new SavingThrow("wis", 4)); - monster.addSavingThrow(new SavingThrow("cha", 5)); + monster.strengthSavingThrowAdvantage = AdvantageType.NONE; + monster.strengthSavingThrowProficiency = ProficiencyType.NONE; + monster.dexteritySavingThrowAdvantage = AdvantageType.ADVANTAGE; + monster.dexteritySavingThrowProficiency = ProficiencyType.PROFICIENT; + monster.constitutionSavingThrowAdvantage = AdvantageType.DISADVANTAGE; + monster.constitutionSavingThrowProficiency = ProficiencyType.EXPERTISE; + monster.intelligenceSavingThrowAdvantage = AdvantageType.NONE; + monster.intelligenceSavingThrowProficiency = ProficiencyType.EXPERTISE; + monster.wisdomSavingThrowAdvantage = AdvantageType.ADVANTAGE; + monster.wisdomSavingThrowProficiency = ProficiencyType.PROFICIENT; + monster.charismaSavingThrowAdvantage = AdvantageType.DISADVANTAGE; + monster.charismaSavingThrowProficiency = ProficiencyType.NONE; //Skills - monster.addSkill(new Skill("perception", "wis")); - monster.addSkill(new Skill("stealth", "dexterity")); + monster.skills.add(new Skill("perception", AbilityScore.WISDOM)); + monster.skills.add(new Skill("stealth", AbilityScore.DEXTERITY)); // Damage Types - monster.addDamageType(new DamageType("acid", " (Vulnerable)", "v")); - monster.addDamageType(new DamageType("bludgeoning", " (Vulnerable)", "v")); - monster.addDamageType(new DamageType("cold", " (Resistant)", "r")); - monster.addDamageType(new DamageType("fire", " (Resistant)", "r")); - monster.addDamageType(new DamageType("force", " (Immune)", "i")); - monster.addDamageType(new DamageType("lightning", " (Immune)", "i")); - monster.addDamageType(new DamageType("necrotic", " (Vulnerable)", "v")); - monster.addDamageType(new DamageType("piercing", " (Resistant)", "r")); - monster.addDamageType(new DamageType("poison", " (Immune)", "i")); + monster.damageImmunities.add("force"); + monster.damageImmunities.add("lightning"); + monster.damageImmunities.add("poison"); + monster.damageResistances.add("cold"); + monster.damageResistances.add("fire"); + monster.damageResistances.add("piercing"); + monster.damageVulnerabilities.add("acid"); + monster.damageVulnerabilities.add("bludgeoning"); + monster.damageVulnerabilities.add("necrotic"); // Condition Immunities - monster.addConditionImmunity("blinded"); + monster.conditionImmunities.add("blinded"); // Senses - monster.setBlindsight("10"); - monster.setIsBlind(true); - monster.setDarkvision("20"); - monster.setTremorsense("30"); - monster.setTruesight("40"); - monster.setTelepathy(20); - monster.setUnderstandsBut("doesn't care"); + monster.blindsightRange = 10; + monster.isBlindBeyondBlindsightRange = true; + monster.darkvisionRange = 20; + monster.tremorsenseRange = 30; + monster.truesightRange = 40; + monster.telepathyRange = 20; + monster.understandsButDescription = "doesn't care"; // Languages - monster.addLanguage(new Language("English", true)); - monster.addLanguage(new Language("Steve", false)); - monster.addLanguage(new Language("Spanish", true)); - monster.addLanguage(new Language("French", true)); - monster.addLanguage(new Language("Mermataur", false)); - monster.addLanguage(new Language("Goldfish", false)); + monster.languages.add(new Language("English", true)); + monster.languages.add(new Language("Steve", false)); + monster.languages.add(new Language("Spanish", true)); + monster.languages.add(new Language("French", true)); + monster.languages.add(new Language("Mermataur", false)); + monster.languages.add(new Language("Goldfish", false)); // Challenge Rating - monster.setChallengeRating("*"); - monster.setCustomChallengeRating("Infinite (0XP)"); - monster.setCustomProficiencyBonus(4); + monster.challengeRating = ChallengeRating.CUSTOM; + monster.customChallengeRatingDescription = "Infinite (0XP)"; + monster.customProficiencyBonus = 4; // Abilities - monster.addAbility(new Ability("Spellcasting", "The acolyte is a 1st-level spellcaster. Its spellcasting ability is Wisdom (spell save DC [WIS SAVE], [WIS ATK] to hit with spell attacks). The acolyte has following cleric spells prepared:\n\n\n> Cantrips (at will): _light, sacred flame, thaumaturgy_\n> 1st level (3 slots): _bless, cure wounds, sanctuary_")); - monster.addAbility(new Ability("Amphibious", "The dragon can breathe air and water.")); - monster.addAbility(new Ability("Legendary Resistance (3/Day)", "If the dragon fails a saving throw, it can choose to succeed instead.")); + monster.abilities.add(new Trait("Spellcasting", "The acolyte is a 1st-level spellcaster. Its spellcasting ability is Wisdom (spell save DC [WIS SAVE], [WIS ATK] to hit with spell attacks). The acolyte has following cleric spells prepared:\n\n\n> Cantrips (at will): _light, sacred flame, thaumaturgy_\n> 1st level (3 slots): _bless, cure wounds, sanctuary_")); + monster.abilities.add(new Trait("Amphibious", "The dragon can breathe air and water.")); + monster.abilities.add(new Trait("Legendary Resistance (3/Day)", "If the dragon fails a saving throw, it can choose to succeed instead.")); // Actions - monster.addAction(new Action("Club", "_Melee Weapon Attack:_ [STR ATK] to hit, reach 5 ft., one target. _Hit:_ 2 (1d4) bludgeoning damage.")); + monster.actions.add(new Trait("Club", "_Melee Weapon Attack:_ [STR ATK] to hit, reach 5 ft., one target. _Hit:_ 2 (1d4) bludgeoning damage.")); // END remove block monsterViewModel = new ViewModelProvider(this).get(MonsterViewModel.class); @@ -127,256 +138,166 @@ public class MonsterFragment extends Fragment { monsterViewModel.setMonster(monster); final TextView monsterName = root.findViewById(R.id.name); - monsterViewModel.getName().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(@Nullable String name) { - monsterName.setText(name); - } - }); + monsterViewModel.getName().observe(getViewLifecycleOwner(), name -> monsterName.setText(name)); final TextView monsterMeta = root.findViewById(R.id.meta); - monsterViewModel.getMeta().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(@Nullable String metaText) { - monsterMeta.setText(metaText); - } - }); + monsterViewModel.getMeta().observe(getViewLifecycleOwner(), metaText -> monsterMeta.setText(metaText)); final TextView monsterArmorClass = root.findViewById(R.id.armor_class); - monsterViewModel.getArmorClass().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(@Nullable String armorText) { - monsterArmorClass.setText(Html.fromHtml("Armor Class " + armorText)); - } - }); + monsterViewModel.getArmorClass().observe(getViewLifecycleOwner(), armorText -> monsterArmorClass.setText(Html.fromHtml("Armor Class " + armorText))); final TextView monsterHitPoints = root.findViewById(R.id.hit_points); - monsterViewModel.getHitPoints().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String hitPoints) { - monsterHitPoints.setText(Html.fromHtml("Hit Points " + hitPoints)); - } - }); + monsterViewModel.getHitPoints().observe(getViewLifecycleOwner(), hitPoints -> monsterHitPoints.setText(Html.fromHtml("Hit Points " + hitPoints))); final TextView monsterSpeed = root.findViewById(R.id.speed); - monsterViewModel.getSpeed().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String speed) { - monsterSpeed.setText(Html.fromHtml("Speed " + speed)); - } - }); + monsterViewModel.getSpeed().observe(getViewLifecycleOwner(), speed -> monsterSpeed.setText(Html.fromHtml("Speed " + speed))); final TextView monsterStrength = root.findViewById(R.id.strength); - monsterViewModel.getStrength().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String strength) { - monsterStrength.setText(strength); - } - }); + monsterViewModel.getStrength().observe(getViewLifecycleOwner(), strength -> monsterStrength.setText(strength)); final TextView monsterDexterity = root.findViewById(R.id.dexterity); - monsterViewModel.getDexterity().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String dexterity) { - monsterDexterity.setText(dexterity); - } - }); + monsterViewModel.getDexterity().observe(getViewLifecycleOwner(), dexterity -> monsterDexterity.setText(dexterity)); final TextView monsterConstitution = root.findViewById(R.id.constitution); - monsterViewModel.getConstitution().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String constitution) { - monsterConstitution.setText(constitution); - } - }); + monsterViewModel.getConstitution().observe(getViewLifecycleOwner(), constitution -> monsterConstitution.setText(constitution)); final TextView monsterIntelligence = root.findViewById(R.id.intelligence); - monsterViewModel.getIntelligence().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String intelligence) { - monsterIntelligence.setText(intelligence); - } - }); + monsterViewModel.getIntelligence().observe(getViewLifecycleOwner(), intelligence -> monsterIntelligence.setText(intelligence)); final TextView monsterWisdom = root.findViewById(R.id.wisdom); - monsterViewModel.getWisdom().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String wisdom) { - monsterWisdom.setText(wisdom); - } - }); + monsterViewModel.getWisdom().observe(getViewLifecycleOwner(), wisdom -> monsterWisdom.setText(wisdom)); final TextView monsterCharisma = root.findViewById(R.id.charisma); - monsterViewModel.getCharisma().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String charisma) { - monsterCharisma.setText(charisma); - } - }); + monsterViewModel.getCharisma().observe(getViewLifecycleOwner(), charisma -> monsterCharisma.setText(charisma)); final TextView monsterSavingThrows = root.findViewById(R.id.saving_throws); - monsterViewModel.getSavingThrows().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String savingThrows) { - if (StringHelper.isNullOrEmpty(savingThrows)) { - monsterSavingThrows.setVisibility(View.GONE); - } else { - monsterSavingThrows.setVisibility(View.VISIBLE); - } - monsterSavingThrows.setText(Html.fromHtml("Saving Throws " + savingThrows)); + monsterViewModel.getSavingThrows().observe(getViewLifecycleOwner(), savingThrows -> { + if (StringHelper.isNullOrEmpty(savingThrows)) { + monsterSavingThrows.setVisibility(View.GONE); + } else { + monsterSavingThrows.setVisibility(View.VISIBLE); } + monsterSavingThrows.setText(Html.fromHtml("Saving Throws " + savingThrows)); }); final TextView monsterSkills = root.findViewById(R.id.skills); - monsterViewModel.getSkills().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String skills) { - if (StringHelper.isNullOrEmpty(skills)) { - monsterSkills.setVisibility(View.GONE); - } else { - monsterSkills.setVisibility(View.VISIBLE); - } - monsterSkills.setText(Html.fromHtml("Skills " + skills)); + monsterViewModel.getSkills().observe(getViewLifecycleOwner(), skills -> { + if (StringHelper.isNullOrEmpty(skills)) { + monsterSkills.setVisibility(View.GONE); + } else { + monsterSkills.setVisibility(View.VISIBLE); } + monsterSkills.setText(Html.fromHtml("Skills " + skills)); }); final TextView monsterDamageVulnerabilities = root.findViewById(R.id.damage_vulnerabilities); - monsterViewModel.getDamageVulnerabilities().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String damageType) { - if (StringHelper.isNullOrEmpty(damageType)) { - monsterDamageVulnerabilities.setVisibility(View.GONE); - } else { - monsterDamageVulnerabilities.setVisibility(View.VISIBLE); - } - monsterDamageVulnerabilities.setText(Html.fromHtml("Damage Vulnerabilities " + damageType)); + monsterViewModel.getDamageVulnerabilities().observe(getViewLifecycleOwner(), damageType -> { + if (StringHelper.isNullOrEmpty(damageType)) { + monsterDamageVulnerabilities.setVisibility(View.GONE); + } else { + monsterDamageVulnerabilities.setVisibility(View.VISIBLE); } + monsterDamageVulnerabilities.setText(Html.fromHtml("Damage Vulnerabilities " + damageType)); }); final TextView monsterDamageResistances = root.findViewById(R.id.damage_resistances); - monsterViewModel.getDamageResistances().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String damageType) { - if (StringHelper.isNullOrEmpty(damageType)) { - monsterDamageResistances.setVisibility(View.GONE); - } else { - monsterDamageResistances.setVisibility(View.VISIBLE); - } - monsterDamageResistances.setText(Html.fromHtml("Damage Resistances " + damageType)); + monsterViewModel.getDamageResistances().observe(getViewLifecycleOwner(), damageType -> { + if (StringHelper.isNullOrEmpty(damageType)) { + monsterDamageResistances.setVisibility(View.GONE); + } else { + monsterDamageResistances.setVisibility(View.VISIBLE); } + monsterDamageResistances.setText(Html.fromHtml("Damage Resistances " + damageType)); }); final TextView monsterDamageImmunities = root.findViewById(R.id.damage_immunities); - monsterViewModel.getDamageImmunities().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String damageType) { - if (StringHelper.isNullOrEmpty(damageType)) { - monsterDamageImmunities.setVisibility(View.GONE); - } else { - monsterDamageImmunities.setVisibility(View.VISIBLE); - } - monsterDamageImmunities.setText(Html.fromHtml("Damage Immunities " + damageType)); + monsterViewModel.getDamageImmunities().observe(getViewLifecycleOwner(), damageType -> { + if (StringHelper.isNullOrEmpty(damageType)) { + monsterDamageImmunities.setVisibility(View.GONE); + } else { + monsterDamageImmunities.setVisibility(View.VISIBLE); } + monsterDamageImmunities.setText(Html.fromHtml("Damage Immunities " + damageType)); }); final TextView monsterConditionImmunities = root.findViewById(R.id.condition_immunities); - monsterViewModel.getConditionImmunities().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String conditionImmunities) { - if (StringHelper.isNullOrEmpty(conditionImmunities)) { - monsterConditionImmunities.setVisibility(View.GONE); - } else { - monsterConditionImmunities.setVisibility(View.VISIBLE); - } - monsterConditionImmunities.setText(Html.fromHtml("Condition Immunities " + conditionImmunities)); + monsterViewModel.getConditionImmunities().observe(getViewLifecycleOwner(), conditionImmunities -> { + if (StringHelper.isNullOrEmpty(conditionImmunities)) { + monsterConditionImmunities.setVisibility(View.GONE); + } else { + monsterConditionImmunities.setVisibility(View.VISIBLE); } + monsterConditionImmunities.setText(Html.fromHtml("Condition Immunities " + conditionImmunities)); }); final TextView monsterSenses = root.findViewById(R.id.senses); - monsterViewModel.getSenses().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String senses) { - if (StringHelper.isNullOrEmpty(senses)) { - monsterSenses.setVisibility(View.GONE); - } else { - monsterSenses.setVisibility(View.VISIBLE); - } - monsterSenses.setText(Html.fromHtml("Senses " + senses)); + monsterViewModel.getSenses().observe(getViewLifecycleOwner(), senses -> { + if (StringHelper.isNullOrEmpty(senses)) { + monsterSenses.setVisibility(View.GONE); + } else { + monsterSenses.setVisibility(View.VISIBLE); } + monsterSenses.setText(Html.fromHtml("Senses " + senses)); }); final TextView monsterLanguages = root.findViewById(R.id.languages); - monsterViewModel.getLanguages().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String languages) { - if (StringHelper.isNullOrEmpty(languages)) { - monsterLanguages.setVisibility(View.GONE); - } else { - monsterLanguages.setVisibility(View.VISIBLE); - } - monsterLanguages.setText(Html.fromHtml("Languages " + languages)); + monsterViewModel.getLanguages().observe(getViewLifecycleOwner(), languages -> { + if (StringHelper.isNullOrEmpty(languages)) { + monsterLanguages.setVisibility(View.GONE); + } else { + monsterLanguages.setVisibility(View.VISIBLE); } + monsterLanguages.setText(Html.fromHtml("Languages " + languages)); }); final TextView monsterChallenge = root.findViewById(R.id.challenge); - monsterViewModel.getChallenge().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String challengeRating) { - monsterChallenge.setText(Html.fromHtml("Challenge " + challengeRating)); - } - }); + monsterViewModel.getChallenge().observe(getViewLifecycleOwner(), challengeRating -> monsterChallenge.setText(Html.fromHtml("Challenge " + challengeRating))); final LinearLayout monsterAbilities = root.findViewById(R.id.abilities); - monsterViewModel.getAbilities().observe(getViewLifecycleOwner(), new Observer>() { - @Override - public void onChanged(List abilities) { - Context context = getContext(); - DisplayMetrics displayMetrics = null; - if (context != null) { - Resources resources = context.getResources(); - if (resources != null) { - displayMetrics = resources.getDisplayMetrics(); - } + monsterViewModel.getAbilities().observe(getViewLifecycleOwner(), abilities -> { + Context context = getContext(); + DisplayMetrics displayMetrics = null; + if (context != null) { + Resources resources = context.getResources(); + if (resources != null) { + displayMetrics = resources.getDisplayMetrics(); } - monsterAbilities.removeAllViews(); - if (abilities != null) { - for (String ability : abilities) { - TextView tvAbility = new TextView(context); - // TODO: Handle multiline block quotes specially so they stay multiline. - // TODO: Replace QuoteSpans in the result of fromHtml with something like this https://stackoverflow.com/questions/7717567/how-to-style-blockquotes-in-android-textviews to make them indent as expected - Spanned spannedText = Html.fromHtml(CommonMarkHelper.toHtml(ability)); - tvAbility.setText(spannedText); - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, displayMetrics); - tvAbility.setLayoutParams(layoutParams); - monsterAbilities.addView(tvAbility); - } + } + monsterAbilities.removeAllViews(); + if (abilities != null) { + for (String ability : abilities) { + TextView tvAbility = new TextView(context); + // TODO: Handle multiline block quotes specially so they stay multiline. + // TODO: Replace QuoteSpans in the result of fromHtml with something like this https://stackoverflow.com/questions/7717567/how-to-style-blockquotes-in-android-textviews to make them indent as expected + Spanned spannedText = Html.fromHtml(CommonMarkHelper.toHtml(ability)); + tvAbility.setText(spannedText); + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + layoutParams.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, displayMetrics); + tvAbility.setLayoutParams(layoutParams); + monsterAbilities.addView(tvAbility); } } }); final LinearLayout monsterActions = root.findViewById(R.id.actions); - monsterViewModel.getActions().observe(getViewLifecycleOwner(), new Observer>() { - @Override - public void onChanged(List actions) { - Context context = getContext(); - DisplayMetrics displayMetrics = null; - if (context != null) { - Resources resources = context.getResources(); - if (resources != null) { - displayMetrics = resources.getDisplayMetrics(); - } + monsterViewModel.getActions().observe(getViewLifecycleOwner(), actions -> { + Context context = getContext(); + DisplayMetrics displayMetrics = null; + if (context != null) { + Resources resources = context.getResources(); + if (resources != null) { + displayMetrics = resources.getDisplayMetrics(); } - monsterActions.removeAllViews(); - if (actions != null) { - for (String action : actions) { - TextView tvAction = new TextView(getContext()); - tvAction.setText(Html.fromHtml(CommonMarkHelper.toHtml(action))); - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.topMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, displayMetrics); - tvAction.setLayoutParams(layoutParams); - monsterActions.addView(tvAction); - } + } + monsterActions.removeAllViews(); + if (actions != null) { + for (String action : actions) { + TextView tvAction = new TextView(getContext()); + tvAction.setText(Html.fromHtml(CommonMarkHelper.toHtml(action))); + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + layoutParams.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, displayMetrics); + tvAction.setLayoutParams(layoutParams); + monsterActions.addView(tvAction); } } });