Adds HP related fields to core data.

Implements hitDieForSize and hitPointsDescription in Monster.
Adds tests.
This commit is contained in:
2020-09-20 03:21:34 -07:00
parent 29f5ef991e
commit 82e5545904
4 changed files with 107 additions and 12 deletions

View File

@@ -17,6 +17,12 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
extern NSString* const kMonsterSizeTiny;
extern NSString* const kMonsterSizeSmall;
extern NSString* const kMonsterSizeMedium;
extern NSString* const kMonsterSizeLarge;
extern NSString* const kMonsterSizeHuge;
extern NSString* const kMonsterSizeGargantuan;
extern const int kArmorClassUnarmored; extern const int kArmorClassUnarmored;
extern const int kArmorClassMageArmor; extern const int kArmorClassMageArmor;
@@ -54,7 +60,6 @@ extern NSString* const kArmorNameOther;
@interface Monster : NSManagedObject @interface Monster : NSManagedObject
@property NSString *hpText;
@property NSString *speed; @property NSString *speed;
@property NSString *burrowSpeed; @property NSString *burrowSpeed;
@property NSString *climbSpeed; @property NSString *climbSpeed;
@@ -71,12 +76,10 @@ extern NSString* const kArmorNameOther;
@property NSString *understandsBut; @property NSString *understandsBut;
@property int naturalArmorBonus; @property int naturalArmorBonus;
@property int hitDice;
@property int customProficiencyBonus; @property int customProficiencyBonus;
// Shouldn't this be a BOOL? // Shouldn't this be a BOOL?
@property int telepathy; @property int telepathy;
@property BOOL customHP;
@property BOOL hover; @property BOOL hover;
@property BOOL customSpeed; @property BOOL customSpeed;
@property BOOL isBlind; @property BOOL isBlind;

View File

@@ -17,15 +17,12 @@
@synthesize challengeRating; @synthesize challengeRating;
@synthesize climbSpeed; @synthesize climbSpeed;
@synthesize customChallengeRating; @synthesize customChallengeRating;
@synthesize customHP;
@synthesize customProficiencyBonus; @synthesize customProficiencyBonus;
@synthesize customSpeed; @synthesize customSpeed;
@synthesize customSpeedDescription; @synthesize customSpeedDescription;
@synthesize darkvisionDistance; @synthesize darkvisionDistance;
@synthesize flySpeed; @synthesize flySpeed;
@synthesize hitDice;
@synthesize hover; @synthesize hover;
@synthesize hpText;
@synthesize isBlind; @synthesize isBlind;
@synthesize naturalArmorBonus; @synthesize naturalArmorBonus;
@synthesize speed; @synthesize speed;
@@ -66,12 +63,34 @@ NSString* const kArmorNameChainMail = @"chain mail";
NSString* const kArmorNameSplintMail = @"splint"; NSString* const kArmorNameSplintMail = @"splint";
NSString* const kArmorNamePlateMail = @"plate"; NSString* const kArmorNamePlateMail = @"plate";
NSString* const kArmorNameOther = @"other"; NSString* const kArmorNameOther = @"other";
NSString* const kMonsterSizeTiny = @"tiny";
NSString* const kMonsterSizeSmall = @"small";
NSString* const kMonsterSizeMedium = @"medium";
NSString* const kMonsterSizeLarge = @"large";
NSString* const kMonsterSizeHuge = @"huge";
NSString* const kMonsterSizeGargantuan = @"gargantuan";
+(int)abilityModifierForScore: (int)score { +(int)abilityModifierForScore: (int)score {
return (int)floor((score - 10) / 2.0); return (int)floor((score - 10) / 2.0);
} }
+(int)hitDieForSize: (NSString*)size{ +(int)hitDieForSize: (NSString*)size{
@throw [[NSException alloc] initWithName:@"unimplemented" reason:@"Method not implemented." userInfo:nil]; if ([kMonsterSizeTiny isEqualToString:size]) {
return 4;
} else if ([kMonsterSizeSmall isEqualToString:size]) {
return 6;
} else if ([kMonsterSizeMedium isEqualToString:size]) {
return 8;
} else if ([kMonsterSizeLarge isEqualToString:size]) {
return 10;
} else if ([kMonsterSizeHuge isEqualToString:size]) {
return 12;
} else if ([kMonsterSizeGargantuan isEqualToString:size]) {
return 20;
} else {
return 8;
}
} }
-(id)init { -(id)init {
@@ -98,6 +117,8 @@ NSString* const kArmorNameOther = @"other";
self.size = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"size" withDefaultValue:@""]; self.size = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"size" withDefaultValue:@""];
self.type = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"type" withDefaultValue:@""]; self.type = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"type" withDefaultValue:@""];
self.subtype = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"tag" withDefaultValue:@""]; self.subtype = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"tag" withDefaultValue:@""];
self.hpText = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"hpText" withDefaultValue:@""];
self.alignment = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"alignment" withDefaultValue:@""]; self.alignment = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"alignment" withDefaultValue:@""];
self.armorName = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"armorName" withDefaultValue:@""]; self.armorName = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"armorName" withDefaultValue:@""];
self.otherArmorDescription = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"otherArmorDesc" withDefaultValue:@""]; self.otherArmorDescription = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"otherArmorDesc" withDefaultValue:@""];
@@ -108,6 +129,9 @@ NSString* const kArmorNameOther = @"other";
self.wisdomScore = [JSONHelper readIntFromDictionary:jsonRoot forKey:@"wisPoints" withDefaultValue:0]; self.wisdomScore = [JSONHelper readIntFromDictionary:jsonRoot forKey:@"wisPoints" withDefaultValue:0];
self.charismaScore = [JSONHelper readIntFromDictionary:jsonRoot forKey:@"chaPoints" withDefaultValue:0]; self.charismaScore = [JSONHelper readIntFromDictionary:jsonRoot forKey:@"chaPoints" withDefaultValue:0];
self.shieldBonus = [JSONHelper readIntFromDictionary:jsonRoot forKey:@"shieldBonus" withDefaultValue:0]; self.shieldBonus = [JSONHelper readIntFromDictionary:jsonRoot forKey:@"shieldBonus" withDefaultValue:0];
self.hitDice = [JSONHelper readIntFromDictionary:jsonRoot forKey:@"hitDice" withDefaultValue:0];
self.customHP = [JSONHelper readBoolFromDictionary:jsonRoot forKey:@"customHP" withDefaultValue:NO];
return self; return self;
} }
@@ -251,7 +275,15 @@ NSString* const kArmorNameOther = @"other";
//getHitPoints //getHitPoints
-(NSString*)hitPointsDescription { -(NSString*)hitPointsDescription {
@throw [[NSException alloc] initWithName:@"unimplemented" reason:@"Method not implemented." userInfo:nil]; if (self.customHP) {
return self.hpText;
} else {
int dieSize = [Monster hitDieForSize:self.size];
int conMod = self.constitutionModifier;
int hpTotal = (int)MAX(1, ceil(dieSize + conMod + (self.hitDice - 1) * ((dieSize + 1) / 2.0 + conMod)));
int conBonus = conMod * self.hitDice;
return [NSString stringWithFormat:@"%d (%dd%d%+d)", hpTotal, self.hitDice, dieSize, conBonus];
}
} }
//getSpeedText //getSpeedText
@@ -450,6 +482,9 @@ NSString* const kArmorNameOther = @"other";
self.armorName = monster.armorName; self.armorName = monster.armorName;
self.otherArmorDescription = monster.otherArmorDescription; self.otherArmorDescription = monster.otherArmorDescription;
self.shieldBonus = monster.shieldBonus; self.shieldBonus = monster.shieldBonus;
self.customHP = monster.customHP;
self.hitDice = monster.hitDice;
self.hpText = monster.hpText;
} }
@end @end

View File

@@ -1,11 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="16119" systemVersion="19G2021" minimumToolsVersion="Automatic" sourceLanguage="Objective-C" usedWithCloudKit="YES" userDefinedModelVersionIdentifier=""> <model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17192" systemVersion="19G2021" minimumToolsVersion="Automatic" sourceLanguage="Objective-C" usedWithCloudKit="YES" userDefinedModelVersionIdentifier="">
<entity name="Monster" representedClassName="Monster" syncable="YES" codeGenerationType="category"> <entity name="Monster" representedClassName="Monster" syncable="YES" codeGenerationType="category">
<attribute name="alignment" attributeType="String" defaultValueString=""/> <attribute name="alignment" attributeType="String" defaultValueString=""/>
<attribute name="armorName" optional="YES" attributeType="String" defaultValueString=""/> <attribute name="armorName" optional="YES" attributeType="String" defaultValueString=""/>
<attribute name="charismaScore" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/> <attribute name="charismaScore" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="constitutionScore" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/> <attribute name="constitutionScore" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="customHP" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="dexterityScore" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/> <attribute name="dexterityScore" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="hitDice" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="hpText" optional="YES" attributeType="String" defaultValueString=""/>
<attribute name="intelligenceScore" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/> <attribute name="intelligenceScore" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="name" attributeType="String" defaultValueString=""/> <attribute name="name" attributeType="String" defaultValueString=""/>
<attribute name="otherArmorDescription" optional="YES" attributeType="String" defaultValueString=""/> <attribute name="otherArmorDescription" optional="YES" attributeType="String" defaultValueString=""/>
@@ -17,6 +20,6 @@
<attribute name="wisdomScore" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/> <attribute name="wisdomScore" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
</entity> </entity>
<elements> <elements>
<element name="Monster" positionX="-63" positionY="-18" width="128" height="253"/> <element name="Monster" positionX="-63" positionY="-18" width="128" height="298"/>
</elements> </elements>
</model> </model>

View File

@@ -25,7 +25,7 @@
- (void)setUp { - (void)setUp {
_context = nil; _context = nil;
_monster = [[Monster alloc] initWithContext:_context]; _monster = [[Monster alloc] initWithContext:_context];
_jsonString = @"{\"name\":\"Acolyte\",\"size\":\"medium\",\"type\":\"humanoid\",\"tag\":\"any race\",\"alignment\":\"any alignment\",\"strPoints\":8,\"dexPoints\":10,\"conPoints\":12,\"intPoints\":14,\"wisPoints\":16,\"chaPoints\":18,\"armorName\":\"none\",\"otherArmorDesc\":\"10\",\"shieldBonus\":2}"; _jsonString = @"{\"name\":\"Acolyte\",\"size\":\"medium\",\"type\":\"humanoid\",\"tag\":\"any race\",\"alignment\":\"any alignment\",\"strPoints\":8,\"dexPoints\":10,\"conPoints\":12,\"intPoints\":14,\"wisPoints\":16,\"chaPoints\":18,\"armorName\":\"none\",\"otherArmorDesc\":\"10\",\"shieldBonus\":2,\"hitDice\":3,\"customHP\":true,\"hpText\":\"1234 (1d1+magic)\"}";
_jsonData = [_jsonString dataUsingEncoding:NSUTF8StringEncoding]; _jsonData = [_jsonString dataUsingEncoding:NSUTF8StringEncoding];
} }
@@ -49,7 +49,9 @@
XCTAssertEqualObjects(@"", _monster.armorName); XCTAssertEqualObjects(@"", _monster.armorName);
XCTAssertEqualObjects(@"", _monster.otherArmorDescription); XCTAssertEqualObjects(@"", _monster.otherArmorDescription);
XCTAssertEqual(0, _monster.shieldBonus); XCTAssertEqual(0, _monster.shieldBonus);
} XCTAssertEqual(NO, _monster.customHP);
XCTAssertEqual(0, _monster.hitDice);
XCTAssertEqualObjects(@"", _monster.hpText);}
- (void)testInitWithJSONString { - (void)testInitWithJSONString {
_monster = [[Monster alloc] initWithJSONString:_jsonString andContext:_context]; _monster = [[Monster alloc] initWithJSONString:_jsonString andContext:_context];
@@ -69,6 +71,9 @@
XCTAssertEqualObjects(@"none", _monster.armorName); XCTAssertEqualObjects(@"none", _monster.armorName);
XCTAssertEqualObjects(@"10", _monster.otherArmorDescription); XCTAssertEqualObjects(@"10", _monster.otherArmorDescription);
XCTAssertEqual(2, _monster.shieldBonus); XCTAssertEqual(2, _monster.shieldBonus);
XCTAssertEqual(YES, _monster.customHP);
XCTAssertEqual(3, _monster.hitDice);
XCTAssertEqualObjects(@"1234 (1d1+magic)", _monster.hpText);
} }
- (void)testInitWithEmptyJSONString { - (void)testInitWithEmptyJSONString {
@@ -89,7 +94,11 @@
XCTAssertEqualObjects(@"", _monster.armorName); XCTAssertEqualObjects(@"", _monster.armorName);
XCTAssertEqualObjects(@"", _monster.otherArmorDescription); XCTAssertEqualObjects(@"", _monster.otherArmorDescription);
XCTAssertEqual(0, _monster.shieldBonus); XCTAssertEqual(0, _monster.shieldBonus);
XCTAssertEqual(NO, _monster.customHP);
XCTAssertEqual(0, _monster.hitDice);
XCTAssertEqualObjects(@"", _monster.hpText);
} }
- (void)testInitWithJSONData { - (void)testInitWithJSONData {
_monster = [[Monster alloc] initWithJSONData:_jsonData andContext:_context]; _monster = [[Monster alloc] initWithJSONData:_jsonData andContext:_context];
@@ -108,6 +117,9 @@
XCTAssertEqualObjects(@"none", _monster.armorName); XCTAssertEqualObjects(@"none", _monster.armorName);
XCTAssertEqualObjects(@"10", _monster.otherArmorDescription); XCTAssertEqualObjects(@"10", _monster.otherArmorDescription);
XCTAssertEqual(2, _monster.shieldBonus); XCTAssertEqual(2, _monster.shieldBonus);
XCTAssertEqual(YES, _monster.customHP);
XCTAssertEqual(3, _monster.hitDice);
XCTAssertEqualObjects(@"1234 (1d1+magic)", _monster.hpText);
} }
- (void)testNameGetterAndSetter { - (void)testNameGetterAndSetter {
@@ -382,4 +394,46 @@
XCTAssertEqualObjects(@"green", _monster.otherArmorDescription); XCTAssertEqualObjects(@"green", _monster.otherArmorDescription);
} }
- (void)testHitDieForSizeReturnsExpectedValuesForKnownSizes {
}
- (void)testHitDieForSizeReutnrsEightForUnknownSizes {
XCTAssertEqual(4, [Monster hitDieForSize:kMonsterSizeTiny]);
XCTAssertEqual(6, [Monster hitDieForSize:kMonsterSizeSmall]);
XCTAssertEqual(8, [Monster hitDieForSize:kMonsterSizeMedium]);
XCTAssertEqual(10, [Monster hitDieForSize:kMonsterSizeLarge]);
XCTAssertEqual(12, [Monster hitDieForSize:kMonsterSizeHuge]);
XCTAssertEqual(20, [Monster hitDieForSize:kMonsterSizeGargantuan]);
}
- (void)testCustomHPGetterAndSetter {
XCTAssertEqual(8, [Monster hitDieForSize:nil]);
XCTAssertEqual(8, [Monster hitDieForSize:@""]);
XCTAssertEqual(8, [Monster hitDieForSize:@"unknown size"]);
}
- (void)testHitDiceGetterAndSetter {
_monster.hitDice = 9;
XCTAssertEqual(9, _monster.hitDice);
}
- (void)testHPTextGetterAndSetter {
_monster.hpText = @"This is my HP.";
XCTAssertEqualObjects(@"This is my HP.", _monster.hpText);
}
- (void)testHitPointsDescriptionWithCustomHP {
_monster = [[Monster alloc] initWithJSONString:_jsonString andContext:_context];
_monster.customHP = YES;
XCTAssertEqualObjects(@"1234 (1d1+magic)", _monster.hitPointsDescription);
}
- (void)testHitPointsDescriptionWithCalculatedHP {
_monster = [[Monster alloc] initWithJSONString:_jsonString andContext:_context];
_monster.customHP = NO;
XCTAssertEqualObjects(@"20 (3d8+3)", _monster.hitPointsDescription);
}
@end @end