Adds challenge rating and proficiency bonus to the monster editor.

This commit is contained in:
2021-03-25 00:30:58 -07:00
parent 70e5f5edf0
commit 4ea630ecca
10 changed files with 304 additions and 79 deletions

View File

@@ -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 = "<group>"; };
E216B798260C2DF200FB205F /* EditLanguages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditLanguages.swift; sourceTree = "<group>"; };
E216B79D260C396F00FB205F /* EditLanguage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditLanguage.swift; sourceTree = "<group>"; };
E216B7B6260C5A9800FB205F /* ChallengeRatingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChallengeRatingViewModel.swift; sourceTree = "<group>"; };
E216B7BB260C691400FB205F /* EditChallengeRating.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditChallengeRating.swift; sourceTree = "<group>"; };
E216B7C0260C6B6000FB205F /* MCChallengeRatingPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MCChallengeRatingPicker.swift; sourceTree = "<group>"; };
E2182E6225B22F8A00DFAEF8 /* Monster+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Monster+CoreDataClass.swift"; sourceTree = "<group>"; };
E24ACE4F2607326E009BF703 /* EditBasicInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditBasicInfo.swift; sourceTree = "<group>"; };
E24ACE552607EE94009BF703 /* EditArmor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditArmor.swift; sourceTree = "<group>"; };
@@ -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;

View File

@@ -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
}
}

View File

@@ -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)"
}
}
}

View File

@@ -321,79 +321,78 @@ public class Monster: NSManagedObject {
}
var proficiencyBonus: Int {
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
// 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
// }
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 ?? ""
}
}
}

View File

@@ -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

View File

@@ -17,6 +17,7 @@
<attribute name="constitutionSavingThrowProficiency" attributeType="String" defaultValueString="none"/>
<attribute name="constitutionScore" attributeType="Integer 64" defaultValueString="10" usesScalarValueType="YES"/>
<attribute name="customArmor" attributeType="String" defaultValueString=""/>
<attribute name="customChallengeRating" attributeType="String" defaultValueString=""/>
<attribute name="customHP" attributeType="String" defaultValueString=""/>
<attribute name="customProficiencyBonus" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="customSpeed" attributeType="String" defaultValueString=""/>
@@ -66,7 +67,7 @@
<relationship name="monster" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Monster" inverseName="skills" inverseEntity="Monster"/>
</entity>
<elements>
<element name="Monster" positionX="-63" positionY="-18" width="128" height="869"/>
<element name="Monster" positionX="-63" positionY="-18" width="128" height="884"/>
<element name="Skill" positionX="-63" positionY="135" width="128" height="14"/>
</elements>
</model>

View File

@@ -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)
}
}

View File

@@ -69,6 +69,10 @@ struct EditMonster: View {
NavigationLink(
"Languages",
destination: EditLanguages(viewModel: monsterViewModel))
NavigationLink(
"Challenge Rating",
destination: EditChallengeRating(viewModel: monsterViewModel))
}
}

View File

@@ -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<ChallengeRating>
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))
}
}

View File

@@ -235,7 +235,7 @@ struct MonsterDetail: View {
// Challenge Rating
if (!monsterChallengeRatingDescription.isEmpty) {
LabeledField("Challenge Rating") {
LabeledField("Challenge") {
Text(monsterChallengeRatingDescription)
}
}