diff --git a/MonsterCards.xcodeproj/project.pbxproj b/MonsterCards.xcodeproj/project.pbxproj index 7c62193..cad44d6 100644 --- a/MonsterCards.xcodeproj/project.pbxproj +++ b/MonsterCards.xcodeproj/project.pbxproj @@ -18,6 +18,9 @@ E216B791260C1FE800FB205F /* LanguageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E216B790260C1FE800FB205F /* LanguageViewModel.swift */; }; E216B799260C2DF200FB205F /* EditLanguages.swift in Sources */ = {isa = PBXBuildFile; fileRef = E216B798260C2DF200FB205F /* EditLanguages.swift */; }; E216B79E260C396F00FB205F /* EditLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E216B79D260C396F00FB205F /* EditLanguage.swift */; }; + E216B7B7260C5A9800FB205F /* ChallengeRatingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E216B7B6260C5A9800FB205F /* ChallengeRatingViewModel.swift */; }; + E216B7BC260C691400FB205F /* EditChallengeRating.swift in Sources */ = {isa = PBXBuildFile; fileRef = E216B7BB260C691400FB205F /* EditChallengeRating.swift */; }; + E216B7C1260C6B6000FB205F /* MCChallengeRatingPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = E216B7C0260C6B6000FB205F /* MCChallengeRatingPicker.swift */; }; E2182E6425B22F8A00DFAEF8 /* Monster+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2182E6225B22F8A00DFAEF8 /* Monster+CoreDataClass.swift */; }; E24ACE502607326E009BF703 /* EditBasicInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24ACE4F2607326E009BF703 /* EditBasicInfo.swift */; }; E24ACE562607EE94009BF703 /* EditArmor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24ACE552607EE94009BF703 /* EditArmor.swift */; }; @@ -83,6 +86,9 @@ E216B790260C1FE800FB205F /* LanguageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageViewModel.swift; sourceTree = ""; }; E216B798260C2DF200FB205F /* EditLanguages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditLanguages.swift; sourceTree = ""; }; E216B79D260C396F00FB205F /* EditLanguage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditLanguage.swift; sourceTree = ""; }; + E216B7B6260C5A9800FB205F /* ChallengeRatingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChallengeRatingViewModel.swift; sourceTree = ""; }; + E216B7BB260C691400FB205F /* EditChallengeRating.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditChallengeRating.swift; sourceTree = ""; }; + E216B7C0260C6B6000FB205F /* MCChallengeRatingPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MCChallengeRatingPicker.swift; sourceTree = ""; }; E2182E6225B22F8A00DFAEF8 /* Monster+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Monster+CoreDataClass.swift"; sourceTree = ""; }; E24ACE4F2607326E009BF703 /* EditBasicInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditBasicInfo.swift; sourceTree = ""; }; E24ACE552607EE94009BF703 /* EditArmor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditArmor.swift; sourceTree = ""; }; @@ -234,6 +240,7 @@ E24ACE5F2607F45E009BF703 /* EditAbilityScores.swift */, E24ACE552607EE94009BF703 /* EditArmor.swift */, E24ACE4F2607326E009BF703 /* EditBasicInfo.swift */, + E216B7BB260C691400FB205F /* EditChallengeRating.swift */, E216B79D260C396F00FB205F /* EditLanguage.swift */, E216B798260C2DF200FB205F /* EditLanguages.swift */, E2B5285825B3028700AAA69E /* EditMonster.swift */, @@ -246,6 +253,7 @@ E2CB0DB726081A2F00142591 /* MCAbilityScorePicker.swift */, E210B83E25B42DAB0083EAC5 /* MCAdvantagePicker.swift */, E26CDA2A25CFB38E00E3F50D /* MCArmorTypePicker.swift */, + E216B7C0260C6B6000FB205F /* MCChallengeRatingPicker.swift */, E210B83925B42D980083EAC5 /* MCProficiencyPicker.swift */, E2BD703025B3BBB90058ED69 /* MCStepperField.swift */, E2BD702B25B3A8D70058ED69 /* MCTextField.swift */, @@ -259,6 +267,7 @@ E257101225B1B2790055B23B /* Models */ = { isa = PBXGroup; children = ( + E216B7B6260C5A9800FB205F /* ChallengeRatingViewModel.swift */, E20209E625D8DEB600EFE733 /* Enums */, E216B790260C1FE800FB205F /* LanguageViewModel.swift */, E2182E6225B22F8A00DFAEF8 /* Monster+CoreDataClass.swift */, @@ -443,11 +452,14 @@ E2570FFA25B1AE020055B23B /* Collections.swift in Sources */, E24ACE5B2607F0F2009BF703 /* EditSpeed.swift in Sources */, E2570FB925B1AC520055B23B /* MonsterCardsApp.swift in Sources */, + E216B7B7260C5A9800FB205F /* ChallengeRatingViewModel.swift in Sources */, E20209D325D8DD9600EFE733 /* Skill+CoreDataClass.swift in Sources */, E24ACE652607F55D009BF703 /* EditSavingThrows.swift in Sources */, E2BD702C25B3A8D70058ED69 /* MCTextField.swift in Sources */, + E216B7BC260C691400FB205F /* EditChallengeRating.swift in Sources */, E20209E825D8DEC100EFE733 /* AbilityScore.swift in Sources */, E210B83F25B42DAB0083EAC5 /* MCAdvantagePicker.swift in Sources */, + E216B7C1260C6B6000FB205F /* MCChallengeRatingPicker.swift in Sources */, E26CDA2B25CFB38E00E3F50D /* MCArmorTypePicker.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/MonsterCards/Models/ChallengeRatingViewModel.swift b/MonsterCards/Models/ChallengeRatingViewModel.swift new file mode 100644 index 0000000..33209fc --- /dev/null +++ b/MonsterCards/Models/ChallengeRatingViewModel.swift @@ -0,0 +1,46 @@ +// +// ChallengeRatingViewModel.swift +// MonsterCards +// +// Created by Tom Hicks on 3/24/21. +// + +import Foundation + +class ChallengeRatingViewModel: ObservableObject/*, Comparable*/, Identifiable { + + func encode(with coder: NSCoder) { + coder.encode(self.rating.rawValue, forKey: "rating") + + } + + static func == (lhs: ChallengeRatingViewModel, rhs: ChallengeRatingViewModel) -> Bool { + lhs.rating == rhs.rating && + lhs.customText == rhs.customText && + lhs.customProficiencyBonus == rhs.customProficiencyBonus + } + + @Published var rating: ChallengeRating + @Published var customText: String + @Published var customProficiencyBonus: Int64 + + init( + _ rating: ChallengeRating = .one, + _ customText: String = "", + _ customProficiencyBonus: Int64 = 0 + ) { + self.rating = rating + self.customText = customText + self.customProficiencyBonus = customProficiencyBonus + } + + init( + _ rating: String = ChallengeRating.one.rawValue, + _ customText: String = "", + _ customProficiencyBonus: Int64 = 0 + ) { + self.rating = ChallengeRating(rawValue: rating) ?? .one + self.customText = customText + self.customProficiencyBonus = customProficiencyBonus + } +} diff --git a/MonsterCards/Models/Enums/ChallengeRating.swift b/MonsterCards/Models/Enums/ChallengeRating.swift index 2150d80..396ac7d 100644 --- a/MonsterCards/Models/Enums/ChallengeRating.swift +++ b/MonsterCards/Models/Enums/ChallengeRating.swift @@ -8,6 +8,7 @@ import Foundation enum ChallengeRating: String, CaseIterable, Identifiable { + case custom = "Custom" case zero = "0" case oneEighth = "1/8" case oneQuarter = "1/4" @@ -42,12 +43,81 @@ enum ChallengeRating: String, CaseIterable, Identifiable { case twentyEight = "28" case twentyNine = "29" case thirty = "30" - case custom = "*" var id: ChallengeRating { self } - // Probably don't need this var displayName: String { - return rawValue + switch(self) { + case .custom: + return "Custom" + case .zero: + return "0 (10 XP)" + case .oneEighth: + return "1/8 (25 XP)" + case .oneQuarter: + return "1/4 (50 XP)" + case .oneHalf: + return "1/2 (100 XP)" + case .one: + return "1 (200 XP)" + case .two: + return "2 (450 XP)" + case .three: + return "3 (700 XP)" + case .four: + return "4 (1,100 XP)" + case .five: + return "5 (1,800 XP)" + case .six: + return "6 (2,300 XP)" + case .seven: + return "7 (2,900 XP)" + case .eight: + return "8 (3,900 XP)" + case .nine: + return "9 (5,000 XP)" + case .ten: + return "10 (5,900 XP)" + case .eleven: + return "11 (7,200 XP)" + case .twelve: + return "12 (8,400 XP)" + case .thirteen: + return "13 (10,000 XP)" + case .fourteen: + return "14 (11,500 XP)" + case .fifteen: + return "15 (13,000 XP)" + case .sixteen: + return "16 (15,000 XP)" + case .seventeen: + return "17 (18,000 XP)" + case .eighteen: + return "18 (20,000 XP)" + case .nineteen: + return "19 (22,000 XP)" + case .twenty: + return "20 (25,000 XP)" + case .twentyOne: + return "21 (33,000 XP)" + case .twentyTwo: + return "22 (41,000 XP)" + case .twentyThree: + return "23 (50,000 XP)" + case .twentyFour: + return "24 (62,000 XP)" + case .twentyFive: + return "25 (75,000 XP)" + case .twentySix: + return "26 (90,000 XP)" + case .twentySeven: + return "27 (105,000 XP)" + case .twentyEight: + return "28 (120,000 XP)" + case .twentyNine: + return "29 (135,000 XP)" + case .thirty: + return "30 (155,000 XP)" + } } } diff --git a/MonsterCards/Models/Monster+CoreDataClass.swift b/MonsterCards/Models/Monster+CoreDataClass.swift index fc79c01..e28c73d 100644 --- a/MonsterCards/Models/Monster+CoreDataClass.swift +++ b/MonsterCards/Models/Monster+CoreDataClass.swift @@ -321,79 +321,78 @@ public class Monster: NSManagedObject { } var proficiencyBonus: Int { - return 5 -// switch challengeRatingEnum { -// case .custom: -// return Int(customProficiencyBonus) -// case .zero: -// fallthrough -// case .oneEighth: -// fallthrough -// case .oneQuarter: -// fallthrough -// case .oneHalf: -// fallthrough -// case .one: -// fallthrough -// case .two: -// fallthrough -// case .three: -// fallthrough -// case .four: -// return 2 -// case .five: -// fallthrough -// case .six: -// fallthrough -// case .seven: -// fallthrough -// case .eight: -// return 3 -// case .nine: -// fallthrough -// case .ten: -// fallthrough -// case .eleven: -// fallthrough -// case .twelve: -// return 4 -// case .thirteen: -// fallthrough -// case .fourteen: -// fallthrough -// case .fifteen: -// fallthrough -// case .sixteen: -// return 5 -// case .seventeen: -// fallthrough -// case .eighteen: -// fallthrough -// case .nineteen: -// fallthrough -// case .twenty: -// return 6 -// case .twentyOne: -// fallthrough -// case .twentyTwo: -// fallthrough -// case .twentyThree: -// fallthrough -// case .twentyFour: -// return 7 -// case .twentyFive: -// fallthrough -// case .twentySix: -// fallthrough -// case .twentySeven: -// fallthrough -// case .twentyEight: -// return 8 -// case .twentyNine: -// fallthrough -// case .thirty: -// return 9 -// } + switch challengeRatingEnum { + case .custom: + return Int(customProficiencyBonus) + case .zero: + fallthrough + case .oneEighth: + fallthrough + case .oneQuarter: + fallthrough + case .oneHalf: + fallthrough + case .one: + fallthrough + case .two: + fallthrough + case .three: + fallthrough + case .four: + return 2 + case .five: + fallthrough + case .six: + fallthrough + case .seven: + fallthrough + case .eight: + return 3 + case .nine: + fallthrough + case .ten: + fallthrough + case .eleven: + fallthrough + case .twelve: + return 4 + case .thirteen: + fallthrough + case .fourteen: + fallthrough + case .fifteen: + fallthrough + case .sixteen: + return 5 + case .seventeen: + fallthrough + case .eighteen: + fallthrough + case .nineteen: + fallthrough + case .twenty: + return 6 + case .twentyOne: + fallthrough + case .twentyTwo: + fallthrough + case .twentyThree: + fallthrough + case .twentyFour: + return 7 + case .twentyFive: + fallthrough + case .twentySix: + fallthrough + case .twentySeven: + fallthrough + case .twentyEight: + return 8 + case .twentyNine: + fallthrough + case .thirty: + return 9 + } } func proficiencyBonusForType(_ profType: ProficiencyType) -> Int { @@ -748,7 +747,11 @@ public class Monster: NSManagedObject { var challengeRatingDescription: String { get { - return ""; + if (challengeRatingEnum != .custom) { + return challengeRatingEnum.displayName + } else { + return customChallengeRating ?? "" + } } } diff --git a/MonsterCards/Models/MonsterViewModel.swift b/MonsterCards/Models/MonsterViewModel.swift index e1a96f1..bf8fe18 100644 --- a/MonsterCards/Models/MonsterViewModel.swift +++ b/MonsterCards/Models/MonsterViewModel.swift @@ -57,6 +57,9 @@ class MonsterViewModel: ObservableObject { @Published var languages: [LanguageViewModel] @Published var telepathy: Int64 @Published var understandsBut: String + @Published var challengeRating: ChallengeRating + @Published var customChallengeRating: String + @Published var customProficiencyBonus: Int64 init(_ rawMonster: Monster? = nil) { self.name = "" @@ -106,6 +109,9 @@ class MonsterViewModel: ObservableObject { self.languages = [] self.telepathy = 0 self.understandsBut = "" + self.challengeRating = .one + self.customChallengeRating = "" + self.customProficiencyBonus = 0 if (rawMonster != nil) { self.copyFromMonster(monster: rawMonster!) @@ -153,6 +159,10 @@ class MonsterViewModel: ObservableObject { self.charismaSavingThrowProficiency = monster.charismaSavingThrowProficiencyEnum self.telepathy = monster.telepathy self.understandsBut = monster.understandsBut ?? "" + self.challengeRating = monster.challengeRatingEnum + self.customChallengeRating = monster.customChallengeRating ?? "" + self.customProficiencyBonus = monster.customProficiencyBonus + self.skills = (monster.skills?.allObjects.map {SkillViewModel(($0 as! Skill))})!.sorted() self.damageImmunities = (monster.damageImmunities ?? []) @@ -220,6 +230,9 @@ class MonsterViewModel: ObservableObject { monster.charismaSavingThrowProficiencyEnum = charismaSavingThrowProficiency monster.telepathy = telepathy monster.understandsBut = understandsBut + monster.challengeRatingEnum = challengeRating + monster.customChallengeRating = customChallengeRating + monster.customProficiencyBonus = customProficiencyBonus // Remove missing skills from raw monster monster.skills?.forEach {s in diff --git a/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents b/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents index 26464f1..34a6b06 100644 --- a/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents +++ b/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents @@ -17,6 +17,7 @@ + @@ -66,7 +67,7 @@ - + \ No newline at end of file diff --git a/MonsterCards/Views/EditChallengeRating.swift b/MonsterCards/Views/EditChallengeRating.swift new file mode 100644 index 0000000..4042e7a --- /dev/null +++ b/MonsterCards/Views/EditChallengeRating.swift @@ -0,0 +1,41 @@ +// +// EditChallengeRating.swift +// MonsterCards +// +// Created by Tom Hicks on 3/24/21. +// + +import SwiftUI + +struct EditChallengeRating: View { + @ObservedObject var viewModel: MonsterViewModel + + var body: some View { + let isUsingCustomProficiencyBonus = viewModel.challengeRating == ChallengeRating.custom + + VStack(alignment: .leading) { + MCChallengeRatingPicker( + label: "Rating", + value: $viewModel.challengeRating) + + MCTextField( + label: "Custom Text", + value: $viewModel.customChallengeRating) + .disabled(!isUsingCustomProficiencyBonus) + + MCStepperField( + label: "Custom Proficiency Bonus", + value: $viewModel.customProficiencyBonus) + .disabled(!isUsingCustomProficiencyBonus) + Spacer() + } + .padding() + } +} + +struct EditChallengeRating_Previews: PreviewProvider { + static var previews: some View { + let viewModel = MonsterViewModel() + EditChallengeRating(viewModel: viewModel) + } +} diff --git a/MonsterCards/Views/EditMonster.swift b/MonsterCards/Views/EditMonster.swift index 1b5771b..465b829 100644 --- a/MonsterCards/Views/EditMonster.swift +++ b/MonsterCards/Views/EditMonster.swift @@ -69,6 +69,10 @@ struct EditMonster: View { NavigationLink( "Languages", destination: EditLanguages(viewModel: monsterViewModel)) + + NavigationLink( + "Challenge Rating", + destination: EditChallengeRating(viewModel: monsterViewModel)) } } diff --git a/MonsterCards/Views/MCChallengeRatingPicker.swift b/MonsterCards/Views/MCChallengeRatingPicker.swift new file mode 100644 index 0000000..2a88c30 --- /dev/null +++ b/MonsterCards/Views/MCChallengeRatingPicker.swift @@ -0,0 +1,35 @@ +// +// MCChallengeRatingPicker.swift +// MonsterCards +// +// Created by Tom Hicks on 3/24/21. +// + +import SwiftUI + +struct MCChallengeRatingPicker: View { + var label: String = "" + var value: Binding + var body: some View { + VStack(alignment: .leading) { + Text(label) + .font(.caption2) + Picker( + selection: value, + label: Text(value.wrappedValue.displayName)) { + ForEach(ChallengeRating.allCases) {abilityScore in + Text(abilityScore.displayName).tag(abilityScore) + } + } + .pickerStyle(MenuPickerStyle()) + } + } +} + +struct MCChallengeRatingPicker_Previews: PreviewProvider { + static var previews: some View { + MCChallengeRatingPicker( + label: "Rating", + value: .constant(ChallengeRating.ten)) + } +} diff --git a/MonsterCards/Views/MonsterDetail.swift b/MonsterCards/Views/MonsterDetail.swift index 5ff035b..5767720 100644 --- a/MonsterCards/Views/MonsterDetail.swift +++ b/MonsterCards/Views/MonsterDetail.swift @@ -235,7 +235,7 @@ struct MonsterDetail: View { // Challenge Rating if (!monsterChallengeRatingDescription.isEmpty) { - LabeledField("Challenge Rating") { + LabeledField("Challenge") { Text(monsterChallengeRatingDescription) } }