Adds senses and passive perception.
Also makes modifier calculations return Int instead of Int64.
This commit is contained in:
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
<attribute name="name" attributeType="String" defaultValueString="Unnamed Monster"/>
|
||||
<attribute name="naturalArmorBonus" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="otherArmorDescription" attributeType="String" defaultValueString=""/>
|
||||
<attribute name="senses" optional="YES" attributeType="Transformable" valueTransformerName="NSSecureUnarchiveFromDataTransformerName" customClassName="[String]"/>
|
||||
<attribute name="shieldBonus" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="size" attributeType="String" defaultValueString=""/>
|
||||
<attribute name="strengthSavingThrowAdvantage" attributeType="String" defaultValueString="none"/>
|
||||
@@ -63,7 +64,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="824"/>
|
||||
<element name="Monster" positionX="-63" positionY="-18" width="128" height="839"/>
|
||||
<element name="Skill" positionX="-63" positionY="135" width="128" height="14"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -20,6 +20,7 @@ struct EditMonster: View {
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Group {
|
||||
NavigationLink(
|
||||
"Basic Info",
|
||||
destination: EditBasicInfo(monsterViewModel: monsterViewModel))
|
||||
@@ -60,6 +61,13 @@ struct EditMonster: View {
|
||||
"Damage Vulnerabilities",
|
||||
destination: EditStrings(viewModel: monsterViewModel, path: \.damageVulnerabilities, title: "Damage Vulnerabilities"))
|
||||
}
|
||||
Group {
|
||||
NavigationLink(
|
||||
"Senses",
|
||||
destination: EditStrings(viewModel: monsterViewModel, path: \.senses, title: "Senses"))
|
||||
}
|
||||
|
||||
}
|
||||
.onAppear(perform: copyMonsterToLocal)
|
||||
.toolbar(content: {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user