diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/models/Language.java b/Android/app/src/main/java/com/majinnaibu/monstercards/models/Language.java index a670740..b7e31da 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/models/Language.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/models/Language.java @@ -1,74 +1,37 @@ package com.majinnaibu.monstercards.models; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - import java.util.Comparator; -import java.util.Objects; public class Language implements Comparator, Comparable { - private String mName; - private boolean mSpeaks; - public Language(String name, boolean speaks) { mName = name; mSpeaks = speaks; } + private String mName; public String getName() { return mName; } - public void setName(String value) { mName = value; } + private boolean mSpeaks; public boolean getSpeaks() { return mSpeaks; } - public void setSpeaks(boolean value) { mSpeaks = value; } @Override public int compareTo(Language o) { - if (this.mSpeaks && !o.mSpeaks) { - return -1; - } - if (!this.mSpeaks && o.mSpeaks) { - return 1; - } - return this.mName.compareToIgnoreCase(o.mName); + return this.getName().compareToIgnoreCase(o.getName()); } @Override - public int compare(@NonNull Language o1, Language o2) { - if (o1.mSpeaks && !o2.mSpeaks) { - return -1; - } - if (!o1.mSpeaks && o2.mSpeaks) { - return 1; - } - return o1.mName.compareToIgnoreCase(o2.mName); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { - return false; - } - if (!(obj instanceof Language)) { - return false; - } - Language otherLanguage = (Language) obj; - if (!Objects.equals(this.mName, otherLanguage.mName)) { - return false; - } - if (this.mSpeaks != otherLanguage.mSpeaks) { - return false; - } - return true; + public int compare(Language o1, Language o2) { + return o1.getName().compareToIgnoreCase(o2.getName()); } } diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java b/Android/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java index 403fe85..4968b97 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java @@ -4,6 +4,7 @@ import com.majinnaibu.monstercards.helpers.StringHelper; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Locale; @@ -14,6 +15,9 @@ public class Monster { public Monster() { mSavingThrows = new HashSet<>(); mSkills = new HashSet<>(); + mDamageTypes = new HashSet<>(); + mConditionImmunities = new HashSet<>(); + mLanguages = new HashSet<>(); } private String mName; @@ -619,4 +623,221 @@ public class Monster { return sb.toString(); } + 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()); + } + } + Collections.sort(vulnerabilities); + return StringHelper.oxfordJoin(", ", ", and ", " and ", vulnerabilities); + } + 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()); + } + } + Collections.sort(vulnerabilities); + return StringHelper.oxfordJoin(", ", ", and ", " and ", vulnerabilities); + } + 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()); + } + } + Collections.sort(vulnerabilities); + return StringHelper.oxfordJoin(", ", ", and ", " and ", vulnerabilities); + } + + 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); + } + + private String mBlindsight; + public String getBlindsight() { + return mBlindsight; + } + public void setBlindsight(String value) { + mBlindsight = value; + } + + private boolean mIsBlind; + public boolean getIsBlind() { + return mIsBlind; + } + public void setIsBlind(boolean value) { + mIsBlind = value; + } + + private String mDarkvision; + public String getDarkvision() { + return mDarkvision; + } + public void setDarkvision(String value) { + mDarkvision = value; + } + + private String mTremorsense; + public String getTremorsense() { + return mTremorsense; + } + public void setTremorsense(String value) { + mTremorsense = value; + } + + private String mTruesight; + public String getTruesight() { + return mTruesight; + } + public void setTruesight(String value) { + mTruesight = value; + } + + 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)" : "")); + } + String darkvision = getDarkvision(); + if (!StringHelper.isNullOrEmpty(darkvision) && !"0".equals(darkvision)) { + parts.add(String.format(Locale.US, "darkvision %s ft.", darkvision)); + } + String tremorsense = getTremorsense(); + if (!StringHelper.isNullOrEmpty(tremorsense) && !"0".equals(tremorsense)) { + parts.add(String.format(Locale.US, "tremorsense %s ft.", tremorsense)); + } + String truesight = getTruesight(); + if (!StringHelper.isNullOrEmpty(truesight) && !"0".equals(truesight)) { + parts.add(String.format(Locale.US, "truesight %s ft.", truesight)); + } + parts.add(String.format(Locale.US, "passive Perception %d", 10 + getWisdomModifier())); + + return StringHelper.join(", ", parts); + } + + 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(); + } + + private int mTelepathy; + public int getTelepathy() { + return mTelepathy; + } + public void setTelepathy(int value) { + mTelepathy = value; + } + + 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) { + if (language != null) { + if (language.getSpeaks()) { + spokenLanguages.add(language.getName()); + } else { + understoodLanguages.add(language.getName()); + } + } + } + Collections.sort(spokenLanguages); + Collections.sort(understoodLanguages); + + String spokenLanguagesString = StringHelper.oxfordJoin(", ", ", and ", " and ", spokenLanguages); + String understoodLanguagesString = StringHelper.oxfordJoin(", ", ", and ", " and ", understoodLanguages); + + 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); + + if (spokenLanguages.size() > 0) { + if (understoodLanguages.size() > 0) { + return String.format( + "%s, understands %s%s%s", + spokenLanguagesString, + understoodLanguagesString, + hasUnderstandsBut ? " but " + understandsBut : "", + hasTelepathy ? telepathyString : ""); + } else { + return String.format( + "%s%s%s", + spokenLanguagesString, + hasUnderstandsBut ? " but " + understandsBut : "", + hasTelepathy ? telepathyString : ""); + } + } else { + if (understoodLanguages.size() > 0) { + return String.format( + "understands %s%s%s", + understoodLanguagesString, + hasUnderstandsBut ? " but " + understandsBut : "", + hasTelepathy ? telepathyString : ""); + } else { + return String.format( + "%S%s", + hasUnderstandsBut ? "none but " + understandsBut : "", + hasTelepathy ? telepathyString : ""); + } + } + } + } diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java index e25773a..1a02cae 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java @@ -15,6 +15,8 @@ import androidx.lifecycle.ViewModelProvider; import com.majinnaibu.monstercards.R; import com.majinnaibu.monstercards.helpers.StringHelper; +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; @@ -70,6 +72,33 @@ public class MonsterFragment extends Fragment { //Skills monster.addSkill(new Skill("perception", "wis")); monster.addSkill(new Skill("stealth", "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")); + // Condition Immunities + monster.addConditionImmunity("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"); + // 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)); // Challenge Rating monster.setChallengeRating("*"); @@ -194,6 +223,84 @@ public class MonsterFragment extends Fragment { } }); + 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)); + } + }); + + 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)); + } + }); + + 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)); + } + }); + + 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)); + } + }); + + 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)); + } + }); + + 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)); + } + }); + return root; } } diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterViewModel.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterViewModel.java index 31bd2a5..8fd208e 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterViewModel.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterViewModel.java @@ -36,6 +36,18 @@ public class MonsterViewModel extends ViewModel { mSavingThrows.setValue(""); mSkills = new MutableLiveData<>(); mSkills.setValue(""); + mDamageVulnerabilities = new MutableLiveData<>(); + mDamageVulnerabilities.setValue(""); + mDamageResistances = new MutableLiveData<>(); + mDamageResistances.setValue(""); + mDamageImmunities = new MutableLiveData<>(); + mDamageImmunities.setValue(""); + mConditionImmunities = new MutableLiveData<>(); + mConditionImmunities.setValue(""); + mSenses = new MutableLiveData<>(); + mSenses.setValue(""); + mLanguages = new MutableLiveData<>(); + mLanguages.setValue(""); } private MutableLiveData mName; @@ -90,6 +102,30 @@ public class MonsterViewModel extends ViewModel { public LiveData getSkills() { return mSkills; } + private MutableLiveData mDamageVulnerabilities; + public LiveData getDamageVulnerabilities() { + return mDamageVulnerabilities; + } + private MutableLiveData mDamageResistances; + public LiveData getDamageResistances() { + return mDamageResistances; + } + private MutableLiveData mDamageImmunities; + public LiveData getDamageImmunities() { + return mDamageImmunities; + } + private MutableLiveData mConditionImmunities; + public LiveData getConditionImmunities() { + return mConditionImmunities; + } + private MutableLiveData mSenses; + public LiveData getSenses() { + return mSenses; + } + private MutableLiveData mLanguages; + public LiveData getLanguages() { + return mLanguages; + } private Monster mMonster; public void setMonster(Monster monster) { @@ -107,5 +143,11 @@ public class MonsterViewModel extends ViewModel { mCharisma.setValue(monster.getCharismaDescription()); mSavingThrows.setValue(monster.getSavingThrowsDescription()); mSkills.setValue(monster.getSkillsDescription()); + mDamageVulnerabilities.setValue(mMonster.getDamageVulnerabilitiesDescription()); + mDamageResistances.setValue(mMonster.getDamageResistancesDescription()); + mDamageImmunities.setValue(mMonster.getDamageImmunitiesDescription()); + mConditionImmunities.setValue(mMonster.getConditionImmunitiesDescription()); + mSenses.setValue(monster.getSensesDescription()); + mLanguages.setValue(mMonster.getLanguagesDescription()); } } \ No newline at end of file diff --git a/Android/app/src/main/res/layout/fragment_monster.xml b/Android/app/src/main/res/layout/fragment_monster.xml index 7ddd2b7..db68877 100644 --- a/Android/app/src/main/res/layout/fragment_monster.xml +++ b/Android/app/src/main/res/layout/fragment_monster.xml @@ -331,5 +331,83 @@ app:layout_constraintTop_toBottomOf="@+id/saving_throws" tools:text="Skills" /> + + + + + + + + + + + + \ No newline at end of file