Adds Saving Throws to the data model and monster editor.

This commit is contained in:
2020-10-03 22:31:47 -07:00
parent 23b840f3ff
commit 3c3ed3c94b
10 changed files with 634 additions and 151 deletions

View File

@@ -408,52 +408,99 @@
<rect key="frame" x="0.0" y="88" width="414" height="725"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="MCIntegerField" id="KwC-8P-1dy" userLabel="MCIntegerField" customClass="MCIntegerFieldTableViewCell">
<rect key="frame" x="0.0" y="28" width="414" height="43.5"/>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="MCRadioField" id="iSG-Tv-aCX" userLabel="MCRadioField" customClass="MCRadioFieldTableViewCell">
<rect key="frame" x="0.0" y="28" width="414" height="68"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="KwC-8P-1dy" id="Dwe-Tg-VQ6">
<rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="iSG-Tv-aCX" id="scU-nK-qiI">
<rect key="frame" x="0.0" y="0.0" width="414" height="68"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="RCc-cF-BI3" userLabel="Text Field">
<rect key="frame" x="82" y="5" width="192" height="34"/>
<constraints>
<constraint firstAttribute="height" constant="34" id="8Nj-FL-Ab6"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
<connections>
<action selector="textFieldValueChanged:" destination="KwC-8P-1dy" eventType="valueChanged" id="5In-Xx-LJB"/>
</connections>
</textField>
<stepper opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" maximumValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="vgc-Rg-Zc8">
<rect key="frame" x="294" y="6" width="100" height="32"/>
<constraints>
<constraint firstAttribute="height" constant="32" id="HhX-Qt-vVP"/>
<constraint firstAttribute="width" constant="100" id="Qn1-ca-Tsy"/>
</constraints>
<connections>
<action selector="stepperValueChanged:" destination="KwC-8P-1dy" eventType="valueChanged" id="BKh-dh-f3d"/>
</connections>
</stepper>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7nN-Bo-Jgm">
<rect key="frame" x="20" y="11.5" width="42" height="21"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="x72-wj-jT3"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" translatesAutoresizingMaskIntoConstraints="NO" id="nTa-ey-RFM">
<rect key="frame" x="20" y="8" width="374" height="52"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="clip" baselineAdjustment="alignBaselines" minimumScaleFactor="0.25" translatesAutoresizingMaskIntoConstraints="NO" id="Sap-Qr-1ZU">
<rect key="frame" x="0.0" y="0.0" width="374" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="rJq-eZ-wvm">
<rect key="frame" x="0.0" y="21" width="374" height="32"/>
<segments>
<segment title="First"/>
<segment title="Second"/>
</segments>
<connections>
<action selector="selectedSegmentChanged:" destination="iSG-Tv-aCX" eventType="valueChanged" id="k8p-F7-ILf"/>
</connections>
</segmentedControl>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstItem="vgc-Rg-Zc8" firstAttribute="centerY" secondItem="Dwe-Tg-VQ6" secondAttribute="centerY" id="6as-ZA-8B4"/>
<constraint firstAttribute="trailingMargin" secondItem="vgc-Rg-Zc8" secondAttribute="trailing" id="GHC-1H-v20"/>
<constraint firstItem="7nN-Bo-Jgm" firstAttribute="centerY" secondItem="Dwe-Tg-VQ6" secondAttribute="centerY" id="Rcx-L4-hEN"/>
<constraint firstItem="7nN-Bo-Jgm" firstAttribute="leading" secondItem="Dwe-Tg-VQ6" secondAttribute="leadingMargin" id="SQY-8s-eLf"/>
<constraint firstItem="RCc-cF-BI3" firstAttribute="leading" secondItem="7nN-Bo-Jgm" secondAttribute="trailing" constant="20" id="So8-Uf-Zfa"/>
<constraint firstItem="vgc-Rg-Zc8" firstAttribute="leading" secondItem="RCc-cF-BI3" secondAttribute="trailing" constant="20" id="T1Y-Pj-gsO"/>
<constraint firstItem="RCc-cF-BI3" firstAttribute="centerY" secondItem="Dwe-Tg-VQ6" secondAttribute="centerY" id="ett-1I-J0L"/>
<constraint firstItem="nTa-ey-RFM" firstAttribute="top" secondItem="scU-nK-qiI" secondAttribute="top" constant="8" id="VT0-G5-ofZ"/>
<constraint firstAttribute="bottom" secondItem="nTa-ey-RFM" secondAttribute="bottom" constant="8" id="XR5-nT-N05"/>
<constraint firstItem="nTa-ey-RFM" firstAttribute="leading" secondItem="scU-nK-qiI" secondAttribute="leading" constant="20" id="oB6-ry-kjt"/>
<constraint firstAttribute="trailing" secondItem="nTa-ey-RFM" secondAttribute="trailing" constant="20" id="p7Q-Bn-sSi"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="labelView" destination="Sap-Qr-1ZU" id="qJ3-Wb-qrb"/>
<outlet property="segmentedControl" destination="rJq-eZ-wvm" id="gKh-IH-iQO"/>
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="MCIntegerField" id="KwC-8P-1dy" userLabel="MCIntegerField" customClass="MCIntegerFieldTableViewCell">
<rect key="frame" x="0.0" y="96" width="414" height="71.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="KwC-8P-1dy" id="Dwe-Tg-VQ6">
<rect key="frame" x="0.0" y="0.0" width="414" height="71.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="tqg-e0-rNO">
<rect key="frame" x="20" y="8" width="374" height="55.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="clip" baselineAdjustment="alignBaselines" minimumScaleFactor="0.25" translatesAutoresizingMaskIntoConstraints="NO" id="7nN-Bo-Jgm">
<rect key="frame" x="0.0" y="0.0" width="374" height="21"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="x72-wj-jT3"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5Hz-MY-MYZ">
<rect key="frame" x="0.0" y="21" width="374" height="34.5"/>
<subviews>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="10" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="RCc-cF-BI3" userLabel="Text Field">
<rect key="frame" x="0.0" y="0.0" width="280" height="34.5"/>
<constraints>
<constraint firstAttribute="height" constant="34" id="8Nj-FL-Ab6"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
<connections>
<action selector="textFieldValueChanged:" destination="KwC-8P-1dy" eventType="valueChanged" id="5In-Xx-LJB"/>
</connections>
</textField>
<stepper opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" maximumValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="vgc-Rg-Zc8">
<rect key="frame" x="280" y="0.0" width="94" height="34.5"/>
<constraints>
<constraint firstAttribute="height" constant="34" id="HhX-Qt-vVP"/>
</constraints>
<connections>
<action selector="stepperValueChanged:" destination="KwC-8P-1dy" eventType="valueChanged" id="BKh-dh-f3d"/>
</connections>
</stepper>
</subviews>
</stackView>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="tqg-e0-rNO" secondAttribute="trailing" constant="20" id="9U8-8r-ZOV"/>
<constraint firstItem="tqg-e0-rNO" firstAttribute="top" secondItem="Dwe-Tg-VQ6" secondAttribute="top" constant="8" id="Ctm-x1-7Uf"/>
<constraint firstAttribute="bottom" secondItem="tqg-e0-rNO" secondAttribute="bottom" constant="8" id="gHo-d9-oh1"/>
<constraint firstItem="tqg-e0-rNO" firstAttribute="leading" secondItem="Dwe-Tg-VQ6" secondAttribute="leading" constant="20" id="pSJ-yP-eoc"/>
</constraints>
</tableViewCellContentView>
<connections>
@@ -463,7 +510,7 @@
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="MCShortStringField" id="s66-ds-RzY" userLabel="MCShortStringField" customClass="MCShortStringFieldTableViewCell">
<rect key="frame" x="0.0" y="71.5" width="414" height="43.5"/>
<rect key="frame" x="0.0" y="167.5" width="414" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="s66-ds-RzY" id="hip-Sr-WMn">
<rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
@@ -493,14 +540,14 @@
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="MCBooleanField" id="aNO-fN-IMT" userLabel="MCBooleanField" customClass="MCBooleanFieldTableViewCell">
<rect key="frame" x="0.0" y="115" width="414" height="43.5"/>
<rect key="frame" x="0.0" y="211" width="414" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="aNO-fN-IMT" id="S88-r0-N1u">
<rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tsg-zB-HOv">
<rect key="frame" x="20" y="11.5" width="305" height="21"/>
<rect key="frame" x="20" y="11.5" width="305" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@@ -529,14 +576,14 @@
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="MCSelectField" id="PQF-mC-UlI" userLabel="MCSelectField" customClass="MCSelectFieldTableViewCell">
<rect key="frame" x="0.0" y="158.5" width="414" height="37.5"/>
<rect key="frame" x="0.0" y="254.5" width="414" height="37.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="PQF-mC-UlI" id="Wcu-Sa-z2O">
<rect key="frame" x="0.0" y="0.0" width="414" height="37.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lik-sI-94j" userLabel="Label View">
<rect key="frame" x="20" y="8" width="42" height="21.5"/>
<rect key="frame" x="20" y="8" width="41.5" height="21.5"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="A1K-Wk-Nuf"/>
</constraints>
@@ -545,7 +592,7 @@
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="DFa-Hd-laX" userLabel="Text Field">
<rect key="frame" x="82" y="2" width="312" height="34"/>
<rect key="frame" x="81.5" y="2" width="312.5" height="34"/>
<constraints>
<constraint firstAttribute="height" constant="34" id="zHt-9x-mSt"/>
</constraints>

View File

@@ -56,6 +56,14 @@ extern NSString* const kArmorNameSplintMail;
extern NSString* const kArmorNamePlateMail;
extern NSString* const kArmorNameOther;
extern NSString *const kProficiencyTypeNone;
extern NSString *const kProficiencyTypeProficient;
extern NSString *const kProficiencyTypeExpertise;
extern NSString *const kAdvantageTypeNone;
extern NSString *const kAdvantageTypeAdvantage;
extern NSString *const kAdvantageTypeDisadvantage;
@class Skill;
@interface Monster : NSManagedObject

View File

@@ -63,6 +63,14 @@ NSString* const kMonsterSizeLarge = @"large";
NSString* const kMonsterSizeHuge = @"huge";
NSString* const kMonsterSizeGargantuan = @"gargantuan";
NSString *const kProficiencyTypeNone = @"none";
NSString *const kProficiencyTypeProficient = @"proficient";
NSString *const kProficiencyTypeExpertise = @"expertise";
NSString *const kAdvantageTypeNone = @"none";
NSString *const kAdvantageTypeAdvantage = @"advantage";
NSString *const kAdvantageTypeDisadvantage = @"disadvantage";
+(int)abilityModifierForScore: (int)score {
return (int)floor((score - 10) / 2.0);
}
@@ -509,6 +517,18 @@ NSString* const kMonsterSizeGargantuan = @"gargantuan";
self.naturalArmorBonus = monster.naturalArmorBonus;
self.hasShield = monster.hasShield;
self.customArmor = monster.customArmor;
self.strengthSavingThrowAdvantage = monster.strengthSavingThrowAdvantage;
self.strengthSavingThrowProficiency = monster.strengthSavingThrowProficiency;
self.dexteritySavingThrowAdvantage = monster.dexteritySavingThrowAdvantage;
self.dexteritySavingThrowProficiency = monster.dexteritySavingThrowProficiency;
self.constitutionSavingThrowAdvantage = monster.constitutionSavingThrowAdvantage;
self.constitutionSavingThrowProficiency = monster.constitutionSavingThrowProficiency;
self.intelligenceSavingThrowAdvantage = monster.intelligenceSavingThrowAdvantage;
self.intelligenceSavingThrowProficiency = monster.intelligenceSavingThrowProficiency;
self.wisdomSavingThrowAdvantage = monster.wisdomSavingThrowAdvantage;
self.wisdomSavingThrowProficiency = monster.wisdomSavingThrowProficiency;
self.charismaSavingThrowAdvantage = monster.charismaSavingThrowAdvantage;
self.charismaSavingThrowProficiency = monster.charismaSavingThrowProficiency;
}
@end

View File

@@ -6,31 +6,43 @@
<attribute name="baseSpeed" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="burrowSpeed" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="canHover" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="charismaSavingThrowAdvantage" attributeType="String" defaultValueString="none"/>
<attribute name="charismaSavingThrowProficiency" attributeType="String" defaultValueString="none"/>
<attribute name="charismaScore" attributeType="Integer 16" defaultValueString="10" usesScalarValueType="YES"/>
<attribute name="climbSpeed" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="constitutionSavingThrowAdvantage" attributeType="String" defaultValueString="none"/>
<attribute name="constitutionSavingThrowProficiency" attributeType="String" defaultValueString="none"/>
<attribute name="constitutionScore" attributeType="Integer 16" defaultValueString="10" usesScalarValueType="YES"/>
<attribute name="customArmor" attributeType="String" defaultValueString=""/>
<attribute name="customHP" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="customSpeed" attributeType="String" defaultValueString=""/>
<attribute name="dexteritySavingThrowAdvantage" attributeType="String" defaultValueString="none"/>
<attribute name="dexteritySavingThrowProficiency" attributeType="String" defaultValueString="none" customClassName="none"/>
<attribute name="dexterityScore" attributeType="Integer 16" defaultValueString="10" usesScalarValueType="YES"/>
<attribute name="flySpeed" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="hasCustomSpeed" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="hasShield" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="hitDice" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="hpText" attributeType="String" defaultValueString=""/>
<attribute name="intelligenceSavingThrowAdvantage" attributeType="String" defaultValueString="none"/>
<attribute name="intelligenceSavingThrowProficiency" attributeType="String" defaultValueString="none"/>
<attribute name="intelligenceScore" attributeType="Integer 16" defaultValueString="10" usesScalarValueType="YES"/>
<attribute name="name" attributeType="String" defaultValueString=""/>
<attribute name="natrualArmorBonus" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="otherArmorDescription" attributeType="String" defaultValueString=""/>
<attribute name="shieldBonus" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="size" attributeType="String" defaultValueString=""/>
<attribute name="strengthSavingThrowAdvantage" attributeType="String" defaultValueString="none"/>
<attribute name="strengthSavingThrowProficiency" attributeType="String" defaultValueString="none"/>
<attribute name="strengthScore" attributeType="Integer 16" defaultValueString="10" usesScalarValueType="YES"/>
<attribute name="subtype" attributeType="String" defaultValueString=""/>
<attribute name="swimSpeed" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="type" attributeType="String" defaultValueString=""/>
<attribute name="wisdomSavingThrowAdvantage" attributeType="String" defaultValueString="none"/>
<attribute name="wisdomSavingThrowProficiency" attributeType="String" defaultValueString="none"/>
<attribute name="wisdomScore" attributeType="Integer 16" defaultValueString="10" usesScalarValueType="YES"/>
</entity>
<elements>
<element name="Monster" positionX="-63" positionY="-18" width="128" height="463"/>
<element name="Monster" positionX="-63" positionY="-18" width="128" height="643"/>
</elements>
</model>

View File

@@ -9,6 +9,7 @@
#import "EditMonsterViewController.h"
#import "MCBooleanFieldTableViewCell.h"
#import "MCIntegerFieldTableViewCell.h"
#import "MCRadioFieldTableViewCell.h"
#import "MCSelectFieldTableViewCell.h"
#import "MCShortStringFieldTableViewCell.h"
#import "AppDelegate.h"
@@ -23,6 +24,7 @@ const int kSectionIndexBasicInfo = 0;
const int kSectionIndexArmor = 1;
const int kSectionIndexSpeed = 2;
const int kSectionIndexAbilityScores = 3;
const int kSectionIndexSavingThrows = 4;
const int kBasicInfoSectionRowIndexName = 0;
const int kBasicInfoSectionRowIndexSize = 1;
@@ -54,9 +56,63 @@ const int kAbilityScoreSectionRowIndexIntelligence = 3;
const int kAbilityScoreSectionRowIndexWisdom = 4;
const int kAbilityScoreSectionRowIndexCharisma = 5;
const int kSavingThrowsSectionRowIndexStrengthProficiency = 0;
const int kSavingThrowsSectionRowIndexStrengthAdvantage = 1;
const int kSavingThrowsSectionRowIndexDexterityProficiency = 2;
const int kSavingThrowsSectionRowIndexDexterityAdvantage = 3;
const int kSavingThrowsSectionRowIndexConstitutionProficiency = 4;
const int kSavingThrowsSectionRowIndexConstitutionAdvantage = 5;
const int kSavingThrowsSectionRowIndexIntelligenceProficiency = 6;
const int kSavingThrowsSectionRowIndexIntelligenceAdvantage = 7;
const int kSavingThrowsSectionRowIndexWisdomProficiency = 8;
const int kSavingThrowsSectionRowIndexWisdomAdvantage = 9;
const int kSavingThrowsSectionRowIndexCharismaProficiency = 10;
const int kSavingThrowsSectionRowIndexCharismaAdvantage = 11;
NSString *const kIdentifierName = @"monster.name";
NSString *const kIdentifierSize = @"monster.size";
NSString *const kIdentifierType = @"monster.type";
NSString *const kIdentifierSubtype = @"monster.subtype";
NSString *const kIdentifierAlignment = @"monster.alignment";
NSString *const kIdentifierCustomHP = @"monster.customHPText";
NSString *const kIdentifierCustomSpeed = @"monster.customSpeed";
NSString *const kIdentifierCustomArmor = @"monster.customArmor";
NSString *const kIdentifierStrengthScore = @"monster.strengthScore";
NSString *const kIdentiferDexterityScore = @"monster.dexterityScore";
NSString *const kIdentifierConstitutionScore = @"monster.constitutionScore";
NSString *const kIdentifierIntelligenceScore = @"monster.intelligenceScore";
NSString *const kIdentifierWisdomScore = @"monster.wisdomScore";
NSString *const kIdentifierCharismaScore = @"monster.charismaScore";
NSString *const kIdentifierHitDice = @"monster.hitDice";
NSString *const kIdentifierBaseSpeed = @"monster.baseSpeed";
NSString *const kIdentifierBurrowSpeed = @"monster.burrowSpeed";
NSString *const kIdentifierClimbSpeed = @"monster.climbSpeed";
NSString *const kIdentifierFlySpeed = @"monster.flySpeed";
NSString *const kIdentifierSwimSpeed = @"monster.swimSpeed";
NSString *const kIdentifierNaturalArmorBonus = @"monster.naturalArmorBonus";
NSString *const kIdentifierHasCustomHP = @"monster.customHP";
NSString *const kIdentifierCanHover = @"monster.canHover";
NSString *const kIdentifierHasCustomSpeed = @"monster.hasCustomSpeed";
NSString *const kIdentifierHasShield = @"monster.hasShield";
NSString *const kIdentifierArmorType = @"monster.armorType";
NSString *const kIdentifierStrengthSavingThrowAdvantage = @"monster.savingThrows.strength.advantage";
NSString *const kIdentifierStrengthSavingThrowProficiency = @"monster.savingThrows.strength.proficiency";
NSString *const kIdentifierDexteritySavingThrowAdvantage = @"monster.savingThrows.dexterity.advantage";
NSString *const kIdentifierDexteritySavingThrowProficiency = @"monster.savingThrows.dexterity.proficiency";
NSString *const kIdentifierConstitutionSavingThrowAdvantage = @"monster.savingThrows.constitution.advantage";
NSString *const kIdentifierConstitutionSavingThrowProficiency = @"monster.savingThrows.constitution.proficiency";
NSString *const kIdentifierIntelligenceSavingThrowAdvantage = @"monster.savingThrows.intelligence.advantage";
NSString *const kIdentifierIntelligenceSavingThrowProficiency = @"monster.savingThrows.intelligence.proficiency";
NSString *const kIdentifierWisdomSavingThrowAdvantage = @"monster.savingThrows.wisdom.advantage";
NSString *const kIdentifierWisdomSavingThrowProficiency = @"monster.savingThrows.wisdom.proficiency";
NSString *const kIdentifierCharismaSavingThrowAdvantage = @"monster.savingThrows.charisma.advantage";
NSString *const kIdentifierCharismaSavingThrowProficiency = @"monster.savingThrows.charisma.proficiency";
@implementation EditMonsterViewController {
NSManagedObjectContext *_context;
NSArray<MCChoice*>* _armorTypes;
NSArray<MCChoice*>* _proficiencyTypes;
NSArray<MCChoice*>* _advantageTypes;
}
- (void)viewDidLoad {
@@ -98,6 +154,22 @@ const int kAbilityScoreSectionRowIndexCharisma = 5;
[MCChoice choiceWithLabel:NSLocalizedString(@"Other", @"")
andValue:kArmorNameOther],
nil];
_proficiencyTypes = [NSArray arrayWithObjects:
[MCChoice choiceWithLabel:NSLocalizedString(@"None", @"")
andValue:kProficiencyTypeNone],
[MCChoice choiceWithLabel:NSLocalizedString(@"Proficient", @"")
andValue:kProficiencyTypeProficient],
[MCChoice choiceWithLabel:NSLocalizedString(@"Expertise", @"")
andValue:kProficiencyTypeExpertise],
nil];
_advantageTypes = [NSArray arrayWithObjects:
[MCChoice choiceWithLabel:NSLocalizedString(@"None", @"")
andValue:kAdvantageTypeNone],
[MCChoice choiceWithLabel:NSLocalizedString(@"Advantage", @"")
andValue:kAdvantageTypeAdvantage],
[MCChoice choiceWithLabel:NSLocalizedString(@"Disadvantage", @"")
andValue:kAdvantageTypeDisadvantage],
nil];
self.monsterTableView.allowsSelection = NO;
self.monsterTableView.allowsSelectionDuringEditing = NO;
@@ -188,6 +260,24 @@ const int kAbilityScoreSectionRowIndexCharisma = 5;
return cell;
}
- (MCRadioFieldTableViewCell*) makeRadioCellFromTableView:(UITableView*)tableView
withIdentifier:(NSString*)identifier
label:(NSString*)label
initialValue:(NSObject*)initialValue
andChoices:(NSArray*)choices {
MCRadioFieldTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MCRadioField"];
if (!cell || ![cell isKindOfClass:[MCRadioFieldTableViewCell class]]) {
return nil;
}
cell.delegate = self;
cell.identifier = identifier;
cell.label = label;
// TODO: possibly swap these two
cell.selectedValue = initialValue;
cell.choices = choices;
return cell;
}
#pragma mark - Navigation
@@ -222,6 +312,8 @@ const int kAbilityScoreSectionRowIndexCharisma = 5;
return 8;
case kSectionIndexAbilityScores:
return 6;
case kSectionIndexSavingThrows:
return 12; // 12
default:
return 0;
}
@@ -229,7 +321,7 @@ const int kAbilityScoreSectionRowIndexCharisma = 5;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 3;
return 5;
}
- (NSString *)tableView:(UITableView *)tableView
@@ -243,6 +335,8 @@ titleForHeaderInSection:(NSInteger)section {
return NSLocalizedString(@"Speed", @"Section title");
case kSectionIndexAbilityScores:
return NSLocalizedString(@"Ability Scores", @"Section title");
case kSectionIndexSavingThrows:
return NSLocalizedString(@"Saving Throws", @"Section title");
default:
return nil;
}
@@ -257,49 +351,49 @@ titleForHeaderInSection:(NSInteger)section {
switch (indexPath.row) {
case kBasicInfoSectionRowIndexName:
newCell = [self makeShortStringCellFromTableView:self.monsterTableView
withIdentifier:@"monster.name"
withIdentifier:kIdentifierName
label:NSLocalizedString(@"Name", @"Placeholder text for the name of a monster or NPC.")
andInitialValue:self.editingMonster.name];
break;
case kBasicInfoSectionRowIndexSize:
newCell = [self makeShortStringCellFromTableView:self.monsterTableView
withIdentifier:@"monster.size"
withIdentifier:kIdentifierSize
label:NSLocalizedString(@"Size", @"Placehodler text for the size of a monster or NPC.")
andInitialValue:self.editingMonster.size];
break;
case kBasicInfoSectionRowIndexType:
newCell = [self makeShortStringCellFromTableView:self.monsterTableView
withIdentifier:@"monster.type"
withIdentifier:kIdentifierType
label:NSLocalizedString(@"Type", @"Placehodler text for the type of a monster or NPC.")
andInitialValue:self.editingMonster.type];
break;
case kBasicInfoSectionRowIndexSubtype:
newCell = [self makeShortStringCellFromTableView:self.monsterTableView
withIdentifier:@"monster.subtype"
withIdentifier:kIdentifierSubtype
label:NSLocalizedString(@"Subtype", @"Placeholder text for the subtype of a monster or NPC.")
andInitialValue:self.editingMonster.subtype];
break;
case kBasicInfoSectionRowIndexAlignment:
newCell = [self makeShortStringCellFromTableView:self.monsterTableView
withIdentifier:@"monster.alignment"
withIdentifier:kIdentifierAlignment
label: NSLocalizedString(@"Alignment", @"Placeholder text for the alignment of a monster or NPC.")
andInitialValue:self.editingMonster.alignment];
break;
case kBasicInfoSectionRowIndexHitDice:
newCell = [self makeIntegerCellFromTableView:self.monsterTableView
withIdentifier:@"monster.hitDice"
withIdentifier:kIdentifierHitDice
label:NSLocalizedString(@"Hit Dice", @"")
andInitialValue:self.editingMonster.hitDice];
break;
case kBasicInfoSectionRowIndexCustomHP:
newCell = [self makeBooleanCellFromTableView:self.monsterTableView
withIdentifier:@"monster.customHP"
withIdentifier:kIdentifierHasCustomHP
label:NSLocalizedString(@"Custom HP", @"")
andInitialValue:self.editingMonster.customHP];
break;
case kBasicInfoSectionRowIndexCustomHPText:
newCell = [self makeShortStringCellFromTableView:self.monsterTableView
withIdentifier:@"monster.customHPText"
withIdentifier:kIdentifierCustomHP
label:NSLocalizedString(@"Custom HP Text", @"")
andInitialValue:self.editingMonster.hpText];
break;
@@ -309,26 +403,26 @@ titleForHeaderInSection:(NSInteger)section {
switch (indexPath.row) {
case kArmorSectionRowIndexArmorType:
newCell = [self makeSelectCellFromTableView:self.monsterTableView
withIdentifier:@"monster.armorType"
withIdentifier:kIdentifierArmorType
label:NSLocalizedString(@"Type", @"")
initialValue:self.editingMonster.armorType
andChoices:_armorTypes];
break;
case kArmorSectionRowIndexHasShield:
newCell = [self makeBooleanCellFromTableView:self.monsterTableView
withIdentifier:@"monster.hasShield"
withIdentifier:kIdentifierHasShield
label:NSLocalizedString(@"Shield", @"")
andInitialValue:self.editingMonster.hasShield];
break;
case kArmorSectionRowIndexCustomArmor:
newCell = [self makeShortStringCellFromTableView:self.monsterTableView
withIdentifier:@"monster.customArmor"
withIdentifier:kIdentifierCustomArmor
label:NSLocalizedString(@"Custom Armor", @"")
andInitialValue:self.editingMonster.customArmor];
break;
case kArmorSectionRowIndexNaturalArmorBonus:
newCell = [self makeIntegerCellFromTableView:self.monsterTableView
withIdentifier:@"monster.naturalArmorBonus"
withIdentifier:kIdentifierNaturalArmorBonus
label:NSLocalizedString(@"Natural Armor Bonus", @"")
andInitialValue:self.editingMonster.naturalArmorBonus];
break;
@@ -338,49 +432,49 @@ titleForHeaderInSection:(NSInteger)section {
switch (indexPath.row) {
case kSpeedSectionRowIndexBaseSpeed:
newCell = [self makeIntegerCellFromTableView:self.monsterTableView
withIdentifier:@"monster.baseSpeed"
withIdentifier:kIdentifierBaseSpeed
label:NSLocalizedString(@"Base", @"")
andInitialValue:self.editingMonster.baseSpeed];
break;
case kSpeedSectionRowIndexBurrowSpeed:
newCell = [self makeIntegerCellFromTableView:self.monsterTableView
withIdentifier:@"monster.burrowSpeed"
withIdentifier:kIdentifierBurrowSpeed
label:NSLocalizedString(@"Burrow", @"")
andInitialValue:self.editingMonster.burrowSpeed];
break;
case kSpeedSectionRowIndexClimbSpeed:
newCell = [self makeIntegerCellFromTableView:self.monsterTableView
withIdentifier:@"monster.climbSpeed"
withIdentifier:kIdentifierClimbSpeed
label:NSLocalizedString(@"Climb", @"")
andInitialValue:self.editingMonster.climbSpeed];
break;
case kSpeedSectionRowIndexFlySpeed:
newCell = [self makeIntegerCellFromTableView:self.monsterTableView
withIdentifier:@"monster.flySpeed"
withIdentifier:kIdentifierFlySpeed
label:NSLocalizedString(@"Fly", @"")
andInitialValue:self.editingMonster.flySpeed];
break;
case kSpeedSectionRowIndexCanHover:
newCell = [self makeBooleanCellFromTableView:self.monsterTableView
withIdentifier:@"monster.canHover"
withIdentifier:kIdentifierCanHover
label:NSLocalizedString(@"Hover", @"")
andInitialValue:self.editingMonster.canHover];
break;
case kSpeedSectionRowIndexSwimSpeed:
newCell = [self makeIntegerCellFromTableView:self.monsterTableView
withIdentifier:@"monster.swimSpeed"
withIdentifier:kIdentifierSwimSpeed
label:NSLocalizedString(@"Swim", @"")
andInitialValue:self.editingMonster.swimSpeed];
break;
case kSpeedSectionRowIndexHasCustomSpeed:
newCell = [self makeBooleanCellFromTableView:self.monsterTableView
withIdentifier:@"monster.hasCustomSpeed"
withIdentifier:kIdentifierHasCustomSpeed
label:NSLocalizedString(@"Custom Speed", @"")
andInitialValue:self.editingMonster.hasCustomSpeed];
break;
case kSpeedSectionRowIndexCustomSpeed:
newCell = [self makeShortStringCellFromTableView:self.monsterTableView
withIdentifier:@"monster.customSpeed"
withIdentifier:kIdentifierCustomSpeed
label:NSLocalizedString(@"Custom Speed", @"")
andInitialValue:self.editingMonster.customSpeed];
break;
@@ -390,43 +484,131 @@ titleForHeaderInSection:(NSInteger)section {
switch (indexPath.row) {
case kAbilityScoreSectionRowIndexStrength:
newCell = [self makeIntegerCellFromTableView:self.monsterTableView
withIdentifier:@"monster.strengthScore"
withIdentifier:kIdentifierStrengthScore
label:NSLocalizedString(@"STR", @"Placeholder abbreviation for the strength score of a monster or NPC.")
andInitialValue:self.editingMonster.strengthScore];
break;
case kAbilityScoreSectionRowIndexDexterity:
newCell = [self makeIntegerCellFromTableView:self.monsterTableView
withIdentifier:@"monster.dexterityScore"
withIdentifier:kIdentiferDexterityScore
label:NSLocalizedString(@"DEX", @"Placeholder abbreviation for the dexterity score of a monster or NPC.")
andInitialValue:self.editingMonster.dexterityScore];
break;
case kAbilityScoreSectionRowIndexConstitution:
newCell = [self makeIntegerCellFromTableView:self.monsterTableView
withIdentifier:@"monster.constitutionScore"
withIdentifier:kIdentifierConstitutionScore
label:NSLocalizedString(@"CON", @"Placeholder abbreviation for the constitution score of a monster or NPC.")
andInitialValue:self.editingMonster.constitutionScore];
break;
case kAbilityScoreSectionRowIndexIntelligence:
newCell = [self makeIntegerCellFromTableView:self.monsterTableView
withIdentifier:@"monster.intelligenceScore"
withIdentifier:kIdentifierIntelligenceScore
label:NSLocalizedString(@"INT", @"Placeholder abbreviation for the intelligence score of a monster or NPC.")
andInitialValue:self.editingMonster.intelligenceScore];
break;
case kAbilityScoreSectionRowIndexWisdom:
newCell = [self makeIntegerCellFromTableView:self.monsterTableView
withIdentifier:@"monster.wisdomScore"
withIdentifier:kIdentifierWisdomScore
label:NSLocalizedString(@"WIS", @"Placeholder abbreviation for the wisdom score of a monster or NPC.")
andInitialValue:self.editingMonster.wisdomScore];
break;
case kAbilityScoreSectionRowIndexCharisma:
newCell = [self makeIntegerCellFromTableView:self.monsterTableView
withIdentifier:@"monster.charismaScore"
withIdentifier:kIdentifierCharismaScore
label:NSLocalizedString(@"CHA", @"Placeholder abbreviation for the charisma score of a monster or NPC.")
andInitialValue:self.editingMonster.charismaScore];
break;
}
break;
case kSectionIndexSavingThrows:
switch (indexPath.row) {
case kSavingThrowsSectionRowIndexStrengthProficiency:
newCell = [self makeRadioCellFromTableView:self.monsterTableView
withIdentifier:kIdentifierStrengthSavingThrowProficiency
label:NSLocalizedString(@"Strength Proficiency", @"")
initialValue:self.editingMonster.strengthSavingThrowProficiency
andChoices:_proficiencyTypes];
break;
case kSavingThrowsSectionRowIndexStrengthAdvantage:
newCell = [self makeRadioCellFromTableView:self.monsterTableView
withIdentifier:kIdentifierStrengthSavingThrowAdvantage
label:NSLocalizedString(@"Strength Advantage", @"")
initialValue:self.editingMonster.strengthSavingThrowAdvantage
andChoices:_advantageTypes];
break;
case kSavingThrowsSectionRowIndexDexterityProficiency:
newCell = [self makeRadioCellFromTableView:self.monsterTableView
withIdentifier:kIdentifierDexteritySavingThrowProficiency
label:NSLocalizedString(@"Dexterity Proficiency", @"")
initialValue:self.editingMonster.dexteritySavingThrowProficiency
andChoices:_proficiencyTypes];
break;
case kSavingThrowsSectionRowIndexDexterityAdvantage:
newCell = [self makeRadioCellFromTableView:self.monsterTableView
withIdentifier:kIdentifierDexteritySavingThrowAdvantage
label:NSLocalizedString(@"Dexterity Advantage", @"")
initialValue:self.editingMonster.dexteritySavingThrowAdvantage
andChoices:_advantageTypes];
break;
case kSavingThrowsSectionRowIndexConstitutionProficiency:
newCell = [self makeRadioCellFromTableView:self.monsterTableView
withIdentifier:kIdentifierConstitutionSavingThrowProficiency
label:NSLocalizedString(@"Constitution Proficiency", @"")
initialValue:self.editingMonster.constitutionSavingThrowProficiency
andChoices:_proficiencyTypes];
break;
case kSavingThrowsSectionRowIndexConstitutionAdvantage:
newCell = [self makeRadioCellFromTableView:self.monsterTableView
withIdentifier:kIdentifierConstitutionSavingThrowAdvantage
label:NSLocalizedString(@"Constitution Advantage", @"")
initialValue:self.editingMonster.constitutionSavingThrowAdvantage
andChoices:_advantageTypes];
break;
case kSavingThrowsSectionRowIndexIntelligenceProficiency:
newCell = [self makeRadioCellFromTableView:self.monsterTableView
withIdentifier:kIdentifierIntelligenceSavingThrowProficiency
label:NSLocalizedString(@"Intelligence Proficiency", @"")
initialValue:self.editingMonster.intelligenceSavingThrowProficiency
andChoices:_proficiencyTypes];
break;
case kSavingThrowsSectionRowIndexIntelligenceAdvantage:
newCell = [self makeRadioCellFromTableView:self.monsterTableView
withIdentifier:kIdentifierIntelligenceSavingThrowAdvantage
label:NSLocalizedString(@"Intelligence Advantage", @"")
initialValue:self.editingMonster.intelligenceSavingThrowAdvantage
andChoices:_advantageTypes];
break;
case kSavingThrowsSectionRowIndexWisdomProficiency:
newCell = [self makeRadioCellFromTableView:self.monsterTableView
withIdentifier:kIdentifierWisdomSavingThrowProficiency
label:NSLocalizedString(@"Wisdom Proficiency", @"")
initialValue:self.editingMonster.wisdomSavingThrowProficiency
andChoices:_proficiencyTypes];
break;
case kSavingThrowsSectionRowIndexWisdomAdvantage:
newCell = [self makeRadioCellFromTableView:self.monsterTableView
withIdentifier:kIdentifierWisdomSavingThrowAdvantage
label:NSLocalizedString(@"Wisdom Advantage", @"")
initialValue:self.editingMonster.wisdomSavingThrowAdvantage
andChoices:_advantageTypes];
break;
case kSavingThrowsSectionRowIndexCharismaProficiency:
newCell = [self makeRadioCellFromTableView:self.monsterTableView
withIdentifier:kIdentifierCharismaSavingThrowProficiency
label:NSLocalizedString(@"Charisma Proficiency", @"")
initialValue:self.editingMonster.charismaSavingThrowProficiency
andChoices:_proficiencyTypes];
break;
case kSavingThrowsSectionRowIndexCharismaAdvantage:
newCell = [self makeRadioCellFromTableView:self.monsterTableView
withIdentifier:kIdentifierCharismaSavingThrowAdvantage
label:NSLocalizedString(@"Charisma Advantage", @"")
initialValue:self.editingMonster.charismaSavingThrowAdvantage
andChoices:_advantageTypes];
break;
}
break;
}
if (!newCell) {
@@ -441,69 +623,97 @@ titleForHeaderInSection:(NSInteger)section {
- (void)editableValueDidChange:(NSObject*)value forIdentifier:(NSString*)identifier andType:(NSString*)type {
if ([kMCFieldValueTypeString isEqualToString:type]) {
if ([@"monster.name" isEqualToString:identifier]) {
if ([kIdentifierName isEqualToString:identifier]) {
self.editingMonster.name = (NSString*)value;
} else if ([@"monster.size" isEqualToString:identifier]) {
} else if ([kIdentifierSize isEqualToString:identifier]) {
self.editingMonster.size = (NSString*)value;
} else if ([@"monster.type" isEqualToString:identifier]) {
} else if ([kIdentifierType isEqualToString:identifier]) {
self.editingMonster.type = (NSString*)value;
} else if ([@"monster.subtype" isEqualToString:identifier]) {
} else if ([kIdentifierSubtype isEqualToString:identifier]) {
self.editingMonster.subtype = (NSString*)value;
} else if ([@"monster.alignment" isEqualToString:identifier]) {
} else if ([kIdentifierAlignment isEqualToString:identifier]) {
self.editingMonster.alignment = (NSString*)value;
} else if ([@"monster.customHPText" isEqualToString:identifier]) {
} else if ([kIdentifierCustomHP isEqualToString:identifier]) {
self.editingMonster.hpText = (NSString*)value;
} else if ([@"monster.customSpeed" isEqualToString:identifier]) {
} else if ([kIdentifierCustomSpeed isEqualToString:identifier]) {
self.editingMonster.customSpeed = (NSString*)value;
} else if ([@"monster.customArmor" isEqualToString:identifier]) {
} else if ([kIdentifierCustomArmor isEqualToString:identifier]) {
self.editingMonster.customArmor = (NSString*)value;
}
}
if ([kMCFieldValueTypeInteger isEqualToString:type]) {
if ([@"monster.strengthScore" isEqualToString:identifier]) {
if ([kIdentifierStrengthScore isEqualToString:identifier]) {
self.editingMonster.strengthScore = [(NSNumber*)value intValue];
} else if ([@"monster.dexterityScore" isEqualToString:identifier]) {
} else if ([kIdentiferDexterityScore isEqualToString:identifier]) {
self.editingMonster.dexterityScore = [(NSNumber*)value intValue];
} else if ([@"monster.constitutionScore" isEqualToString:identifier]) {
} else if ([kIdentifierConstitutionScore isEqualToString:identifier]) {
self.editingMonster.constitutionScore = [(NSNumber*)value intValue];
} else if ([@"monster.intelligenceScore" isEqualToString:identifier]) {
} else if ([kIdentifierIntelligenceScore isEqualToString:identifier]) {
self.editingMonster.intelligenceScore = [(NSNumber*)value intValue];
} else if ([@"monster.wisdomScore" isEqualToString:identifier]) {
} else if ([kIdentifierWisdomScore isEqualToString:identifier]) {
self.editingMonster.wisdomScore = [(NSNumber*)value intValue];
} else if ([@"monster.charismaScore" isEqualToString:identifier]) {
} else if ([kIdentifierCharismaScore isEqualToString:identifier]) {
self.editingMonster.charismaScore = [(NSNumber*)value intValue];
} else if ([@"monster.hitDice" isEqualToString:identifier]) {
} else if ([kIdentifierHitDice isEqualToString:identifier]) {
self.editingMonster.hitDice = [(NSNumber*)value intValue];
} else if ([@"monster.baseSpeed" isEqualToString:identifier]) {
} else if ([kIdentifierBaseSpeed isEqualToString:identifier]) {
self.editingMonster.baseSpeed = [(NSNumber*)value intValue];
} else if ([@"monster.burrowSpeed" isEqualToString:identifier]) {
} else if ([kIdentifierBurrowSpeed isEqualToString:identifier]) {
self.editingMonster.burrowSpeed = [(NSNumber*)value intValue];
} else if ([@"monster.climbSpeed" isEqualToString:identifier]) {
} else if ([kIdentifierClimbSpeed isEqualToString:identifier]) {
self.editingMonster.climbSpeed = [(NSNumber*)value intValue];
} else if ([@"monster.flySpeed" isEqualToString:identifier]) {
} else if ([kIdentifierFlySpeed isEqualToString:identifier]) {
self.editingMonster.flySpeed = [(NSNumber*)value intValue];
} else if ([@"monster.swimSpeed" isEqualToString:identifier]) {
} else if ([kIdentifierSwimSpeed isEqualToString:identifier]) {
self.editingMonster.swimSpeed = [(NSNumber*)value intValue];
} else if ([@"monster.naturalArmorBonus" isEqualToString:identifier]) {
} else if ([kIdentifierNaturalArmorBonus isEqualToString:identifier]) {
self.editingMonster.naturalArmorBonus = [(NSNumber*)value intValue];
}
}
if ([kMCFieldValueTypeBoolean isEqualToString:type]) {
if ([@"monster.customHP" isEqualToString:identifier]) {
if ([kIdentifierHasCustomHP isEqualToString:identifier]) {
self.editingMonster.customHP = [(NSNumber*)value boolValue];
} else if ([@"monster.canHover" isEqualToString:identifier]) {
} else if ([kIdentifierCanHover isEqualToString:identifier]) {
self.editingMonster.canHover = [(NSNumber*)value boolValue];
} else if ([@"monster.hasCustomSpeed" isEqualToString:identifier]) {
} else if ([kIdentifierHasCustomSpeed isEqualToString:identifier]) {
self.editingMonster.hasCustomSpeed = [(NSNumber*)value boolValue];
} else if ([@"monster.hasShield" isEqualToString:identifier]) {
} else if ([kIdentifierHasShield isEqualToString:identifier]) {
self.editingMonster.hasShield = [(NSNumber*)value boolValue];
}
}
if ([kMCFieldValueTypeChoice isEqualToString:type]) {
if ([@"monster.armorType" isEqualToString:identifier]) {
if ([kIdentifierArmorType isEqualToString:identifier]) {
self.editingMonster.armorType = (NSString*)value;
} else if ([kIdentifierStrengthSavingThrowAdvantage isEqualToString:identifier]) {
self.editingMonster.strengthSavingThrowAdvantage = (NSString*)value;
} else if ([kIdentifierStrengthSavingThrowProficiency isEqualToString:identifier]) {
self.editingMonster.strengthSavingThrowProficiency = (NSString*)value;
} else if ([kIdentifierDexteritySavingThrowAdvantage isEqualToString:identifier]) {
self.editingMonster.dexteritySavingThrowAdvantage = (NSString*)value;
} else if ([kIdentifierDexteritySavingThrowProficiency isEqualToString:identifier]) {
self.editingMonster.dexteritySavingThrowProficiency = (NSString*)value;
} else if ([kIdentifierConstitutionSavingThrowAdvantage isEqualToString:identifier]) {
self.editingMonster.constitutionSavingThrowAdvantage = (NSString*)value;
} else if ([kIdentifierConstitutionSavingThrowProficiency isEqualToString:identifier]) {
self.editingMonster.constitutionSavingThrowProficiency = (NSString*)value;
} else if ([kIdentifierIntelligenceSavingThrowAdvantage isEqualToString:identifier]) {
self.editingMonster.intelligenceSavingThrowAdvantage = (NSString*)value;
} else if ([kIdentifierIntelligenceSavingThrowProficiency isEqualToString:identifier]) {
self.editingMonster.intelligenceSavingThrowProficiency = (NSString*)value;
} else if ([kIdentifierWisdomSavingThrowAdvantage isEqualToString:identifier]) {
self.editingMonster.wisdomSavingThrowAdvantage = (NSString*)value;
} else if ([kIdentifierWisdomSavingThrowProficiency isEqualToString:identifier]) {
self.editingMonster.wisdomSavingThrowProficiency = (NSString*)value;
} else if ([kIdentifierCharismaSavingThrowAdvantage isEqualToString:identifier]) {
self.editingMonster.charismaSavingThrowAdvantage = (NSString*)value;
} else if ([kIdentifierCharismaSavingThrowProficiency isEqualToString:identifier]) {
self.editingMonster.charismaSavingThrowProficiency = (NSString*)value;
}
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
@end

View File

@@ -0,0 +1,29 @@
//
// MCRadioFieldTableViewCell.h
// MonsterCards
//
// Created by Tom Hicks on 9/26/20.
// Copyright © 2020 Tom Hicks. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "MCFormFieldDelegate.h"
#import "MCChoice.h"
NS_ASSUME_NONNULL_BEGIN
@interface MCRadioFieldTableViewCell : UITableViewCell
@property NSString* identifier;
@property NSString* label;
@property NSObject* selectedValue;
@property NSArray<MCChoice*>* choices;
@property (weak, nonatomic) id<MCFormFieldDelegate> delegate;
@property (weak, nonatomic) IBOutlet UILabel *labelView;
@property (weak, nonatomic) IBOutlet UISegmentedControl *segmentedControl;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,131 @@
//
// MCRadioFieldTableViewCell.m
// MonsterCards
//
// Created by Tom Hicks on 9/26/20.
// Copyright © 2020 Tom Hicks. All rights reserved.
//
#import "MCRadioFieldTableViewCell.h"
@implementation MCRadioFieldTableViewCell {
MCChoice* _selectedChoice;
}
-(MCChoice*)findChoiceWithValue:(NSObject*)value
inArray:(NSArray*)array {
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id element, NSDictionary *bindings) {
if (![element isKindOfClass:[MCChoice class]]) {
return NO;
}
MCChoice *choice = (MCChoice*)element;
return [choice.value isEqual:value];
}];
NSArray<MCChoice*> *matchingChoices = [array filteredArrayUsingPredicate:predicate];
MCChoice *foundChoice = matchingChoices.count > 0 ? matchingChoices.firstObject : nil;
return foundChoice;
}
-(void)notifyChangedValue {
NSUInteger selectedIndex = [_choices indexOfObject:_selectedChoice];
[self.segmentedControl setSelectedSegmentIndex:selectedIndex];
if (_delegate) {
[_delegate editableValueDidChange:_selectedValue
forIdentifier:_identifier
andType:kMCFieldValueTypeChoice];
}
}
-(void)updateSegments {
if (_segmentedControl) {
[_segmentedControl removeAllSegments];
int index = 0;
for (MCChoice *choice in _choices) {
[_segmentedControl insertSegmentWithTitle:choice.label atIndex:index animated:NO];
index++;
}
_segmentedControl.selectedSegmentIndex = [_choices indexOfObject:_selectedChoice];
}
}
@synthesize choices = _choices;
-(void)setChoices:(NSArray<MCChoice*>*)choices {
MCChoice *foundChoice = [self findChoiceWithValue:_selectedValue
inArray:choices];
if ([_choices isEqualToArray:choices]) {
// Choices are equivalent so selected value. Pointer may have changed but content hasn't.
_selectedChoice = foundChoice;
} else if (foundChoice) {
// Choices are different but selected value is in the new choices. Pointer may have changed but content hasn't.
_selectedChoice = foundChoice;
} else {
// Choices are different and selected value is not in the new choices. Select the first choice or nil if there are none.
_selectedChoice = [choices firstObject];
}
_choices = choices;
if (_selectedValue != foundChoice.value) {
self.selectedValue = foundChoice.value;
}
[self updateSegments];
}
-(NSArray<MCChoice*>*)choices {
return _choices;
}
@synthesize label = _label;
-(void)setLabel:(NSString*)label {
if (![_label isEqualToString:label]) {
_label = label;
}
if (_labelView && ![_labelView.text isEqualToString:label]) {
_labelView.text = label;
}
}
-(NSString*)label {
return _label;
}
@synthesize selectedValue = _selectedValue;
-(void)setSelectedValue:(NSObject*)value {
NSObject *newValue = nil;
MCChoice *foundChoice = [self findChoiceWithValue:value inArray:_choices];
if (!_choices) {
newValue = value;
} else if (!foundChoice) {
newValue = nil;
} else {
newValue = foundChoice.value;
}
_selectedChoice = foundChoice;
if (_selectedValue != newValue) {
_selectedValue = newValue;
[self notifyChangedValue];
}
}
-(NSObject*)selectedValue {
return _selectedValue;
}
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (IBAction)selectedSegmentChanged:(id)sender {
NSInteger selectedIndex = _segmentedControl.selectedSegmentIndex;
MCChoice *newChoice = [_choices objectAtIndex:selectedIndex];
_selectedChoice = newChoice;
_selectedValue = _selectedChoice.value;
[self notifyChangedValue];
}
@end

View File

@@ -22,6 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (weak, nonatomic) id<MCFormFieldDelegate> delegate;
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UILabel *labelView;
@property (nonatomic) UIPickerView *pickerView;
@end

View File

@@ -12,32 +12,63 @@
MCChoice* _selectedChoice;
}
-(MCChoice*)findChoiceWithValue:(NSObject*)value
inArray:(NSArray*)array {
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id element, NSDictionary *bindings) {
if (![element isKindOfClass:[MCChoice class]]) {
return NO;
}
MCChoice *choice = (MCChoice*)element;
return [choice.value isEqual:value];
}];
NSArray<MCChoice*> *matchingChoices = [array filteredArrayUsingPredicate:predicate];
MCChoice *foundChoice = matchingChoices.count > 0 ? matchingChoices.firstObject : nil;
return foundChoice;
}
-(void)notifyChangedValue {
[self updateView];
if (_delegate) {
[_delegate editableValueDidChange:_selectedValue
forIdentifier:_identifier
andType:kMCFieldValueTypeChoice];
}
}
-(void)updateView {
self.textField.text = _selectedChoice.label;
NSInteger selectedRow = [_choices indexOfObject:_selectedChoice];
[self.pickerView selectRow:selectedRow inComponent:0 animated:YES];
}
@synthesize choices = _choices;
-(void)setChoices:(NSArray<MCChoice*>*)choices {
// TODO: only do this if choices is different
// TODO: update selectedValue and selectedIndex
MCChoice *foundChoice = [self findChoiceWithValue:_selectedValue
inArray:choices];
if ([_choices isEqualToArray:choices]) {
// Choices are equivalent so selected value. Pointer may have changed but content hasn't.
_selectedChoice = foundChoice;
} else if (foundChoice) {
// Choices are different but selected value is in the new choices. Pointer may have changed but content hasn't.
_selectedChoice = foundChoice;
} else {
// Choices are different and selected value is not in the new choices. Select the first choice or nil if there are none.
_selectedChoice = [choices firstObject];
}
_choices = choices;
if (![_choices isEqualToArray:choices]) {
self.selectedValue = _selectedValue;
} else if (choices) {
self.selectedValue = [choices firstObject].value;
if (_selectedValue != foundChoice.value) {
self.selectedValue = foundChoice.value;
}
[self updateView];
}
-(NSArray<MCChoice*>*)choices {
return _choices;
}
@synthesize identifier = _identifier;
-(void)setIdentifier:(NSString*)identifier {
if (![_identifier isEqualToString:identifier]) {
_identifier = identifier;
}
}
-(NSString*)identifier {
return _identifier;
}
@synthesize label = _label;
-(void)setLabel:(NSString*)label {
if (![_label isEqualToString:label]) {
@@ -51,42 +82,23 @@
return _label;
}
-(MCChoice*)findChoiceWithValue:(NSObject*)value
inArray:(NSArray*)array {
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id element, NSDictionary *bindings) {
if (![element isKindOfClass:[MCChoice class]]) {
return NO;
}
MCChoice *choice = (MCChoice*)element;
return [choice.value isEqual:value];
}];
NSArray<MCChoice*> *matchingChoices = [_choices filteredArrayUsingPredicate:predicate];
MCChoice *foundChoice = matchingChoices.count > 0 ? matchingChoices.firstObject : nil;
return foundChoice;
}
@synthesize selectedValue = _selectedValue;
-(void)setSelectedValue:(NSObject*)value {
NSObject *newValue = nil;
MCChoice *foundChoice = [self findChoiceWithValue:value inArray:_choices];
if (!_choices) {
// choices hasn't been initialized yet so just set our selected value until choices is set
_selectedValue = value;
newValue = value;
} else if (!foundChoice) {
newValue = nil;
} else {
newValue = foundChoice.value;
}
MCChoice *foundChoice = [self findChoiceWithValue:value
inArray:_choices];
if (![_selectedChoice isEqual:foundChoice] || ![_selectedValue isEqual:foundChoice.value]) {
_selectedChoice = foundChoice;
_selectedValue = foundChoice.value;
if (_delegate) {
[_delegate editableValueDidChange:_selectedValue
forIdentifier:_identifier
andType:kMCFieldValueTypeChoice];
}
_selectedChoice = foundChoice;
if (_selectedValue != newValue) {
_selectedValue = newValue;
[self notifyChangedValue];
}
self.textField.text = _selectedChoice != nil
? _selectedChoice.label != nil
? _selectedChoice.label
: @""
: @"";
}
-(NSObject*)selectedValue {
return _selectedValue;
@@ -94,10 +106,11 @@
- (void)awakeFromNib {
[super awakeFromNib];
UIPickerView *childPicker = [[UIPickerView alloc] init];
childPicker.delegate = self;
childPicker.dataSource = self;
self.textField.inputView = childPicker;
self.pickerView = [[UIPickerView alloc] init];
self.pickerView.delegate = self;
self.pickerView.dataSource = self;
self.textField.inputView = self.pickerView;
self.pickerView.translatesAutoresizingMaskIntoConstraints = NO;
UIToolbar *toolbar = [[UIToolbar alloc] init];
[toolbar sizeToFit];
@@ -154,4 +167,10 @@ numberOfRowsInComponent:(NSInteger)component {
self.selectedValue = _selectedChoice.value;
}
#pragma mark - UITextFieldDelegate
- (void)textFieldDidBeginEditing:(UITextField *)textField {
[self updateView];
}
@end