Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Passed
Pull Request — master (#1005)
by Dan
04:25
created

AbstractSmrShip::getEmptyHolds()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 2
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php declare(strict_types=1);
2
3
abstract class AbstractSmrShip {
4
	protected static $CACHE_BASE_SHIPS = array();
5
6
	const SHIP_CLASS_RAIDER = 3;
7
	const SHIP_CLASS_SCOUT = 4;
8
9
	// Player exp gained for each point of damage done
10
	const EXP_PER_DAMAGE_PLAYER = 0.375;
11
	const EXP_PER_DAMAGE_PLANET = 1.0; // note that planet damage is reduced
12
	const EXP_PER_DAMAGE_PORT   = 0.15;
13
	const EXP_PER_DAMAGE_FORCE  = 0.075;
14
15
	const STARTER_SHIPS = [
16
		RACE_NEUTRAL => SHIP_TYPE_GALACTIC_SEMI,
17
		RACE_ALSKANT => SHIP_TYPE_SMALL_TIMER,
18
		RACE_CREONTI => SHIP_TYPE_MEDIUM_CARGO_HULK,
19
		RACE_HUMAN => SHIP_TYPE_LIGHT_FREIGHTER,
20
		RACE_IKTHORNE => SHIP_TYPE_TINY_DELIGHT,
21
		RACE_SALVENE => SHIP_TYPE_HATCHLINGS_DUE,
22
		RACE_THEVIAN => SHIP_TYPE_SWIFT_VENTURE,
23
		RACE_WQHUMAN => SHIP_TYPE_SLIP_FREIGHTER,
24
		RACE_NIJARIN => SHIP_TYPE_REDEEMER,
25
	];
26
27
	protected $player;
28
29
	protected $gameID;
30
	protected $baseShip;
31
32
	protected $hardware;
33
	protected $oldHardware;
34
35
	protected $cargo;
36
37
	protected $weapons = array();
38
39
	protected $illusionShip;
40
41
	protected $hasChangedWeapons = false;
42
	protected $hasChangedCargo = false;
43
	protected $hasChangedHardware = array();
44
45
	public static function getBaseShip($gameTypeID, $shipTypeID, $forceUpdate = false) {
46
		if ($forceUpdate || !isset(self::$CACHE_BASE_SHIPS[$gameTypeID][$shipTypeID])) {
47
			// determine ship
48
			$db = MySqlDatabase::getInstance();
49
			$db->query('SELECT * FROM ship_type WHERE ship_type_id = ' . $db->escapeNumber($shipTypeID) . ' LIMIT 1'); //TODO add game type id
50
			if ($db->nextRecord()) {
51
				self::$CACHE_BASE_SHIPS[$gameTypeID][$shipTypeID] = self::buildBaseShip($db);
52
			} else {
53
				self::$CACHE_BASE_SHIPS[$gameTypeID][$shipTypeID] = false;
54
			}
55
		}
56
		return self::$CACHE_BASE_SHIPS[$gameTypeID][$shipTypeID];
57
	}
58
59
	protected static function buildBaseShip(MySqlDatabase $db) {
60
		$ship = array();
61
		$ship['Type'] = 'Ship';
62
		$ship['Name'] = $db->getField('ship_name');
63
		$ship['ShipTypeID'] = $db->getInt('ship_type_id');
64
		$ship['ShipClassID'] = $db->getInt('ship_class_id');
65
		$ship['RaceID'] = $db->getInt('race_id');
66
		$ship['Hardpoint'] = $db->getInt('hardpoint');
67
		$ship['Speed'] = $db->getInt('speed');
68
		$ship['Cost'] = $db->getInt('cost');
69
		$ship['AlignRestriction'] = $db->getInt('buyer_restriction');
70
		$ship['Level'] = $db->getInt('lvl_needed');
71
72
		$maxPower = 0;
73
		switch ($ship['Hardpoint']) {
74
			default:
75
				$maxPower += 1 * $ship['Hardpoint'] - 10;
76
			case 10:
77
				$maxPower += 2;
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
78
			case 9:
79
				$maxPower += 2;
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
80
			case 8:
81
				$maxPower += 2;
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
82
			case 7:
83
				$maxPower += 2;
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
84
			case 6:
85
				$maxPower += 3;
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
86
			case 5:
87
				$maxPower += 3;
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
88
			case 4:
89
				$maxPower += 3;
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
90
			case 3:
91
				$maxPower += 4;
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
92
			case 2:
93
				$maxPower += 4;
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
94
			case 1:
95
				$maxPower += 5;
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
96
			case 0:
97
				$maxPower += 0;
98
		}
99
		$ship['MaxPower'] = $maxPower;
100
101
102
		// get supported hardware from db
103
		$db2 = MySqlDatabase::getInstance();
104
		$db2->query('SELECT hardware_type_id, max_amount FROM ship_type_support_hardware ' .
105
			'WHERE ship_type_id = ' . $db2->escapeNumber($ship['ShipTypeID']) . ' ORDER BY hardware_type_id');
106
107
		while ($db2->nextRecord()) {
108
			// adding hardware to array
109
			$ship['MaxHardware'][$db2->getInt('hardware_type_id')] = $db2->getInt('max_amount');
110
		}
111
112
		$ship['BaseMR'] = IRound(
113
								700 -
114
								(
115
									(
116
										$ship['MaxHardware'][HARDWARE_SHIELDS]
117
										+$ship['MaxHardware'][HARDWARE_ARMOUR]
118
										+$ship['MaxHardware'][HARDWARE_COMBAT] * 3
119
									) / 25
120
									+(
121
										$ship['MaxHardware'][HARDWARE_CARGO] / 100
122
										-$ship['Speed'] * 5
123
										+$ship['Hardpoint'] * 5
124
										+$ship['MaxHardware'][HARDWARE_COMBAT] / 5
125
									)
126
								)
127
							);
128
		return $ship;
129
	}
130
131
	public static function getAllBaseShips($gameTypeID) {
132
		// determine ship
133
		$db = MySqlDatabase::getInstance();
134
		$db->query('SELECT * FROM ship_type ORDER BY ship_type_id ASC'); //TODO add game type id
135
		while ($db->nextRecord()) {
136
			if (!isset(self::$CACHE_BASE_SHIPS[$gameTypeID][$db->getInt('ship_type_id')])) {
137
				self::$CACHE_BASE_SHIPS[$gameTypeID][$db->getInt('ship_type_id')] = self::buildBaseShip($db);
138
			}
139
		}
140
		return self::$CACHE_BASE_SHIPS[$gameTypeID];
141
	}
142
143
	protected function __construct(AbstractSmrPlayer $player) {
144
		$this->player = $player;
145
		$this->gameID = $player->getGameID();
146
		$this->regenerateBaseShip();
147
	}
148
149
	protected function regenerateBaseShip() {
150
		$this->baseShip = AbstractSmrShip::getBaseShip(Globals::getGameType($this->gameID), $this->player->getShipTypeID());
151
		$this->checkForExcess();
152
	}
153
154
	public function checkForExcess() {
155
		$this->checkForExcessHardware();
156
		$this->checkForExcessWeapons();
157
		$this->checkForExcessCargo();
158
	}
159
160
	public function checkForExcessWeapons() {
161
		while ($this->hasWeapons() && ($this->getPowerUsed() > $this->getMaxPower() || $this->getNumWeapons() > $this->getHardpoints())) {
162
			//erase the first weapon 1 at a time until we are okay
163
			$this->removeLastWeapon();
164
		}
165
	}
166
167
	public function checkForExcessCargo() {
168
		if ($this->hasCargo()) {
169
			$excess = array_sum($this->getCargo()) - $this->getCargoHolds();
170
			foreach ($this->getCargo() as $goodID => $amount) {
171
				if ($excess > 0) {
172
					$decreaseAmount = min($amount, $excess);
173
					$this->decreaseCargo($goodID, $decreaseAmount);
174
					$excess -= $decreaseAmount;
175
				} else {
176
					// No more excess cargo
177
					break;
178
				}
179
			}
180
		}
181
	}
182
183
	public function checkForExcessHardware() {
184
		//check hardware to see if anything needs to be removed
185
		if (is_array($hardware = $this->getHardware())) {
186
			foreach ($hardware as $hardwareTypeID => $amount) {
187
				if ($amount > ($max = $this->getMaxHardware($hardwareTypeID))) {
188
					$this->setHardware($hardwareTypeID, $max);
189
				}
190
			}
191
		}
192
	}
193
194
	/**
195
	 * Set all hardware to its maximum value for this ship.
196
	 */
197
	public function setHardwareToMax() {
198
		foreach ($this->getMaxHardware() as $key => $max) {
199
			$this->setHardware($key, $max);
200
		}
201
		$this->removeUnderAttack();
202
	}
203
204
	public function getPowerUsed() {
205
		$power = 0;
206
		foreach ($this->weapons as $weapon) {
207
			$power += $weapon->getPowerLevel();
208
		}
209
		return $power;
210
	}
211
212
	public function getRemainingPower() {
213
		return $this->getMaxPower() - $this->getPowerUsed();
214
	}
215
216
	/**
217
	 * given power level of new weapon, return whether there is enough power available to install it on this ship
218
	 */
219
	public function checkPowerAvailable($powerLevel) {
220
		return $this->getRemainingPower() >= $powerLevel;
221
	}
222
223
	public function getMaxPower() {
224
		return $this->baseShip['MaxPower'];
225
	}
226
227
	public function hasIllegalGoods() {
228
		return $this->hasCargo(GOODS_SLAVES) || $this->hasCargo(GOODS_WEAPONS) || $this->hasCargo(GOODS_NARCOTICS);
229
	}
230
231
	public function getDisplayAttackRating() {
232
		if ($this->hasActiveIllusion()) {
233
			return $this->getIllusionAttack();
234
		} else {
235
			return $this->getAttackRating();
236
		}
237
	}
238
239
	public function getDisplayDefenseRating() {
240
		if ($this->hasActiveIllusion()) {
241
			return $this->getIllusionDefense();
242
		} else {
243
			return $this->getDefenseRating();
244
		}
245
	}
246
247
	public function getDisplayName() {
248
		if ($this->hasActiveIllusion()) {
249
			return $this->getIllusionShipName();
250
		} else {
251
			return $this->getName();
252
		}
253
	}
254
255
	public function getAttackRating() : int {
256
		return IRound(($this->getTotalShieldDamage() + $this->getTotalArmourDamage() + $this->getCDs() * 2) / 40);
257
	}
258
259
	public function getAttackRatingWithMaxCDs() : int {
260
		return IRound(($this->getTotalShieldDamage() + $this->getTotalArmourDamage() + $this->getMaxCDs() * .7) / 40);
261
	}
262
263
	public function getDefenseRating() : int {
264
		return IRound((($this->getShields() + $this->getArmour()) / 100) + (($this->getCDs() * 3) / 100));
265
	}
266
267
	public function getMaxDefenseRating() : int {
268
		return IRound((($this->getMaxShields() + $this->getMaxArmour()) / 100) + (($this->getMaxCDs() * 3) / 100));
269
	}
270
271
	public function getShieldLow() : int { return IFloor($this->getShields() / 100) * 100; }
272
	public function getShieldHigh() : int { return $this->getShieldLow() + 100; }
273
	public function getArmourLow() : int { return IFloor($this->getArmour() / 100) * 100; }
274
	public function getArmourHigh() : int { return $this->getArmourLow() + 100; }
275
	public function getCDsLow() : int { return IFloor($this->getCDs() / 100) * 100; }
276
	public function getCDsHigh() : int { return $this->getCDsLow() + 100; }
277
278
279
280
	public function addWeapon(SmrWeapon $weapon) {
281
		if ($this->hasOpenWeaponSlots() && $this->checkPowerAvailable($weapon->getPowerLevel())) {
282
			array_push($this->weapons, $weapon);
283
			$this->hasChangedWeapons = true;
284
			return $weapon;
285
		}
286
		$return = false;
287
		return $return;
288
	}
289
290
	public function moveWeaponUp($orderID) {
291
		$replacement = $orderID - 1;
292
		if ($replacement < 0) {
293
			// Shift everything up by one and put the selected weapon at the bottom
294
			array_push($this->weapons, array_shift($this->weapons));
295
		} else {
296
			// Swap the selected weapon with the one above it
297
			$temp = $this->weapons[$replacement];
298
			$this->weapons[$replacement] = $this->weapons[$orderID];
299
			$this->weapons[$orderID] = $temp;
300
		}
301
		$this->hasChangedWeapons = true;
302
	}
303
304
	public function moveWeaponDown($orderID) {
305
		$replacement = $orderID + 1;
306
		if ($replacement >= count($this->weapons)) {
307
			// Shift everything down by one and put the selected weapon at the top
308
			array_unshift($this->weapons, array_pop($this->weapons));
309
		} else {
310
			// Swap the selected weapon with the one below it
311
			$temp = $this->weapons[$replacement];
312
			$this->weapons[$replacement] = $this->weapons[$orderID];
313
			$this->weapons[$orderID] = $temp;
314
		}
315
		$this->hasChangedWeapons = true;
316
	}
317
318
	public function setWeaponLocations(array $orderArray) {
319
		$weapons = $this->weapons;
320
		foreach ($orderArray as $newOrder => $oldOrder) {
321
			$this->weapons[$newOrder] =& $weapons[$oldOrder];
322
		}
323
		$this->hasChangedWeapons = true;
324
	}
325
326
	public function removeLastWeapon() {
327
		$this->removeWeapon($this->getNumWeapons() - 1);
328
	}
329
330
	public function removeWeapon($orderID) {
331
		// Remove the specified weapon, then reindex the array
332
		unset($this->weapons[$orderID]);
333
		$this->weapons = array_values($this->weapons);
334
		$this->hasChangedWeapons = true;
335
	}
336
337
	public function removeAllWeapons() {
338
		$this->weapons = array();
339
		$this->hasChangedWeapons = true;
340
	}
341
342
	public function removeAllCargo() {
343
		if (is_array($this->cargo)) {
344
			foreach ($this->cargo as $goodID => $amount) {
345
				$this->setCargo($goodID, 0);
346
			}
347
		}
348
	}
349
350
	public function removeAllHardware() {
351
		foreach (array_keys($this->hardware) as $hardwareTypeID) {
352
			$this->setHardware($hardwareTypeID, 0);
353
		}
354
		$this->decloak();
355
		$this->disableIllusion();
356
	}
357
358
	public function getPod($isNewbie = false) {
359
		$this->removeAllWeapons();
360
		$this->removeAllCargo();
361
		$this->removeAllHardware();
362
363
		if ($isNewbie) {
364
			$this->setShields(75, true);
365
			$this->setArmour(150, true);
366
			$this->setCargoHolds(40);
367
			$this->setShipTypeID(SHIP_TYPE_NEWBIE_MERCHANT_VESSEL);
368
		} else {
369
			$this->setShields(50, true);
370
			$this->setArmour(50, true);
371
			$this->setCargoHolds(5);
372
			$this->setShipTypeID(SHIP_TYPE_ESCAPE_POD);
373
		}
374
375
		$this->removeUnderAttack();
376
	}
377
378
	public function giveStarterShip() : void {
379
		if ($this->player->hasNewbieStatus()) {
380
			$shipID = SHIP_TYPE_NEWBIE_MERCHANT_VESSEL;
381
			$amount_shields = 75;
382
			$amount_armour = 150;
383
		} else {
384
			$shipID = self::STARTER_SHIPS[$this->player->getRaceID()];
385
			$amount_shields = 50;
386
			$amount_armour = 50;
387
		}
388
		$this->setShipTypeID($shipID);
389
		$this->setShields($amount_shields, true);
390
		$this->setArmour($amount_armour, true);
391
		$this->setCargoHolds(40);
392
		$this->addWeapon(SmrWeapon::getWeapon(WEAPON_TYPE_LASER));
393
	}
394
395
	public function hasCloak() {
396
		return $this->getHardware(HARDWARE_CLOAK);
397
	}
398
399
	public function canHaveCloak() {
400
		return $this->getMaxHardware(HARDWARE_CLOAK);
401
	}
402
403
404
	public function hasActiveIllusion() {
405
		if (!$this->hasIllusion()) {
406
			return false;
407
		}
408
		return $this->getIllusionShip() !== false;
409
	}
410
411
	public function hasIllusion() {
412
		return $this->getHardware(HARDWARE_ILLUSION);
413
	}
414
415
	public function canHaveIllusion() {
416
		return $this->getMaxHardware(HARDWARE_ILLUSION);
417
	}
418
419
	public function hasJump() {
420
		return $this->getHardware(HARDWARE_JUMP);
421
	}
422
423
	public function canHaveJump() {
424
		return $this->getMaxHardware(HARDWARE_JUMP);
425
	}
426
427
	public function hasDCS() {
428
		return $this->getHardware(HARDWARE_DCS);
429
	}
430
431
	public function canHaveDCS() {
432
		return $this->getMaxHardware(HARDWARE_DCS);
433
	}
434
435
	public function hasScanner() {
436
		return $this->getHardware(HARDWARE_SCANNER);
437
	}
438
439
	public function canHaveScanner() {
440
		return $this->getMaxHardware(HARDWARE_SCANNER);
441
	}
442
443
	abstract public function decloak();
444
445
	abstract public function enableCloak();
446
447
	abstract public function setIllusion($ship_id, $attack, $defense);
448
449
	abstract public function disableIllusion();
450
451
	public function getIllusionShipID() {
452
		$this->getIllusionShip();
453
		return $this->illusionShip['ID'];
454
	}
455
456
	public function getIllusionShipName() {
457
		$this->getIllusionShip();
458
		return $this->illusionShip['Name'];
459
	}
460
461
	abstract public function getIllusionShip();
462
463
	public function getIllusionAttack() {
464
		$this->getIllusionShip();
465
		return $this->illusionShip['Attack'];
466
	}
467
468
	public function getIllusionDefense() {
469
		$this->getIllusionShip();
470
		return $this->illusionShip['Defense'];
471
	}
472
473
	public function getPlayer() {
474
		return $this->player;
475
	}
476
477
	public function getGameID() {
478
		return $this->gameID;
479
	}
480
481
	public function getGame() {
482
		return SmrGame::getGame($this->gameID);
483
	}
484
485
	public function getShipTypeID() {
486
		return $this->baseShip['ShipTypeID'];
487
	}
488
489
	public function getShipClassID() {
490
		return $this->baseShip['ShipClassID'];
491
	}
492
493
	/**
494
	 * Switch to a new ship, updating player turns accordingly.
495
	 */
496
	public function setShipTypeID($shipTypeID) {
497
		$oldSpeed = $this->getSpeed();
498
		$this->getPlayer()->setShipTypeID($shipTypeID);
499
		$this->regenerateBaseShip();
500
		$newSpeed = $this->getSpeed();
501
502
		// Update the player's turns to account for the speed change
503
		$oldTurns = $this->getPlayer()->getTurns();
504
		$this->getPlayer()->setTurns(IRound($oldTurns * $newSpeed / $oldSpeed));
505
	}
506
507
	public function getName() {
508
		return $this->baseShip['Name'];
509
	}
510
511
	public function getCost() {
512
		return $this->baseShip['Cost'];
513
	}
514
515
	public function getCostToUpgrade($upgradeShipID) {
516
		$upgadeBaseShip = AbstractSmrShip::getBaseShip(Globals::getGameType($this->getGameID()), $upgradeShipID);
517
		return $upgadeBaseShip['Cost'] - IFloor($this->getCost() * SHIP_REFUND_PERCENT);
518
	}
519
520
	public function getCostToUpgradeAndUNO($upgradeShipID) {
521
		return $this->getCostToUpgrade($upgradeShipID) + $this->getCostToUNOAgainstShip($upgradeShipID);
522
	}
523
524
	protected function getCostToUNOAgainstShip($shipID) {
525
		$baseShip = AbstractSmrShip::getBaseShip(Globals::getGameType($this->getGameID()), $shipID);
526
		$cost = 0;
527
		$hardwareTypes = array(HARDWARE_SHIELDS, HARDWARE_ARMOUR, HARDWARE_CARGO);
528
		foreach ($hardwareTypes as $hardwareTypeID) {
529
			$cost += max(0, $baseShip['MaxHardware'][$hardwareTypeID] - $this->getHardware($hardwareTypeID)) * Globals::getHardwareCost($hardwareTypeID);
530
		}
531
		return $cost;
532
	}
533
534
	public function getCostToUNO() {
535
		return $this->getCostToUNOAgainstShip($this->getShipTypeID());
536
	}
537
538
	/**
539
	 * Returns the base ship speed (unmodified by the game speed).
540
	 */
541
	public function getSpeed() {
542
		return $this->baseShip['Speed'];
543
	}
544
545
	/**
546
	 * Returns the ship speed modified by the game speed.
547
	 */
548
	public function getRealSpeed() {
549
		return $this->getSpeed() * $this->getGame()->getGameSpeed();
550
	}
551
552
	public function getHardware($hardwareTypeID = false) {
553
		if ($hardwareTypeID === false) {
554
			return $this->hardware;
555
		}
556
		return $this->hardware[$hardwareTypeID] ?? 0;
557
	}
558
559
	public function setHardware($hardwareTypeID, $amount) {
560
		if ($this->getHardware($hardwareTypeID) == $amount) {
561
			return;
562
		}
563
		$this->hardware[$hardwareTypeID] = $amount;
564
		$this->hasChangedHardware[$hardwareTypeID] = true;
565
	}
566
567
	public function increaseHardware($hardwareTypeID, $amount) {
568
		$this->setHardware($hardwareTypeID, $this->getHardware($hardwareTypeID) + $amount);
569
	}
570
571
	public function getOldHardware($hardwareTypeID = false) {
572
		if ($hardwareTypeID === false) {
573
			return $this->oldHardware;
574
		}
575
		return $this->oldHardware[$hardwareTypeID] ?? 0;
576
	}
577
578
	public function setOldHardware($hardwareTypeID, $amount) {
579
		if ($this->getOldHardware($hardwareTypeID) == $amount) {
580
			return;
581
		}
582
		$this->oldHardware[$hardwareTypeID] = $amount;
583
		$this->hasChangedHardware[$hardwareTypeID] = true;
584
	}
585
586
	public function hasMaxHardware($hardwareTypeID) {
587
		return $this->getHardware($hardwareTypeID) == $this->getMaxHardware($hardwareTypeID);
588
	}
589
590
	public function getMaxHardware($hardwareTypeID = false) {
591
		if ($hardwareTypeID === false) {
592
			return $this->baseShip['MaxHardware'];
593
		}
594
		return $this->baseShip['MaxHardware'][$hardwareTypeID];
595
	}
596
597
	public function getShields() {
598
		return $this->getHardware(HARDWARE_SHIELDS);
599
	}
600
601
	public function setShields($amount, $updateOldAmount = false) {
602
		if ($updateOldAmount && !$this->hasLostShields()) {
603
			$this->setOldHardware(HARDWARE_SHIELDS, $amount);
604
		}
605
		$this->setHardware(HARDWARE_SHIELDS, $amount);
606
	}
607
608
	public function decreaseShields($amount) {
609
		$this->setShields($this->getShields() - $amount);
610
	}
611
612
	public function increaseShields($amount) {
613
		$this->setShields($this->getShields() + $amount);
614
	}
615
616
	public function getOldShields() {
617
		return $this->getOldHardware(HARDWARE_SHIELDS);
618
	}
619
620
	public function setOldShields($amount) {
621
		$this->setOldHardware(HARDWARE_SHIELDS, $amount);
622
	}
623
624
	public function hasShields() {
625
		return $this->getShields() > 0;
626
	}
627
628
	public function hasLostShields() {
629
		return $this->getShields() < $this->getOldShields();
630
	}
631
632
	public function hasMaxShields() {
633
		return $this->getShields() == $this->getMaxShields();
634
	}
635
636
	public function getMaxShields() {
637
		return $this->getMaxHardware(HARDWARE_SHIELDS);
638
	}
639
640
	public function getArmour() {
641
		return $this->getHardware(HARDWARE_ARMOUR);
642
	}
643
644
	public function setArmour($amount, $updateOldAmount = false) {
645
		if ($updateOldAmount && !$this->hasLostArmour()) {
646
			$this->setOldHardware(HARDWARE_ARMOUR, $amount);
647
		}
648
		$this->setHardware(HARDWARE_ARMOUR, $amount);
649
	}
650
651
	public function decreaseArmour($amount) {
652
		$this->setArmour($this->getArmour() - $amount);
653
	}
654
655
	public function increaseArmour($amount) {
656
		$this->setArmour($this->getArmour() + $amount);
657
	}
658
659
	public function getOldArmour() {
660
		return $this->getOldHardware(HARDWARE_ARMOUR);
661
	}
662
663
	public function setOldArmour($amount) {
664
		$this->setOldHardware(HARDWARE_ARMOUR, $amount);
665
	}
666
667
	public function hasArmour() {
668
		return $this->getArmour() > 0;
669
	}
670
671
	public function hasLostArmour() {
672
		return $this->getArmour() < $this->getOldArmour();
673
	}
674
675
	public function hasMaxArmour() {
676
		return $this->getArmour() == $this->getMaxArmour();
677
	}
678
679
	public function getMaxArmour() {
680
		return $this->getMaxHardware(HARDWARE_ARMOUR);
681
	}
682
683
	public function isDead() {
684
		return !$this->hasArmour() && !$this->hasShields();
685
	}
686
687
	public function canAcceptCDs() {
688
		return $this->getCDs() < $this->getMaxCDs();
689
	}
690
691
	public function canAcceptSDs() {
692
		return $this->getSDs() < $this->getMaxSDs();
693
	}
694
695
	public function canAcceptMines() {
696
		return $this->getMines() < $this->getMaxMines();
697
	}
698
699
	public function hasCDs() {
700
		return $this->getCDs() > 0;
701
	}
702
703
	public function hasSDs() {
704
		return $this->getSDs() > 0;
705
	}
706
707
	public function hasMines() {
708
		return $this->getMines() > 0;
709
	}
710
711
	public function getCDs() {
712
		return $this->getHardware(HARDWARE_COMBAT);
713
	}
714
715
	public function setCDs($amount, $updateOldAmount = false) {
716
		if ($updateOldAmount && !$this->hasLostCDs()) {
717
			$this->setOldHardware(HARDWARE_COMBAT, $amount);
718
		}
719
		$this->setHardware(HARDWARE_COMBAT, $amount);
720
	}
721
722
	/**
723
	 * Decreases the ship CDs. Use $updateOldAmount=true to prevent
724
	 * this change from triggering `isUnderAttack`.
725
	 */
726
	public function decreaseCDs($amount, $updateOldAmount = false) {
727
		$this->setCDs($this->getCDs() - $amount, $updateOldAmount);
728
	}
729
730
	public function increaseCDs($amount) {
731
		$this->setCDs($this->getCDs() + $amount);
732
	}
733
734
	public function getOldCDs() {
735
		return $this->getOldHardware(HARDWARE_COMBAT);
736
	}
737
738
	public function setOldCDs($amount) {
739
		$this->setOldHardware(HARDWARE_COMBAT, $amount);
740
	}
741
742
	public function hasLostCDs() {
743
		return $this->getCDs() < $this->getOldCDs();
744
	}
745
746
	public function getMaxCDs() {
747
		return $this->getMaxHardware(HARDWARE_COMBAT);
748
	}
749
750
	public function getSDs() {
751
		return $this->getHardware(HARDWARE_SCOUT);
752
	}
753
754
	public function setSDs($amount) {
755
		$this->setHardware(HARDWARE_SCOUT, $amount);
756
	}
757
758
	public function decreaseSDs($amount) {
759
		$this->setSDs($this->getSDs() - $amount);
760
	}
761
762
	public function increaseSDs($amount) {
763
		$this->setSDs($this->getSDs() + $amount);
764
	}
765
766
	public function getMaxSDs() {
767
		return $this->getMaxHardware(HARDWARE_SCOUT);
768
	}
769
770
	public function getMines() {
771
		return $this->getHardware(HARDWARE_MINE);
772
	}
773
774
	public function setMines($amount) {
775
		$this->setHardware(HARDWARE_MINE, $amount);
776
	}
777
778
	public function decreaseMines($amount) {
779
		$this->setMines($this->getMines() - $amount);
780
	}
781
782
	public function increaseMines($amount) {
783
		$this->setMines($this->getMines() + $amount);
784
	}
785
786
	public function getMaxMines() {
787
		return $this->getMaxHardware(HARDWARE_MINE);
788
	}
789
790
	public function getCargoHolds() {
791
		return $this->getHardware(HARDWARE_CARGO);
792
	}
793
794
	public function setCargoHolds($amount) {
795
		$this->setHardware(HARDWARE_CARGO, $amount);
796
	}
797
798
	public function getCargo($goodID = false) {
799
		if ($goodID !== false) {
800
			if (isset($this->cargo[$goodID])) {
801
				return $this->cargo[$goodID];
802
			}
803
			$cargo = 0;
804
			return $cargo;
805
		}
806
		return $this->cargo;
807
	}
808
809
	public function hasCargo($goodID = false) {
810
		if ($goodID !== false) {
811
			return $this->getCargo($goodID) > 0;
812
		}
813
		if (is_array($cargo = $this->getCargo())) {
814
			return array_sum($cargo) > 0;
815
		}
816
		return false;
817
	}
818
819
	public function setCargo($goodID, $amount) {
820
		if ($this->getCargo($goodID) == $amount) {
821
			return;
822
		}
823
		$this->cargo[$goodID] = $amount;
824
		$this->hasChangedCargo = true;
825
		// Sort cargo by goodID to make sure it shows up in the correct order
826
		// before the next page is loaded.
827
		ksort($this->cargo);
828
	}
829
830
	public function decreaseCargo($goodID, $amount) {
831
		if ($amount < 0) {
832
			throw new Exception('Trying to decrease negative cargo.');
833
		}
834
		$this->setCargo($goodID, $this->getCargo($goodID) - $amount);
835
	}
836
837
	public function increaseCargo($goodID, $amount) {
838
		if ($amount < 0) {
839
			throw new Exception('Trying to increase negative cargo.');
840
		}
841
		$this->setCargo($goodID, $this->getCargo($goodID) + $amount);
842
	}
843
844
	public function getEmptyHolds() {
845
		return $this->getCargoHolds() - $this->getUsedHolds();
846
	}
847
848
	public function getUsedHolds() {
849
		return array_sum($this->getCargo());
850
	}
851
852
	public function hasMaxCargoHolds() {
853
		return $this->getCargoHolds() == $this->getMaxCargoHolds();
854
	}
855
856
	public function getMaxCargoHolds() {
857
		return $this->getMaxHardware(HARDWARE_CARGO);
858
	}
859
860
	public function isUnderAttack() {
861
		return $this->hasLostShields() || $this->hasLostArmour() || $this->hasLostCDs();
862
	}
863
864
	public function removeUnderAttack() {
865
		global $var;
866
		$underAttack = $this->isUnderAttack();
867
		$this->setOldShields($this->getShields());
868
		$this->setOldCDs($this->getCDs());
869
		$this->setOldArmour($this->getArmour());
870
		if (isset($var['UnderAttack'])) {
871
			return $var['UnderAttack'];
872
		}
873
		if ($underAttack && !USING_AJAX) {
874
			SmrSession::updateVar('UnderAttack', $underAttack); //Remember we are under attack for AJAX
875
		}
876
		return $underAttack;
877
	}
878
879
	public function hasWeapons() {
880
		return $this->getNumWeapons() > 0;
881
	}
882
883
	public function getWeapons() {
884
		return $this->weapons;
885
	}
886
887
	public function canAttack() {
888
		return $this->hasWeapons() || $this->hasCDs();
889
	}
890
891
	public function getNumWeapons() {
892
		return count($this->getWeapons());
893
	}
894
895
	public function getOpenWeaponSlots() {
896
		return $this->getHardpoints() - $this->getNumWeapons();
897
	}
898
899
	public function hasOpenWeaponSlots() {
900
		return $this->getOpenWeaponSlots() > 0;
901
	}
902
903
	public function getHardpoints() {
904
		return $this->baseShip['Hardpoint'];
905
	}
906
907
	public function getTotalShieldDamage() {
908
		$weapons = $this->getWeapons();
909
		$shieldDamage = 0;
910
		foreach ($weapons as $weapon) {
911
			$shieldDamage += $weapon->getShieldDamage();
912
		}
913
		return $shieldDamage;
914
	}
915
916
	public function getTotalArmourDamage() {
917
		$weapons = $this->getWeapons();
918
		$armourDamage = 0;
919
		foreach ($weapons as $weapon) {
920
			$armourDamage += $weapon->getArmourDamage();
921
		}
922
		return $armourDamage;
923
	}
924
925
	public function isFederal() {
926
		return $this->getShipTypeID() == SHIP_TYPE_FEDERAL_DISCOVERY ||
927
		       $this->getShipTypeID() == SHIP_TYPE_FEDERAL_WARRANT ||
928
		       $this->getShipTypeID() == SHIP_TYPE_FEDERAL_ULTIMATUM;
929
	}
930
931
	public function isUnderground() {
932
		return $this->getShipTypeID() == SHIP_TYPE_THIEF ||
933
		       $this->getShipTypeID() == SHIP_TYPE_ASSASSIN ||
934
		       $this->getShipTypeID() == SHIP_TYPE_DEATH_CRUISER;
935
	}
936
937
	public function &shootPlayers(array $targetPlayers) {
938
		$thisPlayer = $this->getPlayer();
939
		$results = array('Player' => $thisPlayer, 'TotalDamage' => 0, 'Weapons' => []);
940
		if ($thisPlayer->isDead()) {
941
			$results['DeadBeforeShot'] = true;
942
			return $results;
943
		}
944
		$results['DeadBeforeShot'] = false;
945
		foreach ($this->weapons as $orderID => $weapon) {
946
			$results['Weapons'][$orderID] =& $weapon->shootPlayer($thisPlayer, array_rand_value($targetPlayers));
947
			if ($results['Weapons'][$orderID]['Hit']) {
948
				$results['TotalDamage'] += $results['Weapons'][$orderID]['ActualDamage']['TotalDamage'];
949
			}
950
		}
951
		if ($this->hasCDs()) {
952
			$thisCDs = new SmrCombatDrones($this->getGameID(), $this->getCDs());
953
			$results['Drones'] =& $thisCDs->shootPlayer($thisPlayer, array_rand_value($targetPlayers));
954
			$results['TotalDamage'] += $results['Drones']['ActualDamage']['TotalDamage'];
955
		}
956
		$thisPlayer->increaseExperience(IRound($results['TotalDamage'] * self::EXP_PER_DAMAGE_PLAYER));
957
		$thisPlayer->increaseHOF($results['TotalDamage'], array('Combat', 'Player', 'Damage Done'), HOF_PUBLIC);
958
		$thisPlayer->increaseHOF(1, array('Combat', 'Player', 'Shots'), HOF_PUBLIC);
959
		return $results;
960
	}
961
962
	public function &shootForces(SmrForce $forces) {
963
		$thisPlayer = $this->getPlayer();
964
		$results = array('Player' => $thisPlayer, 'TotalDamage' => 0, 'Weapons' => []);
965
		if ($thisPlayer->isDead()) {
966
			$results['DeadBeforeShot'] = true;
967
			return $results;
968
		}
969
		$results['DeadBeforeShot'] = false;
970
		foreach ($this->weapons as $orderID => $weapon) {
971
			$results['Weapons'][$orderID] =& $weapon->shootForces($thisPlayer, $forces);
972
			if ($results['Weapons'][$orderID]['Hit']) {
973
				$results['TotalDamage'] += $results['Weapons'][$orderID]['ActualDamage']['TotalDamage'];
974
				$thisPlayer->increaseHOF($results['Weapons'][$orderID]['ActualDamage']['NumMines'], array('Combat', 'Forces', 'Mines', 'Killed'), HOF_PUBLIC);
975
				$thisPlayer->increaseHOF($results['Weapons'][$orderID]['ActualDamage']['Mines'], array('Combat', 'Forces', 'Mines', 'Damage Done'), HOF_PUBLIC);
976
				$thisPlayer->increaseHOF($results['Weapons'][$orderID]['ActualDamage']['NumCDs'], array('Combat', 'Forces', 'Combat Drones', 'Killed'), HOF_PUBLIC);
977
				$thisPlayer->increaseHOF($results['Weapons'][$orderID]['ActualDamage']['CDs'], array('Combat', 'Forces', 'Combat Drones', 'Damage Done'), HOF_PUBLIC);
978
				$thisPlayer->increaseHOF($results['Weapons'][$orderID]['ActualDamage']['NumSDs'], array('Combat', 'Forces', 'Scout Drones', 'Killed'), HOF_PUBLIC);
979
				$thisPlayer->increaseHOF($results['Weapons'][$orderID]['ActualDamage']['SDs'], array('Combat', 'Forces', 'Scout Drones', 'Damage Done'), HOF_PUBLIC);
980
				$thisPlayer->increaseHOF($results['Weapons'][$orderID]['ActualDamage']['NumMines'] + $results['Weapons'][$orderID]['ActualDamage']['NumCDs'] + $results['Weapons'][$orderID]['ActualDamage']['NumSDs'], array('Combat', 'Forces', 'Killed'), HOF_PUBLIC);
981
			}
982
		}
983
		if ($this->hasCDs()) {
984
			$thisCDs = new SmrCombatDrones($this->getGameID(), $this->getCDs());
985
			$results['Drones'] =& $thisCDs->shootForces($thisPlayer, $forces);
986
			$results['TotalDamage'] += $results['Drones']['ActualDamage']['TotalDamage'];
987
			$thisPlayer->increaseHOF($results['Drones']['ActualDamage']['NumMines'], array('Combat', 'Forces', 'Mines', 'Killed'), HOF_PUBLIC);
988
			$thisPlayer->increaseHOF($results['Drones']['ActualDamage']['Mines'], array('Combat', 'Forces', 'Mines', 'Damage Done'), HOF_PUBLIC);
989
			$thisPlayer->increaseHOF($results['Drones']['ActualDamage']['NumCDs'], array('Combat', 'Forces', 'Combat Drones', 'Killed'), HOF_PUBLIC);
990
			$thisPlayer->increaseHOF($results['Drones']['ActualDamage']['CDs'], array('Combat', 'Forces', 'Combat Drones', 'Damage Done'), HOF_PUBLIC);
991
			$thisPlayer->increaseHOF($results['Drones']['ActualDamage']['NumSDs'], array('Combat', 'Forces', 'Scout Drones', 'Killed'), HOF_PUBLIC);
992
			$thisPlayer->increaseHOF($results['Drones']['ActualDamage']['SDs'], array('Combat', 'Forces', 'Scout Drones', 'Damage Done'), HOF_PUBLIC);
993
			$thisPlayer->increaseHOF($results['Drones']['ActualDamage']['NumMines'] + $results['Drones']['ActualDamage']['NumCDs'] + $results['Drones']['ActualDamage']['NumSDs'], array('Combat', 'Forces', 'Killed'), HOF_PUBLIC);
994
		}
995
		$thisPlayer->increaseExperience(IRound($results['TotalDamage'] * self::EXP_PER_DAMAGE_FORCE));
996
		$thisPlayer->increaseHOF($results['TotalDamage'], array('Combat', 'Forces', 'Damage Done'), HOF_PUBLIC);
997
		$thisPlayer->increaseHOF(1, array('Combat', 'Forces', 'Shots'), HOF_PUBLIC);
998
		return $results;
999
	}
1000
1001
	public function &shootPort(SmrPort $port) {
1002
		$thisPlayer = $this->getPlayer();
1003
		$results = array('Player' => $thisPlayer, 'TotalDamage' => 0, 'Weapons' => []);
1004
		if ($thisPlayer->isDead()) {
1005
			$results['DeadBeforeShot'] = true;
1006
			return $results;
1007
		}
1008
		$results['DeadBeforeShot'] = false;
1009
		foreach ($this->weapons as $orderID => $weapon) {
1010
			$results['Weapons'][$orderID] =& $weapon->shootPort($thisPlayer, $port);
1011
			if ($results['Weapons'][$orderID]['Hit']) {
1012
				$results['TotalDamage'] += $results['Weapons'][$orderID]['ActualDamage']['TotalDamage'];
1013
			}
1014
		}
1015
		if ($this->hasCDs()) {
1016
			$thisCDs = new SmrCombatDrones($this->getGameID(), $this->getCDs());
1017
			$results['Drones'] =& $thisCDs->shootPort($thisPlayer, $port);
1018
			$results['TotalDamage'] += $results['Drones']['ActualDamage']['TotalDamage'];
1019
		}
1020
		$thisPlayer->increaseExperience(IRound($results['TotalDamage'] * self::EXP_PER_DAMAGE_PORT));
1021
		$thisPlayer->increaseHOF($results['TotalDamage'], array('Combat', 'Port', 'Damage Done'), HOF_PUBLIC);
1022
//		$thisPlayer->increaseHOF(1,array('Combat','Port','Shots')); //in SmrPortt::attackedBy()
1023
1024
		// Change alignment if we reach a damage threshold.
1025
		// Increase if player and port races are at war; decrease otherwise.
1026
		if ($results['TotalDamage'] >= SmrPort::DAMAGE_NEEDED_FOR_ALIGNMENT_CHANGE) {
1027
			$relations = Globals::getRaceRelations($thisPlayer->getGameID(), $thisPlayer->getRaceID());
1028
			if ($relations[$port->getRaceID()] <= RELATIONS_WAR) {
1029
				$thisPlayer->increaseAlignment(1);
1030
				$thisPlayer->increaseHOF(1, array('Combat', 'Port', 'Alignment', 'Gain'), HOF_PUBLIC);
1031
			} else {
1032
				$thisPlayer->decreaseAlignment(1);
1033
				$thisPlayer->increaseHOF(1, array('Combat', 'Port', 'Alignment', 'Loss'), HOF_PUBLIC);
1034
			}
1035
		}
1036
		return $results;
1037
	}
1038
1039
	public function &shootPlanet(SmrPlanet $planet, $delayed) {
1040
		$thisPlayer = $this->getPlayer();
1041
		$results = array('Player' => $thisPlayer, 'TotalDamage' => 0, 'Weapons' => []);
1042
		if ($thisPlayer->isDead()) {
1043
			$results['DeadBeforeShot'] = true;
1044
			return $results;
1045
		}
1046
		$results['DeadBeforeShot'] = false;
1047
		foreach ($this->weapons as $orderID => $weapon) {
1048
			$results['Weapons'][$orderID] =& $weapon->shootPlanet($thisPlayer, $planet, $delayed);
1049
			if ($results['Weapons'][$orderID]['Hit']) {
1050
				$results['TotalDamage'] += $results['Weapons'][$orderID]['ActualDamage']['TotalDamage'];
1051
			}
1052
		}
1053
		if ($this->hasCDs()) {
1054
			$thisCDs = new SmrCombatDrones($this->getGameID(), $this->getCDs());
1055
			$results['Drones'] =& $thisCDs->shootPlanet($thisPlayer, $planet, $delayed);
1056
			$results['TotalDamage'] += $results['Drones']['ActualDamage']['TotalDamage'];
1057
		}
1058
		$thisPlayer->increaseExperience(IRound($results['TotalDamage'] * self::EXP_PER_DAMAGE_PLANET));
1059
		$thisPlayer->increaseHOF($results['TotalDamage'], array('Combat', 'Planet', 'Damage Done'), HOF_PUBLIC);
1060
//		$thisPlayer->increaseHOF(1,array('Combat','Planet','Shots')); //in SmrPlanet::attackedBy()
1061
		return $results;
1062
	}
1063
1064
	public function &doWeaponDamage(array $damage) {
1065
		$alreadyDead = $this->getPlayer()->isDead();
1066
		$armourDamage = 0;
1067
		$cdDamage = 0;
1068
		$shieldDamage = 0;
1069
		if (!$alreadyDead) {
1070
			$shieldDamage = $this->doShieldDamage(min($damage['MaxDamage'], $damage['Shield']));
1071
			$damage['MaxDamage'] -= $shieldDamage;
1072
			if (!$this->hasShields() && ($shieldDamage == 0 || $damage['Rollover'])) {
1073
				$cdDamage = $this->doCDDamage(min($damage['MaxDamage'], $damage['Armour']));
1074
				$damage['Armour'] -= $cdDamage;
1075
				$damage['MaxDamage'] -= $cdDamage;
1076
				if (!$this->hasCDs() && ($cdDamage == 0 || $damage['Rollover'])) {
1077
					$armourDamage = $this->doArmourDamage(min($damage['MaxDamage'], $damage['Armour']));
1078
				}
1079
			}
1080
		}
1081
		$return = array(
1082
						'KillingShot' => !$alreadyDead && $this->isDead(),
1083
						'TargetAlreadyDead' => $alreadyDead,
1084
						'Shield' => $shieldDamage,
1085
						'CDs' => $cdDamage,
1086
						'NumCDs' => $cdDamage / CD_ARMOUR,
1087
						'Armour' => $armourDamage,
1088
						'HasCDs' => $this->hasCDs(),
1089
						'TotalDamage' => $shieldDamage + $cdDamage + $armourDamage
1090
		);
1091
		return $return;
1092
	}
1093
1094
	public function &doMinesDamage(array $damage) {
1095
		$alreadyDead = $this->getPlayer()->isDead();
1096
		$armourDamage = 0;
1097
		$cdDamage = 0;
1098
		$shieldDamage = 0;
1099
		if (!$alreadyDead) {
1100
			$shieldDamage = $this->doShieldDamage(min($damage['MaxDamage'], $damage['Shield']));
1101
			$damage['MaxDamage'] -= $shieldDamage;
1102
			if (!$this->hasShields() && ($shieldDamage == 0 || $damage['Rollover'])) { //skip CDs if it's mines
1103
				$armourDamage = $this->doArmourDamage(min($damage['MaxDamage'], $damage['Armour']));
1104
			}
1105
		}
1106
		$return = array(
1107
						'KillingShot' => !$alreadyDead && $this->isDead(),
1108
						'TargetAlreadyDead' => $alreadyDead,
1109
						'Shield' => $shieldDamage,
1110
						'CDs' => $cdDamage,
1111
						'NumCDs' => $cdDamage / CD_ARMOUR,
1112
						'Armour' => $armourDamage,
1113
						'HasCDs' => $this->hasCDs(),
1114
						'TotalDamage' => $shieldDamage + $cdDamage + $armourDamage
1115
		);
1116
		return $return;
1117
	}
1118
1119
	protected function doShieldDamage($damage) {
1120
		$actualDamage = min($this->getShields(), $damage);
1121
		$this->decreaseShields($actualDamage);
1122
		return $actualDamage;
1123
	}
1124
1125
	protected function doCDDamage($damage) {
1126
		$actualDamage = min($this->getCDs(), IFloor($damage / CD_ARMOUR));
1127
		$this->decreaseCDs($actualDamage);
1128
		return $actualDamage * CD_ARMOUR;
1129
	}
1130
1131
	protected function doArmourDamage($damage) {
1132
		$actualDamage = min($this->getArmour(), $damage);
1133
		$this->decreaseArmour($actualDamage);
1134
		return $actualDamage;
1135
	}
1136
1137
	/**
1138
	 * Returns the maneuverability rating for this ship.
1139
	 */
1140
	public function getMR() : int {
1141
		//700 - [ (ship hit points / 25) + (ship stat factors) ]
1142
		//Minimum value of 0 because negative values cause issues with calculations calling this routine
1143
		return max(0, IRound(
1144
						700 -
1145
						(
1146
							(
1147
								$this->getShields()
1148
								+$this->getArmour()
1149
								+$this->getCDs() * 3
1150
							) / 25
1151
							+(
1152
								$this->getCargoHolds() / 100
1153
								-$this->getSpeed() * 5
1154
								+($this->getHardpoints()/*+$ship['Increases']['Ship Power']*/) * 5
1155
								/*+(
1156
									$ship['Increases']['Mines']
1157
									+$ship['Increases']['Scout Drones']
1158
								)/12*/
1159
								+$this->getCDs() / 5
1160
							)
1161
						)
1162
					)
1163
					);
1164
	}
1165
1166
}
1167