Passed
Push — master ( 7a48d2...d0f71f )
by Jakub
12:49
created

CharacterEffect::setDuration()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 4.125

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 8
rs 10
ccs 2
cts 4
cp 0.5
cc 3
nc 2
nop 1
crap 4.125
1
<?php
2
declare(strict_types=1);
3
4
namespace HeroesofAbenez\Combat;
5
6
use Nexendrie\Utils\Constants;
7
use Symfony\Component\OptionsResolver\OptionsResolver;
8
9
/**
10
 * Data structure for effect on character
11
 *
12
 * @author Jakub Konečný
13
 * @property int|string $duration
14
 * @method void onApply(Character $character, CharacterEffect $effect)
15
 * @method void onRemove(Character $character, CharacterEffect $effect)
16
 */
17 1
class CharacterEffect
18
{
19
    use \Nette\SmartObject;
20
21
    public const DURATION_COMBAT = "combat";
22
    public const DURATION_FOREVER = "forever";
23
24
    public readonly string $id;
25
    public readonly string $type;
26
    public readonly string $stat;
27
    public readonly int $value;
28
    public readonly bool $valueAbsolute;
29
    protected int|string $duration;
30
    /** @var callable[] */
31
    public array $onApply = [];
32
    /** @var callable[] */
33
    public array $onRemove = [];
34
35
    public function __construct(array $effect)
36
    {
37 1
        $resolver = new OptionsResolver();
38 1
        $this->configureOptions($resolver);
39 1
        $effect = $resolver->resolve($effect);
40 1
        if (!in_array($effect["type"], SkillSpecial::NO_STAT_TYPES, true) && $effect["stat"] === "") {
41
            throw new \InvalidArgumentException("The option stat with value '' is invalid.");
42
        }
43 1
        $this->id = $effect["id"];
44 1
        $this->type = $effect["type"];
45 1
        $this->stat = $effect["stat"];
46 1
        $this->value = $effect["value"];
47 1
        $this->valueAbsolute = $effect["valueAbsolute"];
48 1
        $this->duration = $effect["duration"];
49 1
        $this->registerDefaultHandlers();
50 1
    }
51
52
    protected function registerDefaultHandlers(): void
53
    {
54 1
        $this->onApply[] = function (Character $character, self $effect): void {
55 1
            $character->recalculateStats();
56 1
            if ($effect->stat === Character::STAT_MAX_HITPOINTS) {
57 1
                $character->heal($effect->value);
58
            }
59 1
        };
60 1
        $this->onRemove[] = function (Character $character, self $effect): void {
61 1
            $character->recalculateStats();
62 1
            if ($effect->stat === Character::STAT_MAX_HITPOINTS) {
63 1
                $character->harm($effect->value);
64
            }
65 1
        };
66 1
    }
67
68
    protected function configureOptions(OptionsResolver $resolver): void
69
    {
70 1
        $allStats = ["id", "type", "value", "valueAbsolute", "duration", "stat",];
71 1
        $resolver->setRequired($allStats);
72 1
        $resolver->setAllowedTypes("id", "string");
73 1
        $resolver->setAllowedTypes("type", "string");
74 1
        $resolver->setAllowedValues("type", function (string $value): bool {
75 1
            return in_array($value, $this->getAllowedTypes(), true);
76 1
        });
77 1
        $resolver->setAllowedTypes("stat", "string");
78 1
        $resolver->setDefault("stat", "");
79 1
        $resolver->setAllowedValues("stat", function (string $value): bool {
80 1
            return $value === "" || in_array($value, $this->getAllowedStats(), true);
81 1
        });
82 1
        $resolver->setAllowedTypes("value", "integer");
83 1
        $resolver->setAllowedTypes("valueAbsolute", "bool");
84 1
        $resolver->setDefault("value", 0);
85 1
        $resolver->setAllowedTypes("duration", ["string", "integer"]);
86 1
        $resolver->setAllowedValues("duration", function ($value): bool {
87 1
            return (in_array($value, $this->getDurations(), true)) || ($value > 0);
88 1
        });
89 1
    }
90
91
    protected function getAllowedStats(): array
92
    {
93 1
        return Constants::getConstantsValues(Character::class, "STAT_");
94
    }
95
96
    /**
97
     * @return string[]
98
     */
99
    protected function getAllowedTypes(): array
100
    {
101 1
        return Constants::getConstantsValues(SkillSpecial::class, "TYPE_");
102
    }
103
104
    /**
105
     * @return string[]
106
     */
107
    protected function getDurations(): array
108
    {
109 1
        return Constants::getConstantsValues(static::class, "DURATION_");
110
    }
111
112
    protected function getDuration(): int|string
113
    {
114 1
        return $this->duration;
115
    }
116
117
    /**
118
     * @throws \InvalidArgumentException
119
     */
120
    protected function setDuration(string|int $value): void
121
    {
122 1
        if (!is_int($value) && !in_array($value, $this->getDurations(), true)) {
123
            throw new \InvalidArgumentException(
124
                "Invalid value set to CharacterEffect::\$duration. Expected string or integer."
125
            );
126
        }
127 1
        $this->duration = $value;
128 1
    }
129
}
130