jaroslavtyc/drd-plus-properties-by-levels

View on GitHub
DrdPlus/PropertiesByLevels/FirstLevelProperties.php

Summary

Maintainability
C
1 day
Test Coverage
<?php declare(strict_types=1);

namespace DrdPlus\PropertiesByLevels;

use DrdPlus\Codes\GenderCode;
use DrdPlus\Codes\Properties\PropertyCode;
use DrdPlus\Person\ProfessionLevels\ProfessionLevels;
use DrdPlus\BaseProperties\Agility;
use DrdPlus\BaseProperties\BaseProperty;
use DrdPlus\BaseProperties\Charisma;
use DrdPlus\BaseProperties\Intelligence;
use DrdPlus\BaseProperties\Knack;
use DrdPlus\BaseProperties\Strength;
use DrdPlus\BaseProperties\Will;
use DrdPlus\Properties\Body\Age;
use DrdPlus\Properties\Body\Height;
use DrdPlus\Properties\Body\HeightInCm;
use DrdPlus\Properties\Body\Size;
use DrdPlus\Properties\Body\BodyWeightInKg;
use DrdPlus\PropertiesByFate\PropertiesByFate;
use DrdPlus\Races\Race;
use DrdPlus\Tables\Tables;
use Granam\Strict\Object\StrictObject;

class FirstLevelProperties extends StrictObject
{
    const INITIAL_PROPERTY_INCREASE_LIMIT = 3;

    /** @var PropertiesByFate */
    private $propertiesByFate;
    /** @var Strength */
    private $firstLevelUnlimitedStrength;
    /** @var Strength */
    private $firstLevelStrength;
    /** @var Agility */
    private $firstLevelUnlimitedAgility;
    /** @var Agility */
    private $firstLevelAgility;
    /** @var Knack */
    private $firstLevelUnlimitedKnack;
    /** @var Knack */
    private $firstLevelKnack;
    /** @var Will */
    private $firstLevelUnlimitedWill;
    /** @var Will */
    private $firstLevelWill;
    /** @var Intelligence */
    private $firstLevelUnlimitedIntelligence;
    /** @var Intelligence */
    private $firstLevelIntelligence;
    /** @var Charisma */
    private $firstLevelUnlimitedCharisma;
    /** @var Charisma */
    private $firstLevelCharisma;
    /** @var BodyWeightInKg */
    private $firstLevelWeightInKgAdjustment;
    /** @var BodyWeightInKg */
    private $firstLevelWeightInKg;
    /** @var Size */
    private $firstLevelSize;
    /** @var HeightInCm */
    private $firstLevelHeightInCmAdjustment;
    /** @var HeightInCm */
    private $firstLevelHeightInCm;
    /** @var Height */
    private $firstLevelHeight;
    /** @var Age */
    private $firstLevelAge;

    /**
     * @param Race $race
     * @param GenderCode $genderCode
     * @param PropertiesByFate $propertiesByFate
     * @param ProfessionLevels $professionLevels
     * @param BodyWeightInKg $weightInKgAdjustment
     * @param HeightInCm $heightInCmAdjustment
     * @param Age $age
     * @param Tables $tables
     * @throws Exceptions\TooLowStrengthAdjustment
     */
    public function __construct(
        Race $race,
        GenderCode $genderCode,
        PropertiesByFate $propertiesByFate,
        ProfessionLevels $professionLevels,
        BodyWeightInKg $weightInKgAdjustment,
        HeightInCm $heightInCmAdjustment,
        Age $age,
        Tables $tables
    )
    {
        $this->propertiesByFate = $propertiesByFate;
        $this->setUpBaseProperties($race, $genderCode, $propertiesByFate, $professionLevels, $tables);
        $this->firstLevelWeightInKgAdjustment = $weightInKgAdjustment;
        $this->firstLevelWeightInKg = $this->createFirstLevelBodyWeightInKg(
            $race,
            $genderCode,
            $weightInKgAdjustment,
            $tables
        );
        $this->firstLevelSize = $this->createFirstLevelSize(
            $race,
            $genderCode,
            $tables,
            $propertiesByFate,
            $professionLevels
        );
        $this->firstLevelHeightInCmAdjustment = $heightInCmAdjustment;
        $this->firstLevelHeightInCm = HeightInCm::getIt(
            $race->getHeightInCm($tables) + $heightInCmAdjustment->getValue()
        );
        $this->firstLevelHeight = Height::getIt($this->firstLevelHeightInCm, $tables);
        $this->firstLevelAge = $age;
    }

    /**
     * @param Race $race
     * @param GenderCode $genderCode
     * @param PropertiesByFate $propertiesByFate
     * @param ProfessionLevels $professionLevels
     * @param Tables $tables
     */
    private function setUpBaseProperties(
        Race $race,
        GenderCode $genderCode,
        PropertiesByFate $propertiesByFate,
        ProfessionLevels $professionLevels,
        Tables $tables
    )
    {
        $propertyValues = [];
        foreach (PropertyCode::getBasePropertyPossibleValues() as $basePropertyCode) {
            /** @noinspection ExceptionsAnnotatingAndHandlingInspection */
            $propertyValues[$basePropertyCode] = $this->calculateFirstLevelBaseProperty(
                PropertyCode::getIt($basePropertyCode),
                $race,
                $genderCode,
                $tables,
                $propertiesByFate,
                $professionLevels
            );
        }

        $this->firstLevelUnlimitedStrength = Strength::getIt($propertyValues[PropertyCode::STRENGTH]);
        /** @noinspection ExceptionsAnnotatingAndHandlingInspection */
        $this->firstLevelStrength = $this->getLimitedProperty($race, $genderCode, $tables, $this->firstLevelUnlimitedStrength);

        $this->firstLevelUnlimitedAgility = Agility::getIt($propertyValues[PropertyCode::AGILITY]);
        /** @noinspection ExceptionsAnnotatingAndHandlingInspection */
        $this->firstLevelAgility = $this->getLimitedProperty($race, $genderCode, $tables, $this->firstLevelUnlimitedAgility);

        $this->firstLevelUnlimitedKnack = Knack::getIt($propertyValues[PropertyCode::KNACK]);
        /** @noinspection ExceptionsAnnotatingAndHandlingInspection */
        $this->firstLevelKnack = $this->getLimitedProperty($race, $genderCode, $tables, $this->firstLevelUnlimitedKnack);

        $this->firstLevelUnlimitedWill = Will::getIt($propertyValues[PropertyCode::WILL]);
        /** @noinspection ExceptionsAnnotatingAndHandlingInspection */
        $this->firstLevelWill = $this->getLimitedProperty($race, $genderCode, $tables, $this->firstLevelUnlimitedWill);

        $this->firstLevelUnlimitedIntelligence = Intelligence::getIt($propertyValues[PropertyCode::INTELLIGENCE]);
        /** @noinspection ExceptionsAnnotatingAndHandlingInspection */
        $this->firstLevelIntelligence = $this->getLimitedProperty($race, $genderCode, $tables, $this->firstLevelUnlimitedIntelligence);

        $this->firstLevelUnlimitedCharisma = Charisma::getIt($propertyValues[PropertyCode::CHARISMA]);
        /** @noinspection ExceptionsAnnotatingAndHandlingInspection */
        $this->firstLevelCharisma = $this->getLimitedProperty($race, $genderCode, $tables, $this->firstLevelUnlimitedCharisma);
    }

    /**
     * @param PropertyCode $propertyCode
     * @param Race $race
     * @param GenderCode $genderCode
     * @param Tables $tables
     * @param PropertiesByFate $propertiesByFate
     * @param ProfessionLevels $professionLevels
     * @return int
     * @throws \DrdPlus\Races\Exceptions\UnknownPropertyCode
     */
    private function calculateFirstLevelBaseProperty(
        PropertyCode $propertyCode,
        Race $race,
        GenderCode $genderCode,
        Tables $tables,
        PropertiesByFate $propertiesByFate,
        ProfessionLevels $professionLevels
    ): int
    {
        /** @noinspection ExceptionsAnnotatingAndHandlingInspection */
        return
            $race->getProperty($propertyCode, $genderCode, $tables)
            + $propertiesByFate->getProperty($propertyCode)->getValue()
            + $professionLevels->getFirstLevelPropertyModifier($propertyCode);
    }

    /**
     * @param Race $race
     * @param GenderCode $genderCode
     * @param Tables $tables
     * @param BaseProperty $baseProperty
     * @return BaseProperty
     * @throws \DrdPlus\Races\Exceptions\UnknownPropertyCode
     */
    private function getLimitedProperty(Race $race, GenderCode $genderCode, Tables $tables, BaseProperty $baseProperty): BaseProperty
    {
        $limit = $this->getBasePropertyLimit($race, $genderCode, $tables, $baseProperty);
        if ($baseProperty->getValue() <= $limit) {
            return $baseProperty;
        }

        return $baseProperty::getIt($limit);
    }

    /**
     * @param Race $race
     * @param GenderCode $genderCode
     * @param Tables $tables
     * @param BaseProperty $baseProperty
     * @return int
     * @throws \DrdPlus\Races\Exceptions\UnknownPropertyCode
     */
    private function getBasePropertyLimit(Race $race, GenderCode $genderCode, Tables $tables, BaseProperty $baseProperty): int
    {
        return $race->getProperty($baseProperty->getCode(), $genderCode, $tables) + self::INITIAL_PROPERTY_INCREASE_LIMIT;
    }

    /**
     * @return PropertiesByFate
     */
    public function getPropertiesByFate(): PropertiesByFate
    {
        return $this->propertiesByFate;
    }

    /**
     * @return int 0+
     */
    public function getStrengthLossBecauseOfLimit(): int
    {
        return $this->firstLevelUnlimitedStrength->getValue() - $this->getFirstLevelStrength()->getValue();
    }

    /**
     * @return int 0+
     */
    public function getAgilityLossBecauseOfLimit(): int
    {
        return $this->firstLevelUnlimitedAgility->getValue() - $this->getFirstLevelAgility()->getValue();
    }

    /**
     * @return int 0+
     */
    public function getKnackLossBecauseOfLimit(): int
    {
        return $this->firstLevelUnlimitedKnack->getValue() - $this->getFirstLevelKnack()->getValue();
    }

    /**
     * @return int 0+
     */
    public function getWillLossBecauseOfLimit(): int
    {
        return $this->firstLevelUnlimitedWill->getValue() - $this->getFirstLevelWill()->getValue();
    }

    /**
     * @return int 0+
     */
    public function getIntelligenceLossBecauseOfLimit(): int
    {
        return $this->firstLevelUnlimitedIntelligence->getValue() - $this->getFirstLevelIntelligence()->getValue();
    }

    /**
     * @return int 0+
     */
    public function getCharismaLossBecauseOfLimit(): int
    {
        return $this->firstLevelUnlimitedCharisma->getValue() - $this->getFirstLevelCharisma()->getValue();
    }

    /**
     * @param Race $race
     * @param GenderCode $genderCode
     * @param BodyWeightInKg $weightInKgAdjustment
     * @param Tables $tables
     * @return BodyWeightInKg
     */
    private function createFirstLevelBodyWeightInKg(
        Race $race,
        GenderCode $genderCode,
        BodyWeightInKg $weightInKgAdjustment,
        Tables $tables
    ): BodyWeightInKg
    {
        return BodyWeightInKg::getIt($race->getWeightInKg($genderCode, $tables) + $weightInKgAdjustment->getValue());
    }

    /**
     * @param Race $race
     * @param GenderCode $genderCode
     * @param Tables $tables
     * @param PropertiesByFate $propertiesByFate
     * @param ProfessionLevels $professionLevels
     * @return Size
     * @throws Exceptions\TooLowStrengthAdjustment
     */
    private function createFirstLevelSize(
        Race $race,
        GenderCode $genderCode,
        Tables $tables,
        PropertiesByFate $propertiesByFate,
        ProfessionLevels $professionLevels
    ): Size
    {
        // the race bonus is NOT count for adjustment, doesn't count to size change respectively
        $sizeModifierByStrength = $this->getSizeModifierByStrength(
            $propertiesByFate->getStrength()->getValue()
            + $professionLevels->getFirstLevelStrengthModifier()
        );
        $raceSize = $race->getSize($genderCode, $tables);

        return Size::getIt($raceSize + $sizeModifierByStrength);
    }

    /**
     * @param $firstLevelStrengthAdjustment
     * @return int
     * @throws Exceptions\TooLowStrengthAdjustment
     */
    private function getSizeModifierByStrength($firstLevelStrengthAdjustment): int
    {
        if ($firstLevelStrengthAdjustment === 0) {
            return -1;
        }
        if ($firstLevelStrengthAdjustment === 1) {
            return 0;
        }
        if ($firstLevelStrengthAdjustment >= 2) {
            return +1;
        }
        throw new Exceptions\TooLowStrengthAdjustment(
            'First level strength adjustment can not be lesser than zero. Given ' . $firstLevelStrengthAdjustment
        );
    }

    public function getFirstLevelStrength(): Strength
    {
        return $this->firstLevelStrength;
    }

    public function getFirstLevelAgility(): Agility
    {
        return $this->firstLevelAgility;
    }

    public function getFirstLevelKnack(): Knack
    {
        return $this->firstLevelKnack;
    }

    public function getFirstLevelWill(): Will
    {
        return $this->firstLevelWill;
    }

    public function getFirstLevelIntelligence(): Intelligence
    {
        return $this->firstLevelIntelligence;
    }

    public function getFirstLevelCharisma(): Charisma
    {
        return $this->firstLevelCharisma;
    }

    public function getFirstLevelBodyWeightInKgAdjustment(): BodyWeightInKg
    {
        return $this->firstLevelWeightInKgAdjustment;
    }

    public function getFirstLevelWeightInKg(): BodyWeightInKg
    {
        return $this->firstLevelWeightInKg;
    }

    public function getFirstLevelSize(): Size
    {
        return $this->firstLevelSize;
    }

    public function getFirstLevelHeightInCmAdjustment(): HeightInCm
    {
        return $this->firstLevelHeightInCmAdjustment;
    }

    public function getFirstLevelHeightInCm(): HeightInCm
    {
        return $this->firstLevelHeightInCm;
    }

    public function getFirstLevelHeight(): Height
    {
        return $this->firstLevelHeight;
    }

    public function getFirstLevelAge(): Age
    {
        return $this->firstLevelAge;
    }

}