Passed
Push — master ( 05d583...7eb4ad )
by Karthik
06:02
created

ItemOption   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 263
Duplicated Lines 0 %

Test Coverage

Coverage 94.51%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 106
dl 0
loc 263
ccs 86
cts 91
cp 0.9451
rs 9.52
c 1
b 0
f 0
wmc 36

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getSlots() 0 3 1
B generate() 0 43 10
A getCrafts() 0 3 1
A getCraftOptions() 0 3 1
A setCraftOption() 0 16 4
A __construct() 0 19 6
A getSlotOptions() 0 3 1
A setSlotOption() 0 10 3
B extract() 0 49 9
1
<?php
2
3
namespace cyberinferno\Cabal\Helpers;
4
5
use cyberinferno\Cabal\Helpers\Exceptions\InvalidCraftLevelException;
6
use cyberinferno\Cabal\Helpers\Exceptions\InvalidOptionException;
7
use cyberinferno\Cabal\Helpers\Exceptions\MaxOptionException;
8
use cyberinferno\Cabal\Helpers\Exceptions\OptionLimitException;
9
10
/**
11
 * Class ItemOption
12
 *
13
 * Contains methods helpful to generate item option
14
 *
15
 * @package cyberinferno\Cabal\Helpers
16
 * @author Karthik P
17
 */
18
class ItemOption
19
{
20
    const MAX_OPTIONS = 4;
21
22
    const MIN_SLOTS = 0;
23
    const MAX_SLOTS = 4;
24
25
    const MIN_CRAFTS = 0;
26
    const MAX_CRAFTS = 3;
27
28
    const OUTPUT_FORMAT_INTEGER = 'int';
29
    const OUTPUT_FORMAT_HEXADECIMAL = 'hex';
30
31
    /**
32
     * @var int Max number of slots the generated item option will have
33
     */
34
    protected $_slots;
35
    /**
36
     * @var array
37
     */
38
    protected $_slotOptions = [];
39
    /**
40
     * @var int Max number of crafts the generated item option will have
41
     */
42
    protected $_crafts;
43
    /**
44
     * @var array
45
     */
46
    protected $_craftOptions = [];
47
    /**
48
     * @var array
49
     */
50
    protected $_availableCraftLevels = ['9', 'A', 'B', 'C', 'D', 'E', 'F'];
51
    /**
52
     * @var array
53
     */
54
    protected $_availableOptions = [
55
        '1', '2', '3', '4', '5',
56
        '6', '7', '8', '9', 'A',
57
        'B', 'C', 'D', 'E', 'F'
58
    ];
59
60
    /**
61
     * ItemOption constructor.
62
     * @param int $slots
63
     * @param int $crafts
64
     * @throws \cyberinferno\Cabal\Helpers\Exceptions\MaxOptionException
65
     */
66 54
    public function __construct($slots = 0, $crafts = 0)
67
    {
68 54
        if ($slots < self::MIN_SLOTS) {
69 3
            $slots = self::MIN_SLOTS;
70
        }
71 54
        if ($slots > self::MAX_SLOTS) {
72 3
            $slots = self::MAX_SLOTS;
73
        }
74 54
        if ($crafts < self::MIN_CRAFTS) {
75 3
            $crafts = self::MIN_CRAFTS;
76
        }
77 54
        if ($crafts > self::MAX_CRAFTS) {
78 3
            $crafts = self::MAX_CRAFTS;
79
        }
80 54
        if ($slots + $crafts > self::MAX_OPTIONS) {
81 3
            throw new MaxOptionException('Maximum number of options cannot exceed ' . self::MAX_OPTIONS);
82
        }
83 51
        $this->_slots = $slots;
84 51
        $this->_crafts = $crafts;
85 51
    }
86
87
    /**
88
     * Returns the number of slots in the option
89
     *
90
     * @return int
91
     */
92 9
    public function getSlots()
93
    {
94 9
        return $this->_slots;
95
    }
96
97
    /**
98
     * Returns the number of crafts in the option
99
     *
100
     * @return int
101
     */
102 9
    public function getCrafts()
103
    {
104 9
        return $this->_crafts;
105
    }
106
107
    /**
108
     * Returns slot options
109
     *
110
     * @return array
111
     */
112 6
    public function getSlotOptions()
113
    {
114 6
        return $this->_slotOptions;
115
    }
116
117
    /**
118
     * Sets a slot option
119
     *
120
     * @param string $option
121
     * @return ItemOption
122
     * @throws InvalidOptionException
123
     * @throws OptionLimitException
124
     */
125 12
    public function setSlotOption($option)
126
    {
127 12
        if (!in_array(strval($option), $this->_availableOptions)) {
128 3
            throw new InvalidOptionException();
129
        }
130 9
        if (count($this->_slotOptions) == $this->_slots) {
131 3
            throw new OptionLimitException('Slot option cannot exceed ' . $this->_slots);
132
        }
133 9
        $this->_slotOptions[] = ['option' => (string)$option];
134 9
        return $this;
135
    }
136
137
    /**
138
     * Returns craft options
139
     *
140
     * @return array
141
     */
142 6
    public function getCraftOptions()
143
    {
144 6
        return $this->_craftOptions;
145
    }
146
147
    /**
148
     * Sets a craft option
149
     *
150
     * @param string $craftLevel
151
     * @param string $option
152
     * @return ItemOption
153
     * @throws InvalidCraftLevelException
154
     * @throws InvalidOptionException
155
     * @throws OptionLimitException
156
     */
157 15
    public function setCraftOption($craftLevel, $option)
158
    {
159 15
        if (!in_array(strval($craftLevel), $this->_availableCraftLevels)) {
160 3
            throw new InvalidCraftLevelException();
161
        }
162 12
        if (!in_array(strval($option), $this->_availableOptions)) {
163 3
            throw new InvalidOptionException();
164
        }
165 9
        if (count($this->_craftOptions) == $this->_crafts) {
166 3
            throw new OptionLimitException('Craft option cannot exceed ' . $this->_crafts);
167
        }
168 9
        $this->_craftOptions[] = [
169 9
            'craftLevel' => (string)$craftLevel,
170 9
            'option' => (string)$option
171
        ];
172 9
        return $this;
173
    }
174
175
    /**
176
     * Returns the generated item option based upon the criteria set
177
     *
178
     * @param string $format
179
     * @return string|int
180
     */
181 3
    public function generate($format = self::OUTPUT_FORMAT_INTEGER)
182
    {
183 3
        $optionString = '';
184 3
        $slotsToFillArray = [];
185
        // Craft options should be at the end of the hex string hence we start prepending all craft options to output
186 3
        foreach ($this->_craftOptions as $craftOption) {
187 3
            $optionString = $craftOption['craftLevel'] . $craftOption['option'] . $optionString;
188
        }
189
        // We calculate slots to fill based upon slot options
190 3
        foreach ($this->_slotOptions as $slotOption) {
191 3
            if (isset($slotsToFillArray[$slotOption['option']])) {
192
                // Item cannot have 4 set of same options
193 3
                if ($slotsToFillArray[$slotOption['option']] == 3) {
194 3
                    continue;
195
                }
196 3
                $slotsToFillArray[$slotOption['option']]++;
197
            } else {
198 3
                $slotsToFillArray[$slotOption['option']] = 1;
199
            }
200
        }
201
        // Sorting slots to fill array to make sure multiple slot options stay in the end
202 3
        arsort($slotsToFillArray, SORT_NUMERIC);
203
        // Build the output with slot options
204 3
        foreach ($slotsToFillArray as $option => $fill) {
205 3
            if (strlen($optionString) == 7) {
206
                // Means we prematurely reached the end due to wrong options being set hence go out of the loop
207
                break;
208
            }
209 3
            if (strlen($optionString) == 6) {
210
                // Ignore slots to fill value
211 3
                $optionString = $option . $optionString;
212
            } else {
213 3
                $optionString = $fill . $option . $optionString;
214
            }
215
        }
216 3
        if (strlen($optionString) < 7) {
217
            // Fill the output with 0s if there are empty slots
218 3
            $optionString = str_repeat('0', 7 - strlen($optionString)) . $optionString;
219
        }
220 3
        if ($format != self::OUTPUT_FORMAT_INTEGER) {
221 3
            return $this->_slots . $optionString;
222
        }
223 3
        return hexdec($this->_slots . $optionString);
224
    }
225
226
    /**
227
     * Extracts item options from generated item option
228
     *
229
     * @param int|string $generatedItemOption
230
     * @return array
231
     */
232 3
    public static function extract($generatedItemOption)
233
    {
234 3
        if (is_int($generatedItemOption)) {
235 3
            $generatedItemOption = dechex($generatedItemOption);
236
        }
237 3
        if (strlen($generatedItemOption) < 8) {
238 3
            $generatedItemOption = str_repeat('0', 8 - strlen($generatedItemOption)) . $generatedItemOption;
239
        }
240 3
        $generatedItemOption = strtoupper($generatedItemOption);
241 3
        if (hexdec($generatedItemOption) > hexdec('4FFFFFFF')) {
242
            // Invalid generated option hence return default values
243
            return [
244
                'slots' => 0,
245
                'crafts' => 0,
246
                'slotOptions' => [],
247
                'craftOptions' => []
248
            ];
249
        }
250 3
        $craftOptions = [];
251 3
        $slotOptions = [];
252
        // Extract last 3 options
253 3
        for ($i = 1; $i <= 3; $i++) {
254 3
            $currentOption = substr($generatedItemOption, -1 * ($i * 2), 2);
255 3
            if (in_array($currentOption[0], ['9', 'A', 'B', 'C', 'D', 'E', 'F'])) {
256 3
                $craftOptions[] = [
257 3
                    'craftLevel' => $currentOption[0],
258 3
                    'craftOption' => $currentOption[1]
259
                ];
260
            } else {
261 3
                for ($j = 1; $j <= (int)$currentOption[0]; $j++) {
262 3
                    if ($currentOption[1] == '0') {
263
                        continue;
264
                    }
265 3
                    $slotOptions[] = [
266 3
                        'slotOption' => $currentOption[1]
267
                    ];
268
                }
269
            }
270
        }
271 3
        if ($generatedItemOption[1] != '0') {
272
            $slotOptions[] = [
273
                'slotOption' => $generatedItemOption[1]
274
            ];
275
        }
276
        return [
277 3
            'slots' => (int)$generatedItemOption[0],
278 3
            'crafts' => count($craftOptions),
279 3
            'slotOptions' => $slotOptions,
280 3
            'craftOptions' => $craftOptions
281
        ];
282
    }
283
}