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
Push — master ( c670fd...b18f1a )
by Dan
20s queued 16s
created

SmrSector   F

Complexity

Total Complexity 292

Size/Duplication

Total Lines 1024
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 490
dl 0
loc 1024
rs 2
c 0
b 0
f 0
wmc 292

110 Methods

Rating   Name   Duplication   Size   Complexity  
A clearCache() 0 4 1
A saveSectors() 0 4 3
A offersFederalProtection() 0 7 3
A markVisited() 0 11 3
A getLocationSectors() 0 12 4
A getFedRaceIDs() 0 8 3
A hasShipShop() 0 7 3
A hasHardwareShop() 0 7 3
A hasHQ() 0 7 3
A update() 0 25 3
A hasWeaponShop() 0 7 3
A getSector() 0 5 3
A createSector() 0 6 2
A sectorExists() 0 6 2
A hasBank() 0 7 3
A hasBar() 0 7 3
B __construct() 0 42 8
A hasUG() 0 7 3
A getGalaxySectors() 0 12 4
A hasLinkLeft() 0 2 1
A diedHere() 0 6 2
A setLinkDown() 0 2 1
A removePlanet() 0 2 1
A setLinkLeft() 0 2 1
A enableLink() 0 2 1
A hasLinkUp() 0 2 1
D hasX() 0 32 26
A getNeighbourSector() 0 2 1
A removeWarp() 0 15 5
A hasFriendlyTraders() 0 11 5
A createPlanet() 0 2 1
A hasPlayerForces() 0 7 3
A addLocation() 0 2 1
A getLinks() 0 2 1
A getBattles() 0 2 1
A getNumberOfLinks() 0 11 4
A setBattles() 0 6 2
A equals() 0 2 2
A removeAllLocations() 0 2 1
A hasAnyLocationsWithAction() 0 9 3
A hasForces() 0 2 1
A oppositeDir() 0 7 1
A getGalaxy() 0 2 1
A hasCachedPort() 0 2 1
A getOtherTraders() 0 4 1
A hasEnemyForces() 0 10 5
A hasLinkRight() 0 2 1
A getLinkDown() 0 2 1
A getSectorDirection() 0 12 4
A getFightingTradersAgainstForces() 0 3 1
A getCachedPort() 0 6 2
A getFightingTradersAgainstPlanet() 0 14 6
A getPlayers() 0 2 1
A isLinked() 0 2 2
A getLinkUp() 0 2 1
A removeAllFixtures() 0 12 5
A getFightingTradersAgainstPort() 0 11 4
A getWarpSector() 0 2 1
A getSQL() 0 2 1
A hasPlanet() 0 2 1
A getPlanet() 0 2 1
A leavingSector() 0 16 2
A getGalaxyMapHREF() 0 2 1
A enteringSector() 0 13 2
A getLink() 0 2 1
A getFriendlyForces() 0 8 3
A getForces() 0 2 1
A hasLocation() 0 14 5
A setLink() 0 10 3
A getNumberOfConnections() 0 6 2
A hasFriendlyForces() 0 10 5
C getFightingTraders() 0 28 14
A getWarp() 0 2 1
A setGalaxyID() 0 6 2
A getSectorID() 0 2 1
A hasOtherTraders() 0 2 1
A getLinkRight() 0 2 1
A hasAllianceFlagship() 0 11 6
A hasPlayers() 0 2 1
A hasPort() 0 2 1
A getLinkLeft() 0 2 1
B hasEnemyTraders() 0 13 7
A isVisited() 0 9 3
B setWarp() 0 26 8
A createPort() 0 2 1
A getLinkSector() 0 5 2
A toggleLink() 0 5 2
A getEnemyForces() 0 8 3
A disableLink() 0 3 1
A getPotentialFightingTraders() 0 11 4
B getNeighbourID() 0 35 10
A setLinkSector() 0 7 3
A limitFightingTraders() 0 13 4
A setLinkRight() 0 2 1
A isLinkedSector() 0 2 2
B hasProtectedTraders() 0 12 7
A hasLink() 0 2 1
A getPort() 0 2 1
A decreaseBattles() 0 2 1
A removePort() 0 2 1
A hasLinkDown() 0 2 1
A getGalaxyID() 0 2 1
A increaseBattles() 0 2 1
A getGameID() 0 2 1
A hasWarp() 0 2 1
A getLocations() 0 2 1
A setLinkUp() 0 2 1
A getSectorScanHREF() 0 2 1
A getLocalMapMoveHREF() 0 2 1
A getCurrentSectorMoveHREF() 0 2 1

How to fix   Complexity   

Complex Class

Complex classes like SmrSector often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SmrSector, and based on these observations, apply Extract Interface, too.

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

851
	public function getFightingTradersAgainstForces(AbstractSmrPlayer $attackingPlayer, /** @scrutinizer ignore-unused */ $bump) {

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...
852
		// Whether bumping or attacking, only the current player fires at forces
853
		return array($attackingPlayer);
854
	}
855
856
	public function getFightingTradersAgainstPort(AbstractSmrPlayer $attackingPlayer, SmrPort $defendingPort) {
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

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

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