diff --git a/iOS/MonsterCards/Helpers/StringHelper.swift b/iOS/MonsterCards/Helpers/StringHelper.swift index b395ce7..927c8dd 100644 --- a/iOS/MonsterCards/Helpers/StringHelper.swift +++ b/iOS/MonsterCards/Helpers/StringHelper.swift @@ -45,4 +45,12 @@ class StringHelper { return str!.containsCaseInsensitive(match) } + + static func safeEqualsIgnoreCase(_ str: String?, _ match: String) -> Bool { + if (str == nil) { + return false + } + + return str!.lowercased() == match.lowercased() + } } diff --git a/iOS/MonsterCards/Models/Monster+CoreDataClass.swift b/iOS/MonsterCards/Models/Monster+CoreDataClass.swift index 295d127..c485a98 100644 --- a/iOS/MonsterCards/Models/Monster+CoreDataClass.swift +++ b/iOS/MonsterCards/Models/Monster+CoreDataClass.swift @@ -625,7 +625,7 @@ public class Monster: NSManagedObject { } } - // MARK: OTHER + // MARK: Immunities, Resistances, and Vulnerabilities var damageVulnerabilitiesDescription: String { get { @@ -656,6 +656,40 @@ public class Monster: NSManagedObject { } } + // MARK: OTHER + + var passivePerception: Int { + get { + let perceptionSkill = skillsArray.first(where: { + StringHelper.safeEqualsIgnoreCase($0.name, "Perception") + }) + if (perceptionSkill == nil) { + return wisdomModifier + } else if (perceptionSkill?.wrappedProficiency == ProficiencyType.expertise) { + return wisdomModifier + proficiencyBonus + proficiencyBonus + } else if (perceptionSkill?.wrappedProficiency == ProficiencyType.proficient) { + return wisdomModifier + proficiencyBonus + } else { + return wisdomModifier + } + } + } + + var sensesDescription: String { + get { + var modifiedSenses = self.senses?.sorted() ?? [] + let hasPassivePerceptionSense = modifiedSenses.contains(where: { + $0.starts(with: "passive Perception") + }) + if (!hasPassivePerceptionSense) { + let calculatedPassivePerception = String(format: "passive Perception %+d", passivePerception) + modifiedSenses.append(calculatedPassivePerception) + } + + return modifiedSenses.sorted().joined(separator: ", ") + } + } + var languagesArray: [String] { get { return ["Common", "Goblin"] diff --git a/iOS/MonsterCards/Models/MonsterViewModel.swift b/iOS/MonsterCards/Models/MonsterViewModel.swift index 1d65613..ab893d6 100644 --- a/iOS/MonsterCards/Models/MonsterViewModel.swift +++ b/iOS/MonsterCards/Models/MonsterViewModel.swift @@ -53,6 +53,7 @@ class MonsterViewModel: ObservableObject { @Published var damageResistances: [StringViewModel] @Published var damageVulnerabilities: [StringViewModel] @Published var conditionImmunities: [StringViewModel] + @Published var senses: [StringViewModel] init(_ rawMonster: Monster? = nil) { self.name = "" @@ -98,6 +99,7 @@ class MonsterViewModel: ObservableObject { self.damageResistances = [] self.damageVulnerabilities = [] self.conditionImmunities = [] + self.senses = [] if (rawMonster != nil) { self.copyFromMonster(monster: rawMonster!) @@ -160,6 +162,10 @@ class MonsterViewModel: ObservableObject { self.conditionImmunities = (monster.conditionImmunities ?? []) .map {StringViewModel($0)} .sorted() + + self.senses = (monster.senses ?? []) + .map {StringViewModel($0)} + .sorted() } func copyToMonster(monster: Monster) { @@ -226,5 +232,6 @@ class MonsterViewModel: ObservableObject { monster.damageImmunities = damageImmunities.map {$0.name} monster.damageResistances = damageResistances.map {$0.name} monster.damageVulnerabilities = damageVulnerabilities.map {$0.name} + monster.senses = senses.map {$0.name} } } diff --git a/iOS/MonsterCards/Models/Skill+CoreDataClass.swift b/iOS/MonsterCards/Models/Skill+CoreDataClass.swift index 4ad1772..da583db 100644 --- a/iOS/MonsterCards/Models/Skill+CoreDataClass.swift +++ b/iOS/MonsterCards/Models/Skill+CoreDataClass.swift @@ -48,17 +48,17 @@ public class Skill: NSManagedObject { } } - var modifier: Int64 { + var modifier: Int { get { let proficiencyBonus = Double(monster?.proficiencyBonus ?? 0) let abilityScoreModifier = Double(monster?.abilityModifierForAbilityScore(wrappedAbilityScore) ?? 0) switch wrappedProficiency { case .none: - return Int64(abilityScoreModifier) + return Int(abilityScoreModifier) case .proficient: - return Int64(abilityScoreModifier + proficiencyBonus) + return Int(abilityScoreModifier + proficiencyBonus) case .expertise: - return Int64(abilityScoreModifier + 2 * proficiencyBonus) + return Int(abilityScoreModifier + 2 * proficiencyBonus) } } } diff --git a/iOS/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents b/iOS/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents index 528df97..43c88b7 100644 --- a/iOS/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents +++ b/iOS/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents @@ -39,6 +39,7 @@ + @@ -63,7 +64,7 @@ - + \ No newline at end of file diff --git a/iOS/MonsterCards/Views/EditMonster.swift b/iOS/MonsterCards/Views/EditMonster.swift index ea62540..3eb7ac4 100644 --- a/iOS/MonsterCards/Views/EditMonster.swift +++ b/iOS/MonsterCards/Views/EditMonster.swift @@ -20,45 +20,53 @@ struct EditMonster: View { var body: some View { List { - NavigationLink( - "Basic Info", - destination: EditBasicInfo(monsterViewModel: monsterViewModel)) + Group { + NavigationLink( + "Basic Info", + destination: EditBasicInfo(monsterViewModel: monsterViewModel)) + + NavigationLink( + "Armor", + destination: EditArmor(monsterViewModel: monsterViewModel)) + + NavigationLink( + "Speed", + destination: EditSpeed(monsterViewModel: monsterViewModel)) + + NavigationLink( + "Ability Scores", + destination: EditAbilityScores(monsterViewModel: monsterViewModel)) + + NavigationLink( + "Saving Throws", + destination: EditSavingThrows(monsterViewModel: monsterViewModel)) + + NavigationLink( + "Skills", + destination: EditSkills(monsterViewModel: monsterViewModel)) + + NavigationLink( + "Condition Immunities", + destination: EditStrings(viewModel: monsterViewModel, path: \.conditionImmunities, title: "Condition Immunities")) + + NavigationLink( + "Damage Immunities", + destination: EditStrings(viewModel: monsterViewModel, path: \.damageImmunities, title: "Damage Immunities")) + + NavigationLink( + "Damage Resistances", + destination: EditStrings(viewModel: monsterViewModel, path: \.damageResistances, title: "Damage Resistances")) + + NavigationLink( + "Damage Vulnerabilities", + destination: EditStrings(viewModel: monsterViewModel, path: \.damageVulnerabilities, title: "Damage Vulnerabilities")) + } + Group { + NavigationLink( + "Senses", + destination: EditStrings(viewModel: monsterViewModel, path: \.senses, title: "Senses")) + } - NavigationLink( - "Armor", - destination: EditArmor(monsterViewModel: monsterViewModel)) - - NavigationLink( - "Speed", - destination: EditSpeed(monsterViewModel: monsterViewModel)) - - NavigationLink( - "Ability Scores", - destination: EditAbilityScores(monsterViewModel: monsterViewModel)) - - NavigationLink( - "Saving Throws", - destination: EditSavingThrows(monsterViewModel: monsterViewModel)) - - NavigationLink( - "Skills", - destination: EditSkills(monsterViewModel: monsterViewModel)) - - NavigationLink( - "Condition Immunities", - destination: EditStrings(viewModel: monsterViewModel, path: \.conditionImmunities, title: "Condition Immunities")) - - NavigationLink( - "Damage Immunities", - destination: EditStrings(viewModel: monsterViewModel, path: \.damageImmunities, title: "Damage Immunities")) - - NavigationLink( - "Damage Resistances", - destination: EditStrings(viewModel: monsterViewModel, path: \.damageResistances, title: "Damage Resistances")) - - NavigationLink( - "Damage Vulnerabilities", - destination: EditStrings(viewModel: monsterViewModel, path: \.damageVulnerabilities, title: "Damage Vulnerabilities")) } .onAppear(perform: copyMonsterToLocal) .toolbar(content: { diff --git a/iOS/MonsterCards/Views/MonsterDetail.swift b/iOS/MonsterCards/Views/MonsterDetail.swift index b2786b7..0b0c921 100644 --- a/iOS/MonsterCards/Views/MonsterDetail.swift +++ b/iOS/MonsterCards/Views/MonsterDetail.swift @@ -137,6 +137,7 @@ struct ResistancesAndImmunitiesView: View { let monsterDamageResistancesDescription = monster.damageResistancesDescription let monsterDamageImmunitiesDescription = monster.damageImmunitiesDescription let monsterConditionImmunitiesDescription = monster.conditionImmunitiesDescription + let monsterSensesDescription = monster.sensesDescription // Damage Vulnerabilities if (!monsterDamageVulnerabilitiesDescription.isEmpty) { @@ -165,6 +166,13 @@ struct ResistancesAndImmunitiesView: View { Text(monsterConditionImmunitiesDescription) } } + + // Senses + if (!monsterSensesDescription.isEmpty) { + LabeledField("Senses") { + Text(monsterSensesDescription) + } + } } }