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)
|
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 {
|
var damageVulnerabilitiesDescription: String {
|
||||||
get {
|
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] {
|
var languagesArray: [String] {
|
||||||
get {
|
get {
|
||||||
return ["Common", "Goblin"]
|
return ["Common", "Goblin"]
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ class MonsterViewModel: ObservableObject {
|
|||||||
@Published var damageResistances: [StringViewModel]
|
@Published var damageResistances: [StringViewModel]
|
||||||
@Published var damageVulnerabilities: [StringViewModel]
|
@Published var damageVulnerabilities: [StringViewModel]
|
||||||
@Published var conditionImmunities: [StringViewModel]
|
@Published var conditionImmunities: [StringViewModel]
|
||||||
|
@Published var senses: [StringViewModel]
|
||||||
|
|
||||||
init(_ rawMonster: Monster? = nil) {
|
init(_ rawMonster: Monster? = nil) {
|
||||||
self.name = ""
|
self.name = ""
|
||||||
@@ -98,6 +99,7 @@ class MonsterViewModel: ObservableObject {
|
|||||||
self.damageResistances = []
|
self.damageResistances = []
|
||||||
self.damageVulnerabilities = []
|
self.damageVulnerabilities = []
|
||||||
self.conditionImmunities = []
|
self.conditionImmunities = []
|
||||||
|
self.senses = []
|
||||||
|
|
||||||
if (rawMonster != nil) {
|
if (rawMonster != nil) {
|
||||||
self.copyFromMonster(monster: rawMonster!)
|
self.copyFromMonster(monster: rawMonster!)
|
||||||
@@ -160,6 +162,10 @@ class MonsterViewModel: ObservableObject {
|
|||||||
self.conditionImmunities = (monster.conditionImmunities ?? [])
|
self.conditionImmunities = (monster.conditionImmunities ?? [])
|
||||||
.map {StringViewModel($0)}
|
.map {StringViewModel($0)}
|
||||||
.sorted()
|
.sorted()
|
||||||
|
|
||||||
|
self.senses = (monster.senses ?? [])
|
||||||
|
.map {StringViewModel($0)}
|
||||||
|
.sorted()
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyToMonster(monster: Monster) {
|
func copyToMonster(monster: Monster) {
|
||||||
@@ -226,5 +232,6 @@ class MonsterViewModel: ObservableObject {
|
|||||||
monster.damageImmunities = damageImmunities.map {$0.name}
|
monster.damageImmunities = damageImmunities.map {$0.name}
|
||||||
monster.damageResistances = damageResistances.map {$0.name}
|
monster.damageResistances = damageResistances.map {$0.name}
|
||||||
monster.damageVulnerabilities = damageVulnerabilities.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 {
|
get {
|
||||||
let proficiencyBonus = Double(monster?.proficiencyBonus ?? 0)
|
let proficiencyBonus = Double(monster?.proficiencyBonus ?? 0)
|
||||||
let abilityScoreModifier = Double(monster?.abilityModifierForAbilityScore(wrappedAbilityScore) ?? 0)
|
let abilityScoreModifier = Double(monster?.abilityModifierForAbilityScore(wrappedAbilityScore) ?? 0)
|
||||||
switch wrappedProficiency {
|
switch wrappedProficiency {
|
||||||
case .none:
|
case .none:
|
||||||
return Int64(abilityScoreModifier)
|
return Int(abilityScoreModifier)
|
||||||
case .proficient:
|
case .proficient:
|
||||||
return Int64(abilityScoreModifier + proficiencyBonus)
|
return Int(abilityScoreModifier + proficiencyBonus)
|
||||||
case .expertise:
|
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="name" attributeType="String" defaultValueString="Unnamed Monster"/>
|
||||||
<attribute name="naturalArmorBonus" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
<attribute name="naturalArmorBonus" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
<attribute name="otherArmorDescription" attributeType="String" defaultValueString=""/>
|
<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="shieldBonus" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
<attribute name="size" attributeType="String" defaultValueString=""/>
|
<attribute name="size" attributeType="String" defaultValueString=""/>
|
||||||
<attribute name="strengthSavingThrowAdvantage" attributeType="String" defaultValueString="none"/>
|
<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"/>
|
<relationship name="monster" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Monster" inverseName="skills" inverseEntity="Monster"/>
|
||||||
</entity>
|
</entity>
|
||||||
<elements>
|
<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"/>
|
<element name="Skill" positionX="-63" positionY="135" width="128" height="14"/>
|
||||||
</elements>
|
</elements>
|
||||||
</model>
|
</model>
|
||||||
@@ -20,6 +20,7 @@ struct EditMonster: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
|
Group {
|
||||||
NavigationLink(
|
NavigationLink(
|
||||||
"Basic Info",
|
"Basic Info",
|
||||||
destination: EditBasicInfo(monsterViewModel: monsterViewModel))
|
destination: EditBasicInfo(monsterViewModel: monsterViewModel))
|
||||||
@@ -60,6 +61,13 @@ struct EditMonster: View {
|
|||||||
"Damage Vulnerabilities",
|
"Damage Vulnerabilities",
|
||||||
destination: EditStrings(viewModel: monsterViewModel, path: \.damageVulnerabilities, title: "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)
|
.onAppear(perform: copyMonsterToLocal)
|
||||||
.toolbar(content: {
|
.toolbar(content: {
|
||||||
ToolbarItem(placement: .primaryAction) {
|
ToolbarItem(placement: .primaryAction) {
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ struct ResistancesAndImmunitiesView: View {
|
|||||||
let monsterDamageResistancesDescription = monster.damageResistancesDescription
|
let monsterDamageResistancesDescription = monster.damageResistancesDescription
|
||||||
let monsterDamageImmunitiesDescription = monster.damageImmunitiesDescription
|
let monsterDamageImmunitiesDescription = monster.damageImmunitiesDescription
|
||||||
let monsterConditionImmunitiesDescription = monster.conditionImmunitiesDescription
|
let monsterConditionImmunitiesDescription = monster.conditionImmunitiesDescription
|
||||||
|
let monsterSensesDescription = monster.sensesDescription
|
||||||
|
|
||||||
// Damage Vulnerabilities
|
// Damage Vulnerabilities
|
||||||
if (!monsterDamageVulnerabilitiesDescription.isEmpty) {
|
if (!monsterDamageVulnerabilitiesDescription.isEmpty) {
|
||||||
@@ -165,6 +166,13 @@ struct ResistancesAndImmunitiesView: View {
|
|||||||
Text(monsterConditionImmunitiesDescription)
|
Text(monsterConditionImmunitiesDescription)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Senses
|
||||||
|
if (!monsterSensesDescription.isEmpty) {
|
||||||
|
LabeledField("Senses") {
|
||||||
|
Text(monsterSensesDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user