From 16aa24150e795a340fe38c41ec510396178abc7f Mon Sep 17 00:00:00 2001 From: Tom Hicks Date: Sun, 20 Sep 2020 03:21:34 -0700 Subject: [PATCH] Adds HP related fields to core data. Implements hitDieForSize and hitPointsDescription in Monster. Adds tests. --- MonsterCards/Models/Monster.h | 9 ++- MonsterCards/Models/Monster.m | 45 ++++++++++++-- .../MonsterCards.xcdatamodel/contents | 7 ++- MonsterCardsTests/Models/MonsterTests.m | 58 ++++++++++++++++++- 4 files changed, 107 insertions(+), 12 deletions(-) diff --git a/MonsterCards/Models/Monster.h b/MonsterCards/Models/Monster.h index 05d09aa..e659fd3 100644 --- a/MonsterCards/Models/Monster.h +++ b/MonsterCards/Models/Monster.h @@ -17,6 +17,12 @@ 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 kArmorClassMageArmor; @@ -54,7 +60,6 @@ extern NSString* const kArmorNameOther; @interface Monster : NSManagedObject -@property NSString *hpText; @property NSString *speed; @property NSString *burrowSpeed; @property NSString *climbSpeed; @@ -71,12 +76,10 @@ extern NSString* const kArmorNameOther; @property NSString *understandsBut; @property int naturalArmorBonus; -@property int hitDice; @property int customProficiencyBonus; // Shouldn't this be a BOOL? @property int telepathy; -@property BOOL customHP; @property BOOL hover; @property BOOL customSpeed; @property BOOL isBlind; diff --git a/MonsterCards/Models/Monster.m b/MonsterCards/Models/Monster.m index 9dd35de..21897d1 100644 --- a/MonsterCards/Models/Monster.m +++ b/MonsterCards/Models/Monster.m @@ -17,15 +17,12 @@ @synthesize challengeRating; @synthesize climbSpeed; @synthesize customChallengeRating; -@synthesize customHP; @synthesize customProficiencyBonus; @synthesize customSpeed; @synthesize customSpeedDescription; @synthesize darkvisionDistance; @synthesize flySpeed; -@synthesize hitDice; @synthesize hover; -@synthesize hpText; @synthesize isBlind; @synthesize naturalArmorBonus; @synthesize speed; @@ -66,12 +63,34 @@ NSString* const kArmorNameChainMail = @"chain mail"; NSString* const kArmorNameSplintMail = @"splint"; NSString* const kArmorNamePlateMail = @"plate"; 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 { return (int)floor((score - 10) / 2.0); } +(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 { @@ -98,6 +117,8 @@ NSString* const kArmorNameOther = @"other"; self.size = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"size" withDefaultValue:@""]; self.type = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"type" 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.armorName = [JSONHelper readStringFromDictionary:jsonRoot forKey:@"armorName" 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.charismaScore = [JSONHelper readIntFromDictionary:jsonRoot forKey:@"chaPoints" 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; } @@ -251,7 +275,15 @@ NSString* const kArmorNameOther = @"other"; //getHitPoints -(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 @@ -450,6 +482,9 @@ NSString* const kArmorNameOther = @"other"; self.armorName = monster.armorName; self.otherArmorDescription = monster.otherArmorDescription; self.shieldBonus = monster.shieldBonus; + self.customHP = monster.customHP; + self.hitDice = monster.hitDice; + self.hpText = monster.hpText; } @end diff --git a/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents b/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents index 3d90d75..a5c0a26 100644 --- a/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents +++ b/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents @@ -1,11 +1,14 @@ - + + + + @@ -17,6 +20,6 @@ - + \ No newline at end of file diff --git a/MonsterCardsTests/Models/MonsterTests.m b/MonsterCardsTests/Models/MonsterTests.m index 61285fc..eec86b9 100644 --- a/MonsterCardsTests/Models/MonsterTests.m +++ b/MonsterCardsTests/Models/MonsterTests.m @@ -25,7 +25,7 @@ - (void)setUp { _context = nil; _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]; } @@ -49,7 +49,9 @@ XCTAssertEqualObjects(@"", _monster.armorName); XCTAssertEqualObjects(@"", _monster.otherArmorDescription); XCTAssertEqual(0, _monster.shieldBonus); -} + XCTAssertEqual(NO, _monster.customHP); + XCTAssertEqual(0, _monster.hitDice); + XCTAssertEqualObjects(@"", _monster.hpText);} - (void)testInitWithJSONString { _monster = [[Monster alloc] initWithJSONString:_jsonString andContext:_context]; @@ -69,6 +71,9 @@ XCTAssertEqualObjects(@"none", _monster.armorName); XCTAssertEqualObjects(@"10", _monster.otherArmorDescription); XCTAssertEqual(2, _monster.shieldBonus); + XCTAssertEqual(YES, _monster.customHP); + XCTAssertEqual(3, _monster.hitDice); + XCTAssertEqualObjects(@"1234 (1d1+magic)", _monster.hpText); } - (void)testInitWithEmptyJSONString { @@ -89,7 +94,11 @@ XCTAssertEqualObjects(@"", _monster.armorName); XCTAssertEqualObjects(@"", _monster.otherArmorDescription); XCTAssertEqual(0, _monster.shieldBonus); + XCTAssertEqual(NO, _monster.customHP); + XCTAssertEqual(0, _monster.hitDice); + XCTAssertEqualObjects(@"", _monster.hpText); } + - (void)testInitWithJSONData { _monster = [[Monster alloc] initWithJSONData:_jsonData andContext:_context]; @@ -108,6 +117,9 @@ XCTAssertEqualObjects(@"none", _monster.armorName); XCTAssertEqualObjects(@"10", _monster.otherArmorDescription); XCTAssertEqual(2, _monster.shieldBonus); + XCTAssertEqual(YES, _monster.customHP); + XCTAssertEqual(3, _monster.hitDice); + XCTAssertEqualObjects(@"1234 (1d1+magic)", _monster.hpText); } - (void)testNameGetterAndSetter { @@ -382,4 +394,46 @@ 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