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

Failed Conditions
Pull Request — master (#1094)
by Dan
04:47
created

SmrSector::__construct()   A

Complexity

Conditions 5
Paths 9

Size

Total Lines 34
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 25
c 1
b 0
f 0
nc 9
nop 4
dl 0
loc 34
rs 9.2088
1
<?php declare(strict_types=1);
2
3
// Exception thrown when a sector cannot be found in the database
4
class SectorNotFoundException extends Exception {}
5
6
class SmrSector {
7
	protected static array $CACHE_SECTORS = [];
8
	protected static array $CACHE_GALAXY_SECTORS = [];
9
	protected static array $CACHE_LOCATION_SECTORS = [];
10
11
	protected Smr\Database $db;
12
	protected string $SQL;
13
14
	protected int $gameID;
15
	protected int $sectorID;
16
	protected int $battles;
17
	protected int $galaxyID;
18
	protected array $visited = [];
19
	protected array $links;
20
	protected int $warp;
21
22
	protected bool $hasChanged = false;
23
	protected bool $isNew = false;
24
25
	/**
26
	 * Constructs the sector to determine if it exists.
27
	 * Returns a boolean value.
28
	 */
29
	public static function sectorExists(int $gameID, int $sectorID) : bool {
30
		try {
31
			self::getSector($gameID, $sectorID);
32
			return true;
33
		} catch (SectorNotFoundException $e) {
34
			return false;
35
		}
36
	}
37
38
	public static function getGalaxySectors(int $gameID, int $galaxyID, bool $forceUpdate = false) : array {
39
		if ($forceUpdate || !isset(self::$CACHE_GALAXY_SECTORS[$gameID][$galaxyID])) {
40
			$db = Smr\Database::getInstance();
41
			$dbResult = $db->read('SELECT * FROM sector WHERE game_id = ' . $db->escapeNumber($gameID) . ' AND galaxy_id=' . $db->escapeNumber($galaxyID) . ' ORDER BY sector_id ASC');
42
			$sectors = array();
43
			foreach ($dbResult->records() as $dbRecord) {
44
				$sectorID = $dbRecord->getInt('sector_id');
45
				$sectors[$sectorID] = self::getSector($gameID, $sectorID, $forceUpdate, $dbRecord);
46
			}
47
			self::$CACHE_GALAXY_SECTORS[$gameID][$galaxyID] = $sectors;
48
		}
49
		return self::$CACHE_GALAXY_SECTORS[$gameID][$galaxyID];
50
	}
51
52
	public static function getLocationSectors(int $gameID, int $locationTypeID, bool $forceUpdate = false) : array {
53
		if ($forceUpdate || !isset(self::$CACHE_LOCATION_SECTORS[$gameID][$locationTypeID])) {
54
			$db = Smr\Database::getInstance();
55
			$dbResult = $db->read('SELECT * FROM location JOIN sector USING (game_id, sector_id) WHERE location_type_id = ' . $db->escapeNumber($locationTypeID) . ' AND game_id=' . $db->escapeNumber($gameID) . ' ORDER BY sector_id ASC');
56
			$sectors = array();
57
			foreach ($dbResult->records() as $dbRecord) {
58
				$sectorID = $dbRecord->getInt('sector_id');
59
				$sectors[$sectorID] = self::getSector($gameID, $sectorID, $forceUpdate, $dbRecord);
60
			}
61
			self::$CACHE_LOCATION_SECTORS[$gameID][$locationTypeID] = $sectors;
62
		}
63
		return self::$CACHE_LOCATION_SECTORS[$gameID][$locationTypeID];
64
	}
65
66
	public static function getSector(int $gameID, int $sectorID, bool $forceUpdate = false, Smr\DatabaseRecord $dbRecord = null) : self {
67
		if (!isset(self::$CACHE_SECTORS[$gameID][$sectorID]) || $forceUpdate) {
68
			self::$CACHE_SECTORS[$gameID][$sectorID] = new SmrSector($gameID, $sectorID, false, $dbRecord);
69
		}
70
		return self::$CACHE_SECTORS[$gameID][$sectorID];
71
	}
72
73
	public static function clearCache() : void {
74
		self::$CACHE_LOCATION_SECTORS = array();
75
		self::$CACHE_GALAXY_SECTORS = array();
76
		self::$CACHE_SECTORS = array();
77
	}
78
79
	public static function saveSectors() : void {
80
		foreach (self::$CACHE_SECTORS as $gameSectors) {
81
			foreach ($gameSectors as $sector) {
82
				$sector->update();
83
			}
84
		}
85
	}
86
87
	public static function createSector(int $gameID, int $sectorID) : self {
88
		if (!isset(self::$CACHE_SECTORS[$gameID][$sectorID])) {
89
			$s = new SmrSector($gameID, $sectorID, true);
90
			self::$CACHE_SECTORS[$gameID][$sectorID] = $s;
91
		}
92
		return self::$CACHE_SECTORS[$gameID][$sectorID];
93
	}
94
95
	protected function __construct(int $gameID, int $sectorID, bool $create = false, Smr\DatabaseRecord $dbRecord = null) {
96
		$this->db = Smr\Database::getInstance();
97
		$this->SQL = 'game_id = ' . $this->db->escapeNumber($gameID) . ' AND sector_id = ' . $this->db->escapeNumber($sectorID);
98
99
		// Do we already have a database record for this sector?
100
		if ($dbRecord === null) {
101
			$dbResult = $this->db->read('SELECT * FROM sector WHERE ' . $this->SQL . ' LIMIT 1');
102
			if ($dbResult->hasRecord()) {
103
				$dbRecord = $dbResult->record();
104
			}
105
		}
106
		$sectorExists = $dbRecord !== null;
107
108
		$this->gameID = $gameID;
109
		$this->sectorID = $sectorID;
110
111
		if ($sectorExists) {
112
			$this->galaxyID = $dbRecord->getInt('galaxy_id');
113
			$this->battles = $dbRecord->getInt('battles');
114
115
			$this->links = [
116
				'Up' => $dbRecord->getInt('link_up'),
117
				'Down' => $dbRecord->getInt('link_down'),
118
				'Left' => $dbRecord->getInt('link_left'),
119
				'Right' => $dbRecord->getInt('link_right'),
120
			];
121
			$this->warp = $dbRecord->getInt('warp');
122
		} elseif ($create) {
123
			$this->battles = 0;
124
			$this->links = [];
125
			$this->warp = 0;
126
			$this->isNew = true;
127
		} else {
128
			throw new SectorNotFoundException('No sector ' . $sectorID . ' in game ' . $gameID);
129
		}
130
	}
131
132
	public function update() : void {
133
		if ($this->isNew) {
134
			$this->db->write('INSERT INTO sector(sector_id,game_id,galaxy_id,link_up,link_down,link_left,link_right,warp)
135
								values
136
								(' . $this->db->escapeNumber($this->getSectorID()) .
137
								',' . $this->db->escapeNumber($this->getGameID()) .
138
								',' . $this->db->escapeNumber($this->getGalaxyID()) .
139
								',' . $this->db->escapeNumber($this->getLinkUp()) .
140
								',' . $this->db->escapeNumber($this->getLinkDown()) .
141
								',' . $this->db->escapeNumber($this->getLinkLeft()) .
142
								',' . $this->db->escapeNumber($this->getLinkRight()) .
143
								',' . $this->db->escapeNumber($this->getWarp()) .
144
								')');
145
		} elseif ($this->hasChanged) {
146
			$this->db->write('UPDATE sector SET battles = ' . $this->db->escapeNumber($this->getBattles()) .
147
									', galaxy_id=' . $this->db->escapeNumber($this->getGalaxyID()) .
148
									', link_up=' . $this->db->escapeNumber($this->getLinkUp()) .
149
									', link_right=' . $this->db->escapeNumber($this->getLinkRight()) .
150
									', link_down=' . $this->db->escapeNumber($this->getLinkDown()) .
151
									', link_left=' . $this->db->escapeNumber($this->getLinkLeft()) .
152
									', warp=' . $this->db->escapeNumber($this->getWarp()) .
153
								' WHERE ' . $this->SQL . ' LIMIT 1');
154
		}
155
		$this->isNew = false;
156
		$this->hasChanged = false;
157
	}
158
159
	public function markVisited(AbstractSmrPlayer $player) : void {
160
		if ($this->hasPort()) {
161
			$this->getPort()->addCachePort($player->getAccountID());
162
		}
163
164
		//now delete the entry from visited
165
		if (!$this->isVisited($player)) {
166
			$this->db->write('DELETE FROM player_visited_sector WHERE ' . $this->SQL . '
167
								 AND account_id = ' . $this->db->escapeNumber($player->getAccountID()) . ' LIMIT 1');
168
		}
169
		$this->visited[$player->getAccountID()] = true;
170
	}
171
172
	public function hasWeaponShop() : bool {
173
		foreach ($this->getLocations() as $location) {
174
			if ($location->isWeaponSold()) {
175
				return true;
176
			}
177
		}
178
		return false;
179
	}
180
181
	public function hasHQ() : bool {
182
		foreach ($this->getLocations() as $location) {
183
			if ($location->isHQ()) {
184
				return true;
185
			}
186
		}
187
		return false;
188
	}
189
190
	public function hasUG() : bool {
191
		foreach ($this->getLocations() as $location) {
192
			if ($location->isUG()) {
193
				return true;
194
			}
195
		}
196
		return false;
197
	}
198
199
	public function hasShipShop() : bool {
200
		foreach ($this->getLocations() as $location) {
201
			if ($location->isShipSold()) {
202
				return true;
203
			}
204
		}
205
		return false;
206
	}
207
208
	public function offersFederalProtection() : bool {
209
		foreach ($this->getLocations() as $location) {
210
			if ($location->isFed()) {
211
				return true;
212
			}
213
		}
214
		return false;
215
	}
216
217
	public function getFedRaceIDs() : array {
218
		$raceIDs = array();
219
		foreach ($this->getLocations() as $location) {
220
			if ($location->isFed()) {
221
				$raceIDs[$location->getRaceID()] = $location->getRaceID();
222
			}
223
		}
224
		return $raceIDs;
225
	}
226
227
	public function hasBar() : bool {
228
		foreach ($this->getLocations() as $location) {
229
			if ($location->isBar()) {
230
				return true;
231
			}
232
		}
233
		return false;
234
	}
235
236
	public function hasHardwareShop() : bool {
237
		foreach ($this->getLocations() as $location) {
238
			if ($location->isHardwareSold()) {
239
				return true;
240
			}
241
		}
242
		return false;
243
	}
244
245
	public function hasBank() : bool {
246
		foreach ($this->getLocations() as $location) {
247
			if ($location->isBank()) {
248
				return true;
249
			}
250
		}
251
		return false;
252
	}
253
254
	public function enteringSector(AbstractSmrPlayer $player, int $movementType) : void {
255
		// send scout messages to user
256
		$message = 'Your forces have spotted ' . $player->getBBLink() . ' ';
257
		$message .= match($movementType) {
258
			MOVEMENT_JUMP => 'jumping into',
259
			MOVEMENT_WARP => 'warping into',
260
			MOVEMENT_WALK => 'entering',
261
		};
262
		$message .= ' sector ' . Globals::getSectorBBLink($this->getSectorID());
263
264
		$forces = $this->getForces();
265
		foreach ($forces as $force) {
266
			$force->ping($message, $player);
267
		}
268
	}
269
270
	public function leavingSector(AbstractSmrPlayer $player, int $movementType) : void {
271
		// send scout messages to user
272
		$message = 'Your forces have spotted ' . $player->getBBLink() . ' ';
273
		$message .= match($movementType) {
274
			MOVEMENT_JUMP => 'jumping from',
275
			MOVEMENT_WARP => 'warping from',
276
			MOVEMENT_WALK => 'leaving',
277
		};
278
		$message .= ' sector ' . Globals::getSectorBBLink($this->getSectorID());
279
280
		// iterate over all scout drones in sector
281
		foreach ($this->getForces() as $force) {
282
			$force->ping($message, $player);
283
		}
284
		$this->db->write('UPDATE sector_has_forces SET refresher = 0 WHERE ' . $this->SQL . '
285
								AND refresher = ' . $this->db->escapeNumber($player->getAccountID()));
286
	}
287
288
	public function diedHere(AbstractSmrPlayer $player) : void {
289
		// iterate over all scout drones in sector
290
		foreach ($this->getForces() as $force) {
291
			// send scout messages to user
292
			$message = 'Your forces have spotted that ' . $player->getBBLink() . ' has been <span class="red">DESTROYED</span> in sector ' . Globals::getSectorBBLink($this->sectorID);
293
			$force->ping($message, $player);
294
		}
295
	}
296
297
	public function getSQL() : string {
298
		return $this->SQL;
299
	}
300
301
	public function getGameID() : int {
302
		return $this->gameID;
303
	}
304
305
	public function getSectorID() : int {
306
		return $this->sectorID;
307
	}
308
309
	public function getGalaxyID() : int {
310
		return $this->galaxyID;
311
	}
312
313
	public function setGalaxyID(int $galaxyID) : void {
314
		if (isset($this->galaxyID) && $this->galaxyID == $galaxyID) {
315
			return;
316
		}
317
		$this->galaxyID = $galaxyID;
318
		$this->hasChanged = true;
319
	}
320
321
	public function getNumberOfLinks() : int {
322
		$num = 0;
323
		foreach ($this->getLinks() as $link) {
324
			if ($link !== 0) {
325
				$num++;
326
			}
327
		}
328
		return $num;
329
	}
330
331
	public function getNumberOfConnections() : int {
332
		$links = $this->getNumberOfLinks();
333
		if ($this->hasWarp()) {
334
			$links++;
335
		}
336
		return $links;
337
	}
338
339
	public function getGalaxy() : SmrGalaxy {
340
		return SmrGalaxy::getGalaxy($this->getGameID(), $this->getGalaxyID());
341
	}
342
343
	public function getNeighbourID(string $dir) : int {
344
		if ($this->hasLink($dir)) {
345
			return $this->getLink($dir);
346
		}
347
		$galaxy = $this->getGalaxy();
348
		$neighbour = $this->getSectorID();
349
		switch ($dir) {
350
			case 'Up':
351
				$neighbour -= $galaxy->getWidth();
352
				if ($neighbour < $galaxy->getStartSector()) {
353
					$neighbour += $galaxy->getSize();
354
				}
355
			break;
356
			case 'Down':
357
				$neighbour += $galaxy->getWidth();
358
				if ($neighbour > $galaxy->getEndSector()) {
359
					$neighbour -= $galaxy->getSize();
360
				}
361
			break;
362
			case 'Left':
363
				$neighbour -= 1;
364
				if ((1 + $neighbour - $galaxy->getStartSector()) % $galaxy->getWidth() == 0) {
365
					$neighbour += $galaxy->getWidth();
366
				}
367
			break;
368
			case 'Right':
369
				$neighbour += 1;
370
				if (($neighbour - $galaxy->getStartSector()) % $galaxy->getWidth() == 0) {
371
					$neighbour -= $galaxy->getWidth();
372
				}
373
			break;
374
			default:
375
				throw new Exception($dir . ': is not a valid direction');
376
		}
377
		return $neighbour;
378
	}
379
380
	public function getSectorDirection(int $sectorID) : string {
381
		if ($sectorID == $this->getSectorID()) {
382
			return 'Current';
383
		}
384
		$dir = array_search($sectorID, $this->getLinks());
385
		if ($dir !== false) {
386
			return $dir;
387
		}
388
		if ($sectorID == $this->getWarp()) {
389
			return 'Warp';
390
		}
391
		return 'None';
392
	}
393
394
	public function getNeighbourSector(string $dir) : self {
395
		return SmrSector::getSector($this->getGameID(), $this->getNeighbourID($dir));
396
	}
397
398
	public function getLinks() : array {
399
		return $this->links;
400
	}
401
402
	public function isLinked(int $sectorID) : bool {
403
		return in_array($sectorID, $this->links) || $sectorID == $this->getWarp();
404
	}
405
406
	public function getLink(string $name) : int {
407
		return $this->links[$name] ?? 0;
408
	}
409
410
	public function hasLink(string $name) : bool {
411
		return $this->getLink($name) != 0;
412
	}
413
414
	public function getLinkSector(string $name) : self|false {
415
		if ($this->hasLink($name)) {
416
			return SmrSector::getSector($this->getGameID(), $this->getLink($name));
417
		}
418
		return false;
419
	}
420
421
	/**
422
	 * Cannot be used for Warps
423
	 */
424
	public function setLink(string $name, int $linkID) : void {
425
		if ($this->getLink($name) == $linkID) {
426
			return;
427
		}
428
		if ($linkID == 0) {
429
			unset($this->links[$name]);
430
		} else {
431
			$this->links[$name] = $linkID;
432
		}
433
		$this->hasChanged = true;
434
	}
435
436
	/**
437
	 * Cannot be used for Warps
438
	 */
439
	public function setLinkSector(string $dir, SmrSector $linkSector) : void {
440
		if ($this->getLink($dir) == $linkSector->getSectorID() || $linkSector->equals($this)) {
441
			return;
442
		}
443
		$this->setLink($dir, $linkSector->getSectorID());
444
		$linkSector->setLink(self::oppositeDir($dir), $this->getSectorID());
445
		$this->hasChanged = true;
446
	}
447
448
	/**
449
	 * Cannot be used for Warps
450
	 */
451
	public function enableLink(string $dir) : void {
452
		$this->setLinkSector($dir, $this->getNeighbourSector($dir));
453
	}
454
455
	/**
456
	 * Cannot be used for Warps
457
	 */
458
	public function disableLink(string $dir) : void {
459
		$this->setLink($dir, 0);
460
		$this->getNeighbourSector($dir)->setLink(self::oppositeDir($dir), 0);
461
	}
462
463
	/**
464
	 * Cannot be used for Warps
465
	 */
466
	public function toggleLink(string $dir) : void {
467
		if ($this->hasLink($dir)) {
468
			$this->disableLink($dir);
469
		} else {
470
			$this->enableLink($dir);
471
		}
472
	}
473
474
	protected static function oppositeDir(string $dir) : string {
475
		return match($dir) {
476
			'Up' => 'Down',
477
			'Down' => 'Up',
478
			'Left' => 'Right',
479
			'Right' => 'Left',
480
			'Warp' => 'Warp',
481
		};
482
	}
483
484
	public function getLinkUp() : int {
485
		return $this->getLink('Up');
486
	}
487
488
	public function setLinkUp(int $linkID) : void {
489
		$this->setLink('Up', $linkID);
490
	}
491
492
	public function hasLinkUp() : bool {
493
		return $this->hasLink('Up');
494
	}
495
496
	public function getLinkDown() : int {
497
		return $this->getLink('Down');
498
	}
499
500
	public function setLinkDown(int $linkID) : void {
501
		$this->setLink('Down', $linkID);
502
	}
503
504
	public function hasLinkDown() : bool {
505
		return $this->hasLink('Down');
506
	}
507
508
	public function getLinkLeft() : int {
509
		return $this->getLink('Left');
510
	}
511
512
	public function hasLinkLeft() : bool {
513
		return $this->hasLink('Left');
514
	}
515
516
	public function setLinkLeft(int $linkID) : void {
517
		$this->setLink('Left', $linkID);
518
	}
519
520
	public function getLinkRight() : int {
521
		return $this->getLink('Right');
522
	}
523
524
	public function hasLinkRight() : bool {
525
		return $this->hasLink('Right');
526
	}
527
528
	public function setLinkRight(int $linkID) : void {
529
		$this->setLink('Right', $linkID);
530
	}
531
532
	/**
533
	 * Returns the warp sector if the sector has a warp; returns 0 otherwise.
534
	 */
535
	public function getWarp() : int {
536
		return $this->warp;
537
	}
538
539
	public function getWarpSector() : self {
540
		return SmrSector::getSector($this->getGameID(), $this->getWarp());
541
	}
542
543
	public function hasWarp() : bool {
544
		return $this->getWarp() != 0;
545
	}
546
547
	/**
548
	 * Set the warp sector for both $this and $warp to ensure
549
	 * a consistent 2-way warp.
550
	 */
551
	public function setWarp(SmrSector $warp) : void {
552
		if ($this->getWarp() == $warp->getSectorID() &&
553
		    $warp->getWarp() == $this->getSectorID()) {
554
			// Warps are already set correctly!
555
			return;
556
		}
557
558
		if ($this->equals($warp)) {
559
			throw new Exception('Sector must not warp to itself!');
560
		}
561
562
		// Can only have 1 warp per sector
563
		foreach ([[$warp, $this], [$this, $warp]] as $sectors) {
564
			$A = $sectors[0];
565
			$B = $sectors[1];
566
			if ($A->hasWarp() && $A->getWarp() != $B->getSectorID()) {
567
				throw new Exception('Sector ' . $A->getSectorID() . ' already has a warp (to ' . $A->getWarp() . ')!');
568
			}
569
		}
570
571
		$this->warp = $warp->getSectorID();
572
		$this->hasChanged = true;
573
574
		if ($warp->getWarp() != $this->getSectorID()) {
575
			// Set the other side if needed
576
			$warp->setWarp($this);
577
		}
578
	}
579
580
	/**
581
	 * Remove the warp sector for both sides of the warp.
582
	 */
583
	public function removeWarp() : void {
584
		if (!$this->hasWarp()) {
585
			return;
586
		}
587
588
		$warp = $this->getWarpSector();
589
		if ($warp->hasWarp() && $warp->getWarp() != $this->getSectorID()) {
590
			throw new Exception('Warp sectors do not match');
591
		}
592
593
		$this->warp = 0;
594
		$this->hasChanged = true;
595
596
		if ($warp->hasWarp()) {
597
			$warp->removeWarp();
598
		}
599
	}
600
601
	public function hasPort() : bool {
602
		return $this->getPort()->exists();
603
	}
604
605
	public function getPort() : SmrPort {
606
		return SmrPort::getPort($this->getGameID(), $this->getSectorID());
607
	}
608
609
	public function createPort() : SmrPort {
610
		return SmrPort::createPort($this->getGameID(), $this->getSectorID());
611
	}
612
613
	public function removePort() : void {
614
		SmrPort::removePort($this->getGameID(), $this->getSectorID());
615
	}
616
617
	public function hasCachedPort(AbstractSmrPlayer $player = null) : bool {
618
		return $this->getCachedPort($player) !== false;
619
	}
620
621
	public function getCachedPort(AbstractSmrPlayer $player = null) : SmrPort|false {
622
		if ($player === null) {
623
			return false;
624
		}
625
		return SmrPort::getCachedPort($this->getGameID(), $this->getSectorID(), $player->getAccountID());
626
	}
627
628
	public function hasAnyLocationsWithAction() : bool {
629
		$locations = SmrLocation::getSectorLocations($this->getGameID(), $this->getSectorID());
630
		$hasAction = false;
631
		foreach ($locations as $location) {
632
			if ($location->hasAction()) {
633
				$hasAction = true;
634
			}
635
		}
636
		return $hasAction;
637
	}
638
639
	public function hasLocation(int $locationTypeID = null) : bool {
640
		$locations = $this->getLocations();
641
		if (count($locations) == 0) {
642
			return false;
643
		}
644
		if ($locationTypeID === null) {
645
			return true;
646
		}
647
		foreach ($locations as $location) {
648
			if ($location->getTypeID() == $locationTypeID) {
649
				return true;
650
			}
651
		}
652
		return false;
653
	}
654
655
	public function getLocations() : array {
656
		return SmrLocation::getSectorLocations($this->getGameID(), $this->getSectorID());
657
	}
658
659
	public function addLocation(SmrLocation $location) : void {
660
		SmrLocation::addSectorLocation($this->getGameID(), $this->getSectorID(), $location);
661
	}
662
663
	public function removeAllLocations() : void {
664
		SmrLocation::removeSectorLocations($this->getGameID(), $this->getSectorID());
665
	}
666
667
	public function hasPlanet() : bool {
668
		return $this->getPlanet()->exists();
669
	}
670
671
	public function getPlanet() : SmrPlanet {
672
		return SmrPlanet::getPlanet($this->getGameID(), $this->getSectorID());
673
	}
674
675
	public function createPlanet(int $type = 1) : SmrPlanet {
676
		return SmrPlanet::createPlanet($this->getGameID(), $this->getSectorID(), $type);
677
	}
678
679
	public function removePlanet() : void {
680
		SmrPlanet::removePlanet($this->getGameID(), $this->getSectorID());
681
	}
682
683
	/**
684
	 * Removes ports, planets, locations, and warps from this sector.
685
	 * NOTE: This should only be used by the universe generator!
686
	 */
687
	public function removeAllFixtures() : void {
688
		if ($this->hasPort()) {
689
			$this->removePort();
690
		}
691
		if ($this->hasPlanet()) {
692
			$this->removePlanet();
693
		}
694
		if ($this->hasLocation()) {
695
			$this->removeAllLocations();
696
		}
697
		if ($this->hasWarp()) {
698
			$this->removeWarp();
699
		}
700
	}
701
702
	public function hasForces() : bool {
703
		return count($this->getForces()) > 0;
704
	}
705
706
	public function hasEnemyForces(AbstractSmrPlayer $player = null) : bool {
707
		if ($player == null || !$this->hasForces()) {
708
			return false;
709
		}
710
		foreach ($this->getForces() as $force) {
711
			if (!$player->forceNAPAlliance($force->getOwner())) {
712
				return true;
713
			}
714
		}
715
		return false;
716
	}
717
718
	public function getEnemyForces(AbstractSmrPlayer $player) : array {
719
		$enemyForces = array();
720
		foreach ($this->getForces() as $force) {
721
			if (!$player->forceNAPAlliance($force->getOwner())) {
722
				$enemyForces[] = $force;
723
			}
724
		}
725
		return $enemyForces;
726
	}
727
728
	/**
729
	 * Returns true if any forces in this sector belong to $player.
730
	 */
731
	public function hasPlayerForces(AbstractSmrPlayer $player) : bool {
732
		foreach ($this->getForces() as $force) {
733
			if ($player->getAccountID() == $force->getOwnerID()) {
734
				return true;
735
			}
736
		}
737
		return false;
738
	}
739
740
	public function hasFriendlyForces(AbstractSmrPlayer $player = null) : bool {
741
		if ($player == null || !$this->hasForces()) {
742
			return false;
743
		}
744
		foreach ($this->getForces() as $force) {
745
			if ($player->forceNAPAlliance($force->getOwner())) {
746
				return true;
747
			}
748
		}
749
		return false;
750
	}
751
752
	public function getFriendlyForces(AbstractSmrPlayer $player) : array {
753
		$friendlyForces = array();
754
		foreach ($this->getForces() as $force) {
755
			if ($player->forceNAPAlliance($force->getOwner())) {
756
				$friendlyForces[] = $force;
757
			}
758
		}
759
		return $friendlyForces;
760
	}
761
762
	public function getForces() : array {
763
		return SmrForce::getSectorForces($this->getGameID(), $this->getSectorID());
764
	}
765
766
	public function getPlayers() : array {
767
		return SmrPlayer::getSectorPlayers($this->getGameID(), $this->getSectorID());
768
	}
769
770
	public function hasPlayers() : bool {
771
		return count($this->getPlayers()) > 0;
772
	}
773
774
	public function getOtherTraders(AbstractSmrPlayer $player) : array {
775
		$players = SmrPlayer::getSectorPlayers($this->getGameID(), $this->getSectorID()); //Do not use & because we unset something and only want that in what we return
776
		unset($players[$player->getAccountID()]);
777
		return $players;
778
	}
779
780
	public function hasOtherTraders(AbstractSmrPlayer $player) : bool {
781
		return count($this->getOtherTraders($player)) > 0;
782
	}
783
784
	public function hasEnemyTraders(AbstractSmrPlayer $player = null) : bool {
785
		if ($player == null || !$this->hasOtherTraders($player)) {
786
			return false;
787
		}
788
		$otherPlayers = $this->getOtherTraders($player);
789
		foreach ($otherPlayers as $otherPlayer) {
790
			if (!$player->traderNAPAlliance($otherPlayer)
791
				&& !$otherPlayer->hasNewbieTurns()
792
				&& !$otherPlayer->hasFederalProtection()) {
793
				return true;
794
			}
795
		}
796
		return false;
797
	}
798
799
	public function hasFriendlyTraders(AbstractSmrPlayer $player = null) : bool {
800
		if ($player == null || !$this->hasOtherTraders($player)) {
801
			return false;
802
		}
803
		$otherPlayers = $this->getOtherTraders($player);
804
		foreach ($otherPlayers as $otherPlayer) {
805
			if ($player->traderNAPAlliance($otherPlayer)) {
806
				return true;
807
			}
808
		}
809
		return false;
810
	}
811
812
	/**
813
	 * Is the $player's alliance flagship in this sector?
814
	 */
815
	public function hasAllianceFlagship(AbstractSmrPlayer $player = null) : bool {
816
		if (is_null($player) || !$player->hasAlliance() || !$player->getAlliance()->hasFlagship()) {
817
			return false;
818
		}
819
		$flagshipID = $player->getAlliance()->getFlagshipID();
820
		foreach ($this->getPlayers() as $sectorPlayer) {
821
			if ($sectorPlayer->getAccountID() == $flagshipID) {
822
				return true;
823
			}
824
		}
825
		return false;
826
	}
827
828
	public function hasProtectedTraders(AbstractSmrPlayer $player = null) : bool {
829
		if ($player == null || !$this->hasOtherTraders($player)) {
830
			return false;
831
		}
832
		$otherPlayers = $this->getOtherTraders($player);
833
		foreach ($otherPlayers as $otherPlayer) {
834
			if (!$player->traderNAPAlliance($otherPlayer)
835
				&& ($otherPlayer->hasNewbieTurns() || $otherPlayer->hasFederalProtection())) {
836
				return true;
837
			}
838
		}
839
		return false;
840
	}
841
842
	public function getFightingTradersAgainstForces(AbstractSmrPlayer $attackingPlayer, bool $bump) : array {
0 ignored issues
show
Unused Code introduced by
The parameter $bump is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

842
	public function getFightingTradersAgainstForces(AbstractSmrPlayer $attackingPlayer, /** @scrutinizer ignore-unused */ bool $bump) : array {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
843
		// Whether bumping or attacking, only the current player fires at forces
844
		return array($attackingPlayer);
845
	}
846
847
	public function getFightingTradersAgainstPort(AbstractSmrPlayer $attackingPlayer, SmrPort $defendingPort) : array {
0 ignored issues
show
Unused Code introduced by
The parameter $defendingPort is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

847
	public function getFightingTradersAgainstPort(AbstractSmrPlayer $attackingPlayer, /** @scrutinizer ignore-unused */ SmrPort $defendingPort) : array {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
848
		$fightingPlayers = array();
849
		$alliancePlayers = SmrPlayer::getSectorPlayersByAlliances($this->getGameID(), $this->getSectorID(), array($attackingPlayer->getAllianceID()));
850
		foreach ($alliancePlayers as $accountID => $player) {
851
			if ($player->canFight()) {
852
				if ($attackingPlayer->traderAttackPortAlliance($player)) {
853
					$fightingPlayers[$accountID] = $alliancePlayers[$accountID];
854
				}
855
			}
856
		}
857
		return self::limitFightingTraders($fightingPlayers, $attackingPlayer, MAXIMUM_PORT_FLEET_SIZE);
858
	}
859
860
	public function getFightingTradersAgainstPlanet(AbstractSmrPlayer $attackingPlayer, SmrPlanet $defendingPlanet) : array {
861
		$fightingPlayers = array();
862
		$alliancePlayers = SmrPlayer::getSectorPlayersByAlliances($this->getGameID(), $this->getSectorID(), array($attackingPlayer->getAllianceID()));
863
		if (count($alliancePlayers) > 0) {
864
			$planetOwner = $defendingPlanet->getOwner();
865
			foreach ($alliancePlayers as $accountID => $player) {
866
				if ($player->canFight()) {
867
					if ($attackingPlayer->traderAttackPlanetAlliance($player) && !$planetOwner->planetNAPAlliance($player)) {
868
						$fightingPlayers[$accountID] = $alliancePlayers[$accountID];
869
					}
870
				}
871
			}
872
		}
873
		return self::limitFightingTraders($fightingPlayers, $attackingPlayer, min($defendingPlanet->getMaxAttackers(), MAXIMUM_PLANET_FLEET_SIZE));
874
	}
875
876
	public function getFightingTraders(AbstractSmrPlayer $attackingPlayer, AbstractSmrPlayer $defendingPlayer, bool $checkForCloak = false) : array {
877
		if ($attackingPlayer->traderNAPAlliance($defendingPlayer)) {
878
			throw new Exception('These traders are NAPed.');
879
		}
880
		$fightingPlayers = array('Attackers' => array(), 'Defenders' => array());
881
		$alliancePlayers = SmrPlayer::getSectorPlayersByAlliances($this->getGameID(), $this->getSectorID(), array($attackingPlayer->getAllianceID(), $defendingPlayer->getAllianceID()));
882
		$attackers = array();
883
		$defenders = array();
884
		foreach ($alliancePlayers as $accountID => $player) {
885
			if ($player->canFight()) {
886
				if ($attackingPlayer->traderAttackTraderAlliance($player) && !$defendingPlayer->traderDefendTraderAlliance($player) && !$defendingPlayer->traderNAPAlliance($player)) {
887
					$attackers[] = $alliancePlayers[$accountID];
888
				} elseif ($defendingPlayer->traderDefendTraderAlliance($player) && !$attackingPlayer->traderAttackTraderAlliance($player) && !$attackingPlayer->traderNAPAlliance($player) && ($checkForCloak === false || $attackingPlayer->canSee($player))) {
889
					$defenders[] = $alliancePlayers[$accountID];
890
				}
891
			}
892
		}
893
		$attackers = self::limitFightingTraders($attackers, $attackingPlayer, MAXIMUM_PVP_FLEET_SIZE);
894
		shuffle($attackers);
895
		foreach ($attackers as $attacker) {
896
			$fightingPlayers['Attackers'][$attacker->getAccountID()] = $attacker;
897
		}
898
		$defenders = self::limitFightingTraders($defenders, $defendingPlayer, MAXIMUM_PVP_FLEET_SIZE);
899
		shuffle($defenders);
900
		foreach ($defenders as $defender) {
901
			$fightingPlayers['Defenders'][$defender->getAccountID()] = $defender;
902
		}
903
		return $fightingPlayers;
904
	}
905
906
	public static function limitFightingTraders(array $fightingPlayers, AbstractSmrPlayer $keepPlayer, int $maximumFleetSize) : array {
907
		// Cap fleets to the required size
908
		$fleet_size = count($fightingPlayers);
909
		if ($fleet_size > $maximumFleetSize) {
910
			// We use random key to stop the same people being capped all the time
911
			for ($j = 0; $j < $fleet_size - $maximumFleetSize; ++$j) {
912
				do {
913
					$key = array_rand($fightingPlayers);
914
				} while ($keepPlayer->equals($fightingPlayers[$key]));
915
				unset($fightingPlayers[$key]);
916
			}
917
		}
918
		return $fightingPlayers;
919
	}
920
921
	public function getPotentialFightingTraders(AbstractSmrPlayer $attackingPlayer) : array {
922
		$fightingPlayers = array();
923
		$alliancePlayers = SmrPlayer::getSectorPlayersByAlliances($this->getGameID(), $this->getSectorID(), array($attackingPlayer->getAllianceID()));
924
		foreach ($alliancePlayers as $accountID => $player) {
925
			if ($player->canFight()) {
926
				if ($attackingPlayer->traderAttackTraderAlliance($player)) {
927
					$fightingPlayers['Attackers'][$accountID] = $player;
928
				}
929
			}
930
		}
931
		return $fightingPlayers;
932
	}
933
934
	public function getBattles() : int {
935
		return $this->battles;
936
	}
937
938
	public function setBattles(int $amount) : void {
939
		if ($this->battles == $amount) {
940
			return;
941
		}
942
		$this->battles = $amount;
943
		$this->hasChanged = true;
944
	}
945
946
	public function decreaseBattles(int $amount) : void {
947
		$this->setBattles($this->battles - $amount);
948
	}
949
950
	public function increaseBattles(int $amount) : void {
951
		$this->setBattles($this->battles + $amount);
952
	}
953
954
	public function equals(SmrSector $otherSector) : bool {
955
		return $otherSector->getSectorID() == $this->getSectorID() && $otherSector->getGameID() == $this->getGameID();
956
	}
957
958
	public function isLinkedSector(SmrSector $otherSector) : bool {
959
		return $otherSector->getGameID() == $this->getGameID() && $this->isLinked($otherSector->getSectorID());
960
	}
961
962
	public function isVisited(AbstractSmrPlayer $player = null) : bool {
963
		if ($player === null) {
964
			return true;
965
		}
966
		if (!isset($this->visited[$player->getAccountID()])) {
967
			$dbResult = $this->db->read('SELECT 1 FROM player_visited_sector WHERE ' . $this->SQL . ' AND account_id=' . $this->db->escapeNumber($player->getAccountID()) . ' LIMIT 1');
968
			$this->visited[$player->getAccountID()] = !$dbResult->hasRecord();
969
		}
970
		return $this->visited[$player->getAccountID()];
971
	}
972
973
	public function getLocalMapMoveHREF(AbstractSmrPlayer $player) : string {
974
		return Globals::getSectorMoveHREF($player, $this->getSectorID(), 'map_local.php');
975
	}
976
977
	public function getCurrentSectorMoveHREF(AbstractSmrPlayer $player) : string {
978
		return Globals::getCurrentSectorMoveHREF($player, $this->getSectorID());
979
	}
980
981
	public function getGalaxyMapHREF() : string {
982
		return '?sector_id=' . $this->getSectorID();
983
	}
984
985
	public function getSectorScanHREF(AbstractSmrPlayer $player) : string {
986
		return Globals::getSectorScanHREF($player, $this->getSectorID());
987
	}
988
989
	public function hasX(mixed $x, AbstractSmrPlayer $player = null) : bool {
990
		if ($x instanceof SmrSector) {
991
			return $this->equals($x);
992
		}
993
		if ($x == 'Port') {
994
			return $this->hasPort();
995
		}
996
		if ($x == 'Location') {
997
			return $this->hasLocation();
998
		}
999
		if ($x instanceof SmrLocation) {
1000
			return $this->hasLocation($x->getTypeID());
1001
		}
1002
		if ($x instanceof SmrGalaxy) {
1003
			return $x->contains($this);
1004
		}
1005
1006
		if (is_array($x) && $x['Type'] == 'Good') { //Check if it's possible for port to have X, hacky but nice performance gains
1007
			if ($this->hasPort() && $this->getPort()->hasX($x)) {
1008
				return true;
1009
			}
1010
		}
1011
1012
		//Check if it's possible for location to have X, hacky but nice performance gains
1013
		if ($x instanceof SmrWeaponType || $x instanceof SmrShipType || (is_array($x) && $x['Type'] == 'Hardware') || (is_string($x) && ($x == 'Bank' || $x == 'Bar' || $x == 'Fed' || $x == 'SafeFed' || $x == 'HQ' || $x == 'UG' || $x == 'Hardware' || $x == 'Ship' || $x == 'Weapon'))) {
1014
			foreach ($this->getLocations() as $loc) {
1015
				if ($loc->hasX($x, $player)) {
1016
					return true;
1017
				}
1018
			}
1019
		}
1020
		return false;
1021
	}
1022
}
1023