/**
  * @test
  * @expectedException \DrdPlus\Person\ProfessionLevels\Exceptions\InvalidZeroLevelRank
  * @expectedExceptionMessageRegExp ~[^\d]0[^\d]~
  */
 public function I_can_not_create_it_with_higher_level_thank_zero()
 {
     $professionZeroLevel = ProfessionZeroLevel::createZeroLevel($commoner = Commoner::getIt());
     $reflection = new \ReflectionClass(ProfessionZeroLevel::class);
     /** @see \DrdPlus\Person\ProfessionLevels\ProfessionLevel::__construct */
     $constructor = $reflection->getMethod('__construct');
     $constructor->setAccessible(true);
     $constructor->invokeArgs($professionZeroLevel, [$commoner, LevelRank::getIt(1), Strength::getIt(0), Agility::getIt(0), Knack::getIt(0), Will::getIt(0), Intelligence::getIt(0), Charisma::getIt(0)]);
 }
 /**
  * @param $agility
  * @param $knack
  * @param $intelligence
  * @param $charisma
  * @return BaseProperties
  */
 private function createBaseProperties($agility, $knack = 0, $intelligence = 0, $charisma = 0)
 {
     $properties = \Mockery::mock(BaseProperties::class);
     $properties->shouldReceive('getAgility')->andReturn(Agility::getIt($agility));
     $properties->shouldReceive('getKnack')->andReturn(Knack::getIt($knack));
     $properties->shouldReceive('getIntelligence')->andReturn(Intelligence::getIt($intelligence));
     $properties->shouldReceive('getCharisma')->andReturn(Charisma::getIt($charisma));
     return $properties;
 }
 public function __construct(ProfessionLevels $professionLevels)
 {
     $this->nextLevelsStrength = Strength::getIt($professionLevels->getNextLevelsStrengthModifier());
     $this->nextLevelsAgility = Agility::getIt($professionLevels->getNextLevelsAgilityModifier());
     $this->nextLevelsKnack = Knack::getIt($professionLevels->getNextLevelsKnackModifier());
     $this->nextLevelsWill = Will::getIt($professionLevels->getNextLevelsWillModifier());
     $this->nextLevelsIntelligence = Intelligence::getIt($professionLevels->getNextLevelsIntelligenceModifier());
     $this->nextLevelsCharisma = Charisma::getIt($professionLevels->getNextLevelsCharismaModifier());
 }
 /**
  * @test
  */
 public function I_can_create_it()
 {
     $zeroLevel = $this->createZeroLevel();
     $firstLevel = $this->createFirstLevel('fighter');
     $withFirstLevelOnly = new ProfessionLevels($zeroLevel, $firstLevel);
     self::assertNotNull($withFirstLevelOnly);
     $anotherInstance = ProfessionLevels::createIt($zeroLevel, $firstLevel);
     self::assertEquals($withFirstLevelOnly, $anotherInstance);
     $yetAnotherInstance = ProfessionLevels::createIt($zeroLevel, $firstLevel);
     self::assertNotSame($anotherInstance, $yetAnotherInstance);
     $withExplicitlyEmptyNextLevels = ProfessionLevels::createIt($zeroLevel, $firstLevel, []);
     self::assertEquals($withFirstLevelOnly, $withExplicitlyEmptyNextLevels);
     $withNextLevels = ProfessionLevels::createIt($zeroLevel, $firstLevel, $nextLevels = [ProfessionNextLevel::createNextLevel(Fighter::getIt(), LevelRank::getIt(2), Strength::getIt(1), Agility::getIt(0), Knack::getIt(0), Will::getIt(0), Intelligence::getIt(1), Charisma::getIt(0))]);
     self::assertNotEquals($withFirstLevelOnly, $withNextLevels);
 }
 /**
  * @param Commoner $commoner
  * @param \DateTimeImmutable|null $levelUpAt
  * @return ProfessionZeroLevel
  * @throws Exceptions\InvalidZeroLevelRank
  */
 public static function createZeroLevel(Commoner $commoner, \DateTimeImmutable $levelUpAt = null)
 {
     /** @noinspection ExceptionsAnnotatingAndHandlingInspection */
     return new static($commoner, new LevelRank(0), Strength::getIt(0), Agility::getIt(0), Knack::getIt(0), Will::getIt(0), Intelligence::getIt(0), Charisma::getIt(0), $levelUpAt);
 }
 private function setUpBaseProperties(Race $race, GenderCode $genderCode, ExceptionalityProperties $exceptionalityProperties, ProfessionLevels $professionLevels, Tables $tables)
 {
     $propertyValues = [];
     foreach (PropertyCode::getBasePropertyPossibleValues() as $basePropertyCode) {
         $propertyValues[$basePropertyCode] = $this->calculateFirstLevelBaseProperty($basePropertyCode, $race, $genderCode, $tables, $exceptionalityProperties, $professionLevels);
     }
     $this->firstLevelUnlimitedStrength = Strength::getIt($propertyValues[Strength::STRENGTH]);
     $this->firstLevelStrength = $this->getLimitedProperty($race, $genderCode, $tables, $this->firstLevelUnlimitedStrength);
     $this->firstLevelUnlimitedAgility = Agility::getIt($propertyValues[Agility::AGILITY]);
     $this->firstLevelAgility = $this->getLimitedProperty($race, $genderCode, $tables, $this->firstLevelUnlimitedAgility);
     $this->firstLevelUnlimitedKnack = Knack::getIt($propertyValues[Knack::KNACK]);
     $this->firstLevelKnack = $this->getLimitedProperty($race, $genderCode, $tables, $this->firstLevelUnlimitedKnack);
     $this->firstLevelUnlimitedWill = Will::getIt($propertyValues[Will::WILL]);
     $this->firstLevelWill = $this->getLimitedProperty($race, $genderCode, $tables, $this->firstLevelUnlimitedWill);
     $this->firstLevelUnlimitedIntelligence = Intelligence::getIt($propertyValues[Intelligence::INTELLIGENCE]);
     $this->firstLevelIntelligence = $this->getLimitedProperty($race, $genderCode, $tables, $this->firstLevelUnlimitedIntelligence);
     $this->firstLevelUnlimitedCharisma = Charisma::getIt($propertyValues[Charisma::CHARISMA]);
     $this->firstLevelCharisma = $this->getLimitedProperty($race, $genderCode, $tables, $this->firstLevelUnlimitedCharisma);
 }
 /**
  * @param string $propertyCodeTooHigh
  *
  * @test
  * @dataProvider providePropertyCodeOneByOne
  * @expectedException \DrdPlus\Person\ProfessionLevels\Exceptions\TooHighNextLevelPropertyIncrement
  */
 public function I_can_not_create_next_level_with_too_high_property_increment($propertyCodeTooHigh)
 {
     ProfessionNextLevel::createNextLevel($this->createProfession(ProfessionCode::FIGHTER), $levelRank = LevelRank::getIt(2), Strength::getIt($propertyCodeTooHigh === Strength::STRENGTH ? 2 : 0), Agility::getIt($propertyCodeTooHigh === Agility::AGILITY ? 2 : 0), Knack::getIt($propertyCodeTooHigh === Knack::KNACK ? 2 : 0), Will::getIt($propertyCodeTooHigh === Will::WILL ? 2 : 0), Intelligence::getIt($propertyCodeTooHigh === Intelligence::INTELLIGENCE ? 2 : 0), Charisma::getIt($propertyCodeTooHigh === Charisma::CHARISMA ? 2 : 0));
 }
 /**
  * @param Race $race
  * @param GenderCode $genderCode
  * @param ExceptionalityProperties $exceptionalityProperties
  * @param ProfessionLevels $professionLevels
  * @param WeightInKg $weightInKgAdjustment
  * @param HeightInCm $heightInCm
  * @param Age $age
  * @param Tables $tables
  * @throws Exceptions\TooLowStrengthAdjustment
  */
 public function __construct(Race $race, GenderCode $genderCode, ExceptionalityProperties $exceptionalityProperties, ProfessionLevels $professionLevels, WeightInKg $weightInKgAdjustment, HeightInCm $heightInCm, Age $age, Tables $tables)
 {
     $this->firstLevelProperties = new FirstLevelProperties($race, $genderCode, $exceptionalityProperties, $professionLevels, $weightInKgAdjustment, $heightInCm, $age, $tables);
     $this->nextLevelsProperties = new NextLevelsProperties($professionLevels);
     $this->strength = Strength::getIt($this->firstLevelProperties->getFirstLevelStrength()->getValue() + $this->nextLevelsProperties->getNextLevelsStrength()->getValue());
     $this->agility = Agility::getIt($this->firstLevelProperties->getFirstLevelAgility()->getValue() + $this->nextLevelsProperties->getNextLevelsAgility()->getValue());
     $this->knack = Knack::getIt($this->firstLevelProperties->getFirstLevelKnack()->getValue() + $this->nextLevelsProperties->getNextLevelsKnack()->getValue());
     $this->will = Will::getIt($this->firstLevelProperties->getFirstLevelWill()->getValue() + $this->nextLevelsProperties->getNextLevelsWill()->getValue());
     $this->intelligence = Intelligence::getIt($this->firstLevelProperties->getFirstLevelIntelligence()->getValue() + $this->nextLevelsProperties->getNextLevelsIntelligence()->getValue());
     $this->charisma = Charisma::getIt($this->firstLevelProperties->getFirstLevelCharisma()->getValue() + $this->nextLevelsProperties->getNextLevelsCharisma()->getValue());
     // delivered properties
     $this->toughness = new Toughness($this->getStrength(), $race->getRaceCode(), $race->getSubraceCode(), $tables->getRacesTable());
     $this->endurance = new Endurance($this->getStrength(), $this->getWill());
     $this->speed = new Speed($this->getStrength(), $this->getAgility(), $this->getHeight());
     $this->senses = new Senses($this->getKnack(), RaceCode::getIt($race->getRaceCode()), SubRaceCode::getIt($race->getSubraceCode()), $tables->getRacesTable());
     // aspects of visage
     $this->beauty = new Beauty($this->getAgility(), $this->getKnack(), $this->getCharisma());
     $this->dangerousness = new Dangerousness($this->getStrength(), $this->getWill(), $this->getCharisma());
     $this->dignity = new Dignity($this->getIntelligence(), $this->getWill(), $this->getCharisma());
     /** @noinspection ExceptionsAnnotatingAndHandlingInspection */
     $this->fightNumber = new FightNumber(ProfessionCode::getIt($professionLevels->getFirstLevel()->getProfession()->getValue()), $this, $this->getHeight());
     $this->attack = new Attack($this->getAgility());
     $this->shooting = new Shooting($this->getKnack());
     $this->defenseNumber = new DefenseNumber($this->getAgility());
     $this->defenseAgainstShooting = new DefenseNumberAgainstShooting($this->getDefenseNumber(), $this->getSize());
     $this->woundsLimit = new WoundBoundary($this->getToughness(), $tables->getWoundsTable());
     $this->fatigueLimit = new FatigueBoundary($this->getEndurance(), $tables->getFatigueTable());
 }
 /**
  * @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());
 }
 /**
  * @return array
  */
 public static function createEntities()
 {
     $professionLevels = new ProfessionLevels(ProfessionZeroLevel::createZeroLevel(Commoner::getIt()), ProfessionFirstLevel::createFirstLevel($profession = Theurgist::getIt()));
     $professionLevels->addLevel(ProfessionNextLevel::createNextLevel($profession, LevelRank::getIt(2), Strength::getIt(1), Agility::getIt(0), Knack::getIt(0), Will::getIt(0), Intelligence::getIt(1), Charisma::getIt(0)));
     return [ProfessionZeroLevel::createZeroLevel(Commoner::getIt()), ProfessionFirstLevel::createFirstLevel(Fighter::getIt()), ProfessionNextLevel::createNextLevel(Wizard::getIt(), LevelRank::getIt(2), Strength::getIt(1), Agility::getIt(1), Knack::getIt(0), Will::getIt(0), Intelligence::getIt(0), Charisma::getIt(0)), $professionLevels];
 }
 /**
  * @param ExceptionalityFate $fate
  * @param ProfessionLevel $professionLevel
  * @param int $chosenStrengthValue
  * @param int $chosenAgilityValue
  * @param int $chosenKnackValue
  * @param int $chosenWillValue
  * @param int $chosenIntelligenceValue
  * @param int $chosenCharismaValue
  * @return ChosenProperties
  */
 public function createChosenProperties(ExceptionalityFate $fate, ProfessionLevel $professionLevel, $chosenStrengthValue, $chosenAgilityValue, $chosenKnackValue, $chosenWillValue, $chosenIntelligenceValue, $chosenCharismaValue)
 {
     $this->checkChosenProperties($chosenStrength = Strength::getIt($chosenStrengthValue), $chosenAgility = Agility::getIt($chosenAgilityValue), $chosenKnack = Knack::getIt($chosenKnackValue), $chosenWill = Will::getIt($chosenWillValue), $chosenIntelligence = Intelligence::getIt($chosenIntelligenceValue), $chosenCharisma = Charisma::getIt($chosenCharismaValue), $professionLevel, $fate);
     return new ChosenProperties($chosenStrength, $chosenAgility, $chosenKnack, $chosenWill, $chosenIntelligence, $chosenCharisma);
 }
 /**
  * @param Profession $profession
  * @param \DateTimeImmutable|null $levelUpAt
  * @return ProfessionFirstLevel
  * @throws \DrdPlus\Person\ProfessionLevels\Exceptions\InvalidFirstLevelPropertyValue
  */
 public static function createFirstLevel(Profession $profession, \DateTimeImmutable $levelUpAt = null)
 {
     return new static($profession, new LevelRank(1), Strength::getIt(self::getBasePropertyFirstLevelModifier(Strength::STRENGTH, $profession)), Agility::getIt(self::getBasePropertyFirstLevelModifier(Agility::AGILITY, $profession)), Knack::getIt(self::getBasePropertyFirstLevelModifier(Knack::KNACK, $profession)), Will::getIt(self::getBasePropertyFirstLevelModifier(Will::WILL, $profession)), Intelligence::getIt(self::getBasePropertyFirstLevelModifier(Intelligence::INTELLIGENCE, $profession)), Charisma::getIt(self::getBasePropertyFirstLevelModifier(Charisma::CHARISMA, $profession)), $levelUpAt);
 }
 /**
  * @param int|IntegerInterface $knackValue
  * @return Knack
  */
 public function createKnack($knackValue)
 {
     return Knack::getIt($knackValue);
 }
 public static function createSkillsEntity(Tables $tables)
 {
     return Skills::createSkills(ProfessionLevels::createIt(ProfessionFirstLevel::createFirstLevel($profession = Fighter::getIt()), [ProfessionNextLevel::createNextLevel($profession, LevelRank::getIt(2), Strength::getIt(0), Agility::getIt(1), Knack::getIt(0), Will::getIt(0), Intelligence::getIt(1), Charisma::getIt(0))]), BackgroundSkillPoints::getIt(2, Heritage::getIt(7)), $tables, new PhysicalSkills(), new PsychicalSkills(), new CombinedSkills());
 }