Adds HP related fields to core data.
Implements hitDieForSize and hitPointsDescription in Monster. Adds tests.
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user