/** * @param RidingAnimalCode $ridingAnimalCode * @param DefianceOfWildPercents $defianceOfWildPercents * @param bool $jumpingAndDangerousMoves * @return int */ public function getDefianceOfWild(RidingAnimalCode $ridingAnimalCode, DefianceOfWildPercents $defianceOfWildPercents, $jumpingAndDangerousMoves) { $defianceOfDomesticated = $this->getDefianceOfDomesticated($ridingAnimalCode, $jumpingAndDangerousMoves); $additionForWild = SumAndRound::round(10 + 2 * $defianceOfWildPercents->getRate()); // 10..12 return $defianceOfDomesticated + $additionForWild; }
/** * @param $terrainCode * @param TerrainDifficultyPercents $difficultyPercents * @return int * @throws \DrdPlus\Tables\Environments\Exceptions\UnknownTerrainCode * @throws \DrdPlus\Tables\Environments\Exceptions\InvalidTerrainCodeFormat */ private function getSpeedMalusValueForTerrain($terrainCode, TerrainDifficultyPercents $difficultyPercents) { // value is zero or negative, so bonus is de facto malus $range = $this->getSpeedMalusValuesRangeForTerrain($terrainCode); $difference = $range[self::IMPASSIBILITY_OF_TERRAIN_TO] - $range[self::IMPASSIBILITY_OF_TERRAIN_FROM]; $addition = $difference * $difficultyPercents->getRate(); return SumAndRound::round($range[self::IMPASSIBILITY_OF_TERRAIN_FROM] + $addition); }
/** * @test */ public function I_get_rounds_to_put_on_armor_related_to_its_protection() { $bodyArmorsTable = new BodyArmorsTable(); foreach (BodyArmorCode::getPossibleValues() as $bodyArmorCode) { if ($bodyArmorCode === BodyArmorCode::WITHOUT_ARMOR) { self::assertFalse($bodyArmorsTable->getRoundsToPutOnOf($bodyArmorCode)); } else { self::assertSame(SumAndRound::ceiledThird($bodyArmorsTable->getProtectionOf($bodyArmorCode)), $bodyArmorsTable->getRoundsToPutOnOf($bodyArmorCode)); } } }
public function provideDistanceAndExpectedModifier() { $testValues = []; $distanceTable = new DistanceTable(); for ($distanceBonus = 1; $distanceBonus < 100; $distanceBonus++) { $distanceInMeters = (new DistanceBonus($distanceBonus, $distanceTable))->getDistance()->getMeters(); $attackNumberModifier = -(SumAndRound::half($distanceBonus) - 9); // PPH page 104 left column $testValues[] = [$distanceInMeters, $attackNumberModifier]; } return $testValues; }
/** * @param string $code * @param Percents $percents * @return int * @throws \DrdPlus\Tables\Partials\Exceptions\UnexpectedPercents * @throws \Granam\Scalar\Tools\Exceptions\WrongParameterType * @throws \DrdPlus\Tables\Partials\Exceptions\RequiredRowNotFound */ protected function getBonusBy($code, Percents $percents) { if ($percents->getValue() > 100 && !$this->canBeMore($code)) { throw new Exceptions\UnexpectedPercents('For ' . ValueDescriber::describe($code) . " can be percents of addition only between zero and one hundred, got {$percents}"); } $bonusFrom = $this->getBonusBorder($code, self::BONUS_FROM); $bonusTo = $this->getBonusBorder($code, self::BONUS_TO); if ($bonusFrom < $bonusTo) { // has to swap start and end list($bonusFrom, $bonusTo) = [$bonusTo, $bonusFrom]; } $difference = $bonusTo - $bonusFrom; $addition = $difference * $percents->getRate(); $totalBonus = $bonusFrom + $addition; return SumAndRound::round($totalBonus); }
/** * @param ProfessionCode $professionCode * @param BaseProperties $baseProperties * @param Height $height * @return int * @throws \DrdPlus\Properties\Combat\Exceptions\UnknownProfession */ private function calculateValue(ProfessionCode $professionCode, BaseProperties $baseProperties, Height $height) { $modifierByHeight = SumAndRound::ceiledThird($height->getValue()) - 2; switch ($professionCode->getValue()) { case ProfessionCode::FIGHTER: return $baseProperties->getAgility()->getValue() + $modifierByHeight; case ProfessionCode::THIEF: case ProfessionCode::RANGER: // same as a thief return SumAndRound::average($baseProperties->getAgility()->getValue(), $baseProperties->getKnack()->getValue()) + $modifierByHeight; case ProfessionCode::WIZARD: case ProfessionCode::THEURGIST: // same as a wizard return SumAndRound::average($baseProperties->getAgility()->getValue(), $baseProperties->getIntelligence()->getValue()) + $modifierByHeight; case ProfessionCode::PRIEST: return SumAndRound::average($baseProperties->getAgility()->getValue(), $baseProperties->getCharisma()->getValue()) + $modifierByHeight; default: throw new Exceptions\UnknownProfession('Unknown profession of code ' . ValueDescriber::describe($professionCode->getValue())); } }
/** * @param Strength $strength * @param Will $will */ public function __construct(Strength $strength, Will $will) { /** @noinspection ExceptionsAnnotatingAndHandlingInspection */ parent::__construct(SumAndRound::average($strength->getValue(), $will->getValue())); }
/** * @test */ public function I_can_get_floored_third() { $number = 5; $this->assertSame(1, SumAndRound::flooredThird($number)); $number = 2.9999; $this->assertSame(0, SumAndRound::flooredThird($number)); $number = 99; $this->assertSame(33, SumAndRound::flooredThird($number)); }
/** * Despite rules this library deducts half of size from defense number, instead of adding to attack number, * because it is more practical from numbers-point-of-view * PPH page 104 right column top * * @param DefenseNumber $defense * @param Size $size */ public function __construct(DefenseNumber $defense, Size $size) { /** @noinspection ExceptionsAnnotatingAndHandlingInspection */ parent::__construct($defense->getValue() - SumAndRound::half($size->getValue())); }
/** * @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()); }
protected function calculateValue($firstPropertyValue, $secondPropertyValue, $charismaValue) { return SumAndRound::average($firstPropertyValue, $secondPropertyValue) + SumAndRound::half($charismaValue); }
/** * Affects activities using strength, agility or knack, see PPH page 113, right column, bottom. * @param Strength $strength * @param Weight $cargoWeight * @return int negative number or zero * @throws \DrdPlus\Tables\Measurements\Partials\Exceptions\BonusRequiresInteger */ public function getMalusFromLoad(Strength $strength, Weight $cargoWeight) { $requiredStrength = $cargoWeight->getBonus()->getValue(); $missingStrength = $requiredStrength - $strength->getValue(); $malus = -SumAndRound::half($missingStrength); // see PPH page 113, right column if ($malus > 0) { return 0; } return $malus; }
/** * @param IntegerInterface $firstProperty * @param IntegerInterface $secondProperty * @param Charisma $charisma */ protected function __construct(IntegerInterface $firstProperty, IntegerInterface $secondProperty, Charisma $charisma) { /** @noinspection ExceptionsAnnotatingAndHandlingInspection */ parent::__construct(SumAndRound::average($firstProperty->getValue(), $secondProperty->getValue()) + SumAndRound::half($charisma->getValue())); }
/** * @param Knack $knack */ public function __construct(Knack $knack) { /** @noinspection ExceptionsAnnotatingAndHandlingInspection */ parent::__construct(SumAndRound::flooredHalf($knack->getValue())); }
/** * @param Speed $speed */ public function __construct(Speed $speed) { /** @noinspection ExceptionsAnnotatingAndHandlingInspection */ parent::__construct(SumAndRound::half($speed->getValue())); }
/** * @param RangedWeaponCode $rangedWeaponCode * @param Speed $speed * @return int * @throws CanNotUseWeaponBecauseOfMissingStrength */ private function getEncounterRangeBonusBySpeed(RangedWeaponCode $rangedWeaponCode, Speed $speed) { if (!$rangedWeaponCode->isThrowingWeapon()) { return 0; } return SumAndRound::half($speed->getValue()); }
/** * @param Strength $strength * @param Agility $agility * @param Height $height */ public function __construct(Strength $strength, Agility $agility, Height $height) { /** @noinspection ExceptionsAnnotatingAndHandlingInspection */ parent::__construct(SumAndRound::average($strength->getValue(), $agility->getValue()) + SumAndRound::ceil($height->getValue() / 3) - 2); }
/** * @param Agility $agility */ public function __construct(Agility $agility) { /** @noinspection ExceptionsAnnotatingAndHandlingInspection */ parent::__construct(SumAndRound::ceiledHalf($agility->getValue())); }