Adds challenge rating and proficiency bonus to the monster editor.

This commit is contained in:
2021-03-25 00:30:58 -07:00
parent 33e2b52dc3
commit 9fd5f55e9d
10 changed files with 304 additions and 79 deletions

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 {
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 ?? ""
}
}
}

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