/** * Distance modifier can be solved very roughly by a simple table or more precisely with continual values by a calculation. * This uses that calculation. * See PPH page 104 left column. * * @param EncounterRange $currentEncounterRange * @param Distance $distance * @param MaximalRange $currentMaximalRange * @return int * @throws Exceptions\DistanceIsOutOfMaximalRange * @throws Exceptions\EncounterRangeCanNotBeGreaterThanMaximalRange * @throws DistanceOutOfKnownValues */ public function getAttackNumberModifierByDistance(Distance $distance, EncounterRange $currentEncounterRange, MaximalRange $currentMaximalRange) { if ($distance->getBonus()->getValue() > $currentMaximalRange->getValue()) { // comparing distance bonuses in fact throw new Exceptions\DistanceIsOutOfMaximalRange("Given distance {$distance->getBonus()} ({$distance->getMeters()} meters)" . " is out of maximal range {$currentMaximalRange}" . ' (' . $currentMaximalRange->getInMeters($this->tables->getDistanceTable()) . ' meters)'); } if ($currentEncounterRange->getValue() > $currentMaximalRange->getValue()) { throw new Exceptions\EncounterRangeCanNotBeGreaterThanMaximalRange("Got encounter range {$currentEncounterRange} greater than given maximal range {$currentMaximalRange}"); } $attackNumberModifier = $this->tables->getContinuousAttackNumberByDistanceTable()->getAttackNumberModifierByDistance($distance); if ($distance->getBonus()->getValue() > $currentEncounterRange->getValue()) { // comparing distance bonuses in fact $attackNumberModifier += $currentEncounterRange->getValue() - $distance->getBonus()->getValue(); // always negative } return $attackNumberModifier; }
/** * @test * @depends I_can_get_race * @param Race $race * @throws \LogicException */ public function I_can_get_non_base_property(Race $race) { $tables = new Tables(); $racesTable = $tables->getRacesTable(); $distanceTable = $tables->getDistanceTable(); foreach ($this->getGenders() as $genderCode) { foreach ($this->getNonBaseNonDerivedPropertyCodes() as $propertyCode) { $sameValueByGenericGetter = $race->getProperty($propertyCode, $genderCode, $tables); switch ($propertyCode) { case PropertyCode::SENSES: $value = $race->getSenses($racesTable); break; case PropertyCode::TOUGHNESS: $value = $race->getToughness($racesTable); break; case PropertyCode::SIZE: $value = $race->getSize($genderCode, $tables); break; case PropertyCode::WEIGHT: $value = $race->getWeight($genderCode, $tables); break; case PropertyCode::WEIGHT_IN_KG: $value = $race->getWeightInKg($genderCode, $tables); break; case PropertyCode::HEIGHT_IN_CM: $value = $race->getHeightInCm($racesTable); break; case PropertyCode::HEIGHT: $value = $race->getHeight($racesTable, $distanceTable); break; case PropertyCode::INFRAVISION: $value = $race->hasInfravision($racesTable); break; case PropertyCode::NATIVE_REGENERATION: $value = $race->hasNativeRegeneration($racesTable); break; case PropertyCode::REQUIRES_DM_AGREEMENT: $value = $race->requiresDmAgreement($racesTable); break; case PropertyCode::REMARKABLE_SENSE: $value = $race->getRemarkableSense($racesTable); break; case PropertyCode::AGE: $value = $race->getAge($racesTable); break; default: throw new \LogicException("Unexpected property {$propertyCode} for {$race->getSubraceCode()} {$race->getRaceCode()} {$genderCode}"); } if ($propertyCode === PropertyCode::WEIGHT) { $expectedOtherProperty = $this->getExpectedWeight($genderCode, $tables->getWeightTable()); } else { $expectedOtherProperty = $this->getExpectedOtherProperty($propertyCode, $genderCode->getValue()); } self::assertEquals($expectedOtherProperty, $value, "Unexpected {$propertyCode} of {$race->getSubraceCode()} {$race->getRaceCode()} {$genderCode}"); self::assertSame($sameValueByGenericGetter, $value); } } }
/** * @test * @dataProvider getCombination * * @param Race $race * @param GenderCode $genderCode * @param ExceptionalityProperties $exceptionalityProperties * @param ProfessionLevels $professionLevels * @param Tables $tables * @param WeightInKg $weightInKgAdjustment * @param HeightInCm $heightInCmAdjustment * @param Age $age * @param int $expectedStrength * @param int $expectedAgility * @param int $expectedKnack * @param int $expectedWill * @param int $expectedIntelligence * @param int $expectedCharisma */ public function I_can_create_properties_for_any_combination(Race $race, GenderCode $genderCode, ExceptionalityProperties $exceptionalityProperties, ProfessionLevels $professionLevels, Tables $tables, WeightInKg $weightInKgAdjustment, HeightInCm $heightInCmAdjustment, Age $age, $expectedStrength, $expectedAgility, $expectedKnack, $expectedWill, $expectedIntelligence, $expectedCharisma) { $properties = new PropertiesByLevels($race, $genderCode, $exceptionalityProperties, $professionLevels, $weightInKgAdjustment, $heightInCmAdjustment, $age, $tables); self::assertInstanceOf(FirstLevelProperties::class, $properties->getFirstLevelProperties()); self::assertInstanceOf(NextLevelsProperties::class, $properties->getNextLevelsProperties()); self::assertSame($expectedStrength, $properties->getStrength()->getValue(), "{$race} {$genderCode}"); self::assertSame($expectedAgility, $properties->getAgility()->getValue(), "{$race} {$genderCode}"); self::assertSame($expectedKnack, $properties->getKnack()->getValue(), "{$race} {$genderCode}"); self::assertSame($expectedWill, $properties->getWill()->getValue(), "{$race} {$genderCode}"); self::assertSame($expectedIntelligence, $properties->getIntelligence()->getValue(), "{$race} {$genderCode}"); self::assertSame($expectedCharisma, $properties->getCharisma()->getValue(), "{$race} {$genderCode}"); self::assertSame($weightInKgAdjustment, $properties->getWeightInKgAdjustment()); self::assertGreaterThan($weightInKgAdjustment->getValue(), $properties->getWeightInKg()->getValue(), "{$race} {$genderCode}"); self::assertSame($heightInCmAdjustment, $properties->getHeightInCmAdjustment()); self::assertGreaterThan($heightInCmAdjustment->getValue(), $properties->getHeightInCm()->getValue(), "{$race} {$genderCode}"); self::assertEquals($expectedHeight = new Height($properties->getHeightInCm(), $tables->getDistanceTable()), $properties->getHeight()); self::assertSame($age, $properties->getAge()); $expectedToughness = new Toughness(Strength::getIt($expectedStrength), $race->getRaceCode(), $race->getSubraceCode(), $tables->getRacesTable()); self::assertInstanceOf(Toughness::class, $properties->getToughness()); self::assertSame($expectedToughness->getValue(), $properties->getToughness()->getValue(), "{$race} {$genderCode}"); $expectedEndurance = new Endurance(Strength::getIt($expectedStrength), Will::getIt($expectedWill)); self::assertInstanceOf(Endurance::class, $properties->getEndurance()); self::assertSame($expectedEndurance->getValue(), $properties->getEndurance()->getValue(), "{$race} {$genderCode}"); $expectedSize = Size::getIt($race->getSize($genderCode, $tables) + 1); /* size bonus by strength */ self::assertInstanceOf(Size::class, $properties->getSize(), "{$race} {$genderCode}"); self::assertSame($expectedSize->getValue(), $properties->getSize()->getValue(), "{$race} {$genderCode}"); $expectedSpeed = new Speed(Strength::getIt($expectedStrength), Agility::getIt($expectedAgility), $expectedHeight); self::assertInstanceOf(Speed::class, $properties->getSpeed(), "{$race} {$genderCode}"); self::assertSame($expectedSpeed->getValue(), $properties->getSpeed()->getValue(), "{$race} {$genderCode}"); $expectedSenses = new Senses(Knack::getIt($expectedKnack), RaceCode::getIt($race->getRaceCode()), SubRaceCode::getIt($race->getSubraceCode()), $tables->getRacesTable()); self::assertInstanceOf(Senses::class, $properties->getSenses()); self::assertSame($expectedSenses->getValue(), $properties->getSenses()->getValue(), "{$race} {$genderCode}"); $expectedBeauty = new Beauty(Agility::getIt($expectedAgility), Knack::getIt($expectedKnack), Charisma::getIt($expectedCharisma)); self::assertInstanceOf(Beauty::class, $properties->getBeauty()); self::assertSame($expectedBeauty->getValue(), $properties->getBeauty()->getValue(), "{$race} {$genderCode}"); $expectedDangerousness = new Dangerousness(Strength::getIt($expectedStrength), Will::getIt($expectedWill), Charisma::getIt($expectedCharisma)); self::assertInstanceOf(Dangerousness::class, $properties->getDangerousness()); self::assertSame($expectedDangerousness->getValue(), $properties->getDangerousness()->getValue(), "{$race} {$genderCode}"); $expectedDignity = new Dignity(Intelligence::getIt($expectedIntelligence), Will::getIt($expectedWill), Charisma::getIt($expectedCharisma)); self::assertInstanceOf(Dignity::class, $properties->getDignity()); self::assertSame($expectedDignity->getValue(), $properties->getDignity()->getValue(), "{$race} {$genderCode}"); $expectedFightValue = $expectedAgility + (SumAndRound::ceil($expectedHeight->getValue() / 3) - 2); self::assertInstanceOf(FightNumber::class, $properties->getFightNumber()); self::assertSame($expectedFightValue, $properties->getFightNumber()->getValue(), "{$race} {$genderCode} with height {$expectedHeight}"); $expectedAttack = new Attack(Agility::getIt($expectedAgility)); self::assertInstanceOf(Attack::class, $properties->getAttack()); self::assertSame($expectedAttack->getValue(), $properties->getAttack()->getValue(), "{$race} {$genderCode}"); $expectedShooting = new Shooting(Knack::getIt($expectedKnack)); self::assertInstanceOf(Shooting::class, $properties->getShooting()); self::assertSame($expectedShooting->getValue(), $properties->getShooting()->getValue(), "{$race} {$genderCode}"); $expectedDefense = new DefenseNumber(Agility::getIt($expectedAgility)); self::assertInstanceOf(DefenseNumber::class, $properties->getDefenseNumber()); self::assertSame($expectedDefense->getValue(), $properties->getDefenseNumber()->getValue(), "{$race} {$genderCode}"); $expectedDefenseAgainstShooting = new DefenseNumberAgainstShooting($expectedDefense, $expectedSize); self::assertInstanceOf(DefenseNumberAgainstShooting::class, $properties->getDefenseAgainstShooting()); self::assertSame($expectedDefenseAgainstShooting->getValue(), $properties->getDefenseAgainstShooting()->getValue(), "{$race} {$genderCode}"); $expectedWoundBoundary = new WoundBoundary($expectedToughness, $tables->getWoundsTable()); self::assertInstanceOf(WoundBoundary::class, $properties->getWoundBoundary()); self::assertSame($expectedWoundBoundary->getValue(), $properties->getWoundBoundary()->getValue()); $expectedFatigueBoundary = new FatigueBoundary($expectedEndurance, $tables->getFatigueTable()); self::assertInstanceOf(FatigueBoundary::class, $properties->getFatigueBoundary()); self::assertSame($expectedFatigueBoundary->getValue(), $properties->getFatigueBoundary()->getValue()); }
/** * @test * @dataProvider provideBasePropertyValues * @param $strength * @param $agility * @param $knack * @param $will * @param $intelligence * @param $charisma */ public function I_can_get_every_property_both_limited_and_unlimited($strength, $agility, $knack, $will, $intelligence, $charisma) { $race = CommonHuman::getIt(); $female = GenderCode::getIt(GenderCode::FEMALE); $exceptionalityProperties = $this->createExceptionalityProperties($strength, $agility, $knack, $will, $intelligence, $charisma); $professionLevels = $this->createProfessionLevels(); $weightInKgAdjustment = WeightInKg::getIt(12.3); $heightInCmAdjustment = HeightInCm::getIt(123.45); $age = Age::getIt(32); $tables = new Tables(); $firstLevelProperties = new FirstLevelProperties($race, $female, $exceptionalityProperties, $professionLevels, $weightInKgAdjustment, $heightInCmAdjustment, $age, $tables); self::assertSame($exceptionalityProperties, $firstLevelProperties->getExceptionalityProperties()); $expectedStrength = min($strength, 3) - 1; /* female */ self::assertInstanceOf(Strength::class, $firstLevelProperties->getFirstLevelStrength()); self::assertSame($expectedStrength, $firstLevelProperties->getFirstLevelStrength()->getValue()); self::assertSame(max(0, $strength - 3), $firstLevelProperties->getStrengthLossBecauseOfLimit()); $expectedAgility = min($agility, 3); self::assertInstanceOf(Agility::class, $firstLevelProperties->getFirstLevelAgility()); self::assertEquals($expectedAgility, $firstLevelProperties->getFirstLevelAgility()->getValue()); self::assertSame(max(0, $agility - 3), $firstLevelProperties->getAgilityLossBecauseOfLimit()); $expectedKnack = min($knack, 3); self::assertInstanceOf(Knack::class, $firstLevelProperties->getFirstLevelKnack()); self::assertEquals($expectedKnack, $firstLevelProperties->getFirstLevelKnack()->getValue()); self::assertSame(max(0, $knack - 3), $firstLevelProperties->getKnackLossBecauseOfLimit()); $expectedWill = min($will, 3); self::assertInstanceOf(Will::class, $firstLevelProperties->getFirstLevelWill()); self::assertEquals($expectedWill, $firstLevelProperties->getFirstLevelWill()->getValue()); self::assertSame(max(0, $will - 3), $firstLevelProperties->getWillLossBecauseOfLimit()); $expectedIntelligence = min($intelligence, 3); self::assertInstanceOf(Intelligence::class, $firstLevelProperties->getFirstLevelIntelligence()); self::assertEquals($expectedIntelligence, $firstLevelProperties->getFirstLevelIntelligence()->getValue()); self::assertSame(max(0, $intelligence - 3), $firstLevelProperties->getIntelligenceLossBecauseOfLimit()); $expectedCharisma = min($charisma, 3) + 1; /* female */ self::assertInstanceOf(Charisma::class, $firstLevelProperties->getFirstLevelCharisma()); self::assertEquals($expectedCharisma, $firstLevelProperties->getFirstLevelCharisma()->getValue()); self::assertSame(max(0, $charisma - 3), $firstLevelProperties->getCharismaLossBecauseOfLimit()); $expectedSize = -1; /* female */ if ($strength === 0) { $expectedSize--; } else { if ($strength > 1) { $expectedSize++; } } self::assertInstanceOf(Size::class, $firstLevelProperties->getFirstLevelSize()); self::assertSame($expectedSize, $firstLevelProperties->getFirstLevelSize()->getValue()); self::assertSame($weightInKgAdjustment, $firstLevelProperties->getFirstLevelWeightInKgAdjustment()); self::assertEquals(WeightInKg::getIt(70 + $weightInKgAdjustment->getValue()), $firstLevelProperties->getFirstLevelWeightInKg()); self::assertSame($heightInCmAdjustment, $firstLevelProperties->getFirstLevelHeightInCmAdjustment()); self::assertSame($heightInCm = HeightInCm::getIt(180 + $heightInCmAdjustment->getValue()), $firstLevelProperties->getFirstLevelHeightInCm()); self::assertEquals(new Height($heightInCm, $tables->getDistanceTable()), $firstLevelProperties->getFirstLevelHeight()); self::assertSame($age, $firstLevelProperties->getFirstLevelAge()); }