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 | use \Nette\SmartObject; |
||
19 | |||
20 | public const DURATION_COMBAT = "combat"; |
||
21 | public const DURATION_FOREVER = "forever"; |
||
22 | |||
23 | public readonly string $id; |
||
24 | public readonly string $type; |
||
25 | public readonly string $stat; |
||
26 | public readonly int $value; |
||
27 | public readonly bool $valueAbsolute; |
||
28 | protected int|string $duration; |
||
29 | /** @var callable[] */ |
||
30 | public array $onApply = []; |
||
31 | /** @var callable[] */ |
||
32 | public array $onRemove = []; |
||
33 | |||
34 | public function __construct(array $effect) { |
||
35 | 1 | $resolver = new OptionsResolver(); |
|
36 | 1 | $this->configureOptions($resolver); |
|
37 | 1 | $effect = $resolver->resolve($effect); |
|
38 | 1 | if(!in_array($effect["type"], SkillSpecial::NO_STAT_TYPES, true) && $effect["stat"] === "") { |
|
39 | throw new \InvalidArgumentException("The option stat with value '' is invalid."); |
||
40 | } |
||
41 | 1 | $this->id = $effect["id"]; |
|
42 | 1 | $this->type = $effect["type"]; |
|
43 | 1 | $this->stat = $effect["stat"]; |
|
44 | 1 | $this->value = $effect["value"]; |
|
45 | 1 | $this->valueAbsolute = $effect["valueAbsolute"]; |
|
46 | 1 | $this->duration = $effect["duration"]; |
|
47 | 1 | $this->registerDefaultHandlers(); |
|
48 | 1 | } |
|
49 | |||
50 | protected function registerDefaultHandlers(): void { |
||
51 | 1 | $this->onApply[] = function(Character $character, self $effect): void { |
|
52 | 1 | $character->recalculateStats(); |
|
53 | 1 | if($effect->stat === Character::STAT_MAX_HITPOINTS) { |
|
54 | 1 | $character->heal($effect->value); |
|
55 | } |
||
56 | 1 | }; |
|
57 | 1 | $this->onRemove[] = function(Character $character, self $effect): void { |
|
58 | 1 | $character->recalculateStats(); |
|
59 | 1 | if($effect->stat === Character::STAT_MAX_HITPOINTS) { |
|
60 | 1 | $character->harm($effect->value); |
|
61 | } |
||
62 | 1 | }; |
|
63 | 1 | } |
|
64 | |||
65 | protected function configureOptions(OptionsResolver $resolver): void { |
||
66 | 1 | $allStats = ["id", "type", "value", "valueAbsolute", "duration", "stat", ]; |
|
67 | 1 | $resolver->setRequired($allStats); |
|
68 | 1 | $resolver->setAllowedTypes("id", "string"); |
|
69 | 1 | $resolver->setAllowedTypes("type", "string"); |
|
70 | 1 | $resolver->setAllowedValues("type", function(string $value): bool { |
|
71 | 1 | return in_array($value, $this->getAllowedTypes(), true); |
|
72 | 1 | }); |
|
73 | 1 | $resolver->setAllowedTypes("stat", "string"); |
|
74 | 1 | $resolver->setDefault("stat", ""); |
|
75 | 1 | $resolver->setAllowedValues("stat", function(string $value): bool { |
|
76 | 1 | return $value === "" || in_array($value, $this->getAllowedStats(), true); |
|
77 | 1 | }); |
|
78 | 1 | $resolver->setAllowedTypes("value", "integer"); |
|
79 | 1 | $resolver->setAllowedTypes("valueAbsolute", "bool"); |
|
80 | 1 | $resolver->setDefault("value", 0); |
|
81 | 1 | $resolver->setAllowedTypes("duration", ["string", "integer"]); |
|
82 | 1 | $resolver->setAllowedValues("duration", function($value): bool { |
|
83 | 1 | return (in_array($value, $this->getDurations(), true)) || ($value > 0); |
|
84 | 1 | }); |
|
85 | 1 | } |
|
86 | |||
87 | protected function getAllowedStats(): array { |
||
88 | 1 | return Constants::getConstantsValues(Character::class, "STAT_"); |
|
89 | } |
||
90 | |||
91 | /** |
||
92 | * @return string[] |
||
93 | */ |
||
94 | protected function getAllowedTypes(): array { |
||
95 | 1 | return Constants::getConstantsValues(SkillSpecial::class, "TYPE_"); |
|
96 | } |
||
97 | |||
98 | /** |
||
99 | * @return string[] |
||
100 | */ |
||
101 | protected function getDurations(): array { |
||
102 | 1 | return Constants::getConstantsValues(static::class, "DURATION_"); |
|
103 | } |
||
104 | |||
105 | protected function getDuration(): int|string { |
||
106 | 1 | return $this->duration; |
|
107 | } |
||
108 | |||
109 | /** |
||
110 | * @throws \InvalidArgumentException |
||
111 | */ |
||
112 | protected function setDuration(string|int $value): void { |
||
113 | 1 | if(!is_int($value) && !in_array($value, $this->getDurations(), true)) { |
|
114 | throw new \InvalidArgumentException("Invalid value set to CharacterEffect::\$duration. Expected string or integer."); |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
115 | } |
||
116 | 1 | $this->duration = $value; |
|
117 | 1 | } |
|
118 | } |
||
119 | ?> |