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
Push — master ( 0850d7...1083c7 )
by Dan
04:07
created

AbstractSmrPlayer::increaseBountyAmount()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
require_once('missions.inc');
3
4
abstract class AbstractSmrPlayer {
5
	protected $db;
6
7
	const HOF_CHANGED = 1;
8
	const HOF_NEW = 2;
9
10
	protected $accountID;
11
	protected $gameID;
12
	protected $playerName; // This is escaped with htmlentities in the db
13
	protected $playerID;
14
	protected $sectorID;
15
	protected $lastSectorID;
16
	protected $newbieTurns;
17
	protected $dead;
18
	protected $npc;
19
	protected $newbieStatus;
20
	protected $landedOnPlanet;
21
	protected $lastActive;
22
	protected $raceID;
23
	protected $credits;
24
	protected $alignment;
25
	protected $experience;
26
	protected $level;
27
	protected $allianceID;
28
	protected $shipID;
29
	protected $kills;
30
	protected $deaths;
31
	protected $assists;
32
	protected $stats;
33
	protected $pureRelations;
34
	protected $relations;
35
	protected $militaryPayment;
36
	protected $bounties;
37
	protected $turns;
38
	protected $lastCPLAction;
39
	protected $missions;
40
41
	protected $visitedSectors;
42
	protected $allianceRoles = array(
43
		0 => 0
44
	);
45
46
	protected $draftLeader;
47
	protected $gpWriter;
48
	protected $HOF;
49
	protected static $HOFVis;
50
51
	protected $hasChanged = false;
52
	protected $hasHOFChanged = false;
53
	protected static $hasHOFVisChanged = array();
54
	protected $hasBountyChanged = array();
55
56
	protected function __construct() {
57
	}
58
59
	public function getAccountID() {
60
		return $this->accountID;
61
	}
62
63
	public function getGameID() {
64
		return $this->gameID;
65
	}
66
67
	public function getGame() {
68
		return SmrGame::getGame($this->gameID);
69
	}
70
71
	public function getNewbieTurns() {
72
		return $this->newbieTurns;
73
	}
74
75
	public function hasNewbieTurns() {
76
		return $this->getNewbieTurns() > 0;
77
	}
78
	public function setNewbieTurns($newbieTurns) {
79
		if ($this->newbieTurns == $newbieTurns) {
80
			return;
81
		}
82
		$this->newbieTurns = $newbieTurns;
83
		$this->hasChanged = true;
84
	}
85
86
	public function getShipTypeID() {
87
		return $this->shipID;
88
	}
89
90
	public function setShipTypeID($shipID) {
91
		if ($this->shipID == $shipID) {
92
			return;
93
		}
94
		$this->shipID = $shipID;
95
		$this->hasChanged = true;
96
	}
97
98
	/**
99
	 * Get planet owned by this player.
100
	 * Returns false if this player does not own a planet.
101
	 */
102
	public function getPlanet() {
103
		$this->db->query('SELECT * FROM planet WHERE game_id=' . $this->db->escapeNumber($this->getGameID()) . ' AND owner_id=' . $this->db->escapeNumber($this->getAccountID()));
104
		if ($this->db->nextRecord()) {
105
			return SmrPlanet::getPlanet($this->getGameID(), $this->db->getInt('sector_id'), false, $this->db);
106
		} else {
107
			return false;
108
		}
109
	}
110
111
	public function getSectorPlanet() {
112
		return SmrPlanet::getPlanet($this->getGameID(), $this->getSectorID());
113
	}
114
115
	public function getSectorPort() {
116
		return SmrPort::getPort($this->getGameID(), $this->getSectorID());
117
	}
118
119
	public function getSectorID() {
120
		return $this->sectorID;
121
	}
122
123
	public function getSector() {
124
		return SmrSector::getSector($this->getGameID(), $this->getSectorID());
125
	}
126
127
	public function setSectorID($sectorID) {
128
		$this->lastSectorID = $this->getSectorID();
129
		$this->actionTaken('LeaveSector', array('Sector'=>$this->getSector()));
130
		$this->sectorID = $sectorID;
131
		$this->actionTaken('EnterSector', array('Sector'=>$this->getSector()));
132
		$this->hasChanged = true;
133
	}
134
135
	public function getLastSectorID() {
136
		return $this->lastSectorID;
137
	}
138
139
	public function isDead() {
140
		return $this->dead;
141
	}
142
143
	public function isNPC() {
144
		return $this->npc;
145
	}
146
147
	/**
148
	 * Does the player have Newbie status?
149
	 */
150
	public function hasNewbieStatus() {
151
		return $this->newbieStatus;
152
	}
153
154
	/**
155
	 * Update the player's newbie status if it has changed.
156
	 * This function queries the account, so use sparingly.
157
	 */
158
	public function updateNewbieStatus() {
159
		$accountNewbieStatus = !$this->getAccount()->isVeteran();
0 ignored issues
show
Bug introduced by
The method getAccount() does not exist on AbstractSmrPlayer. Did you maybe mean getAccountID()? ( Ignorable by Annotation )

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

159
		$accountNewbieStatus = !$this->/** @scrutinizer ignore-call */ getAccount()->isVeteran();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
160
		if ($this->newbieStatus != $accountNewbieStatus) {
161
			$this->newbieStatus = $accountNewbieStatus;
162
			$this->hasChanged = true;
163
		}
164
	}
165
166
	public function isDraftLeader() {
167
		if (!isset($this->draftLeader)) {
168
			$this->draftLeader = false;
169
			$this->db->query('SELECT 1 FROM draft_leaders WHERE ' . $this->SQL . ' LIMIT 1');
170
			if ($this->db->nextRecord()) {
171
				$this->draftLeader = true;
172
			}
173
		}
174
		return $this->draftLeader;
175
	}
176
177
	public function getGPWriter() {
178
		if (!isset($this->gpWriter)) {
179
			$this->gpWriter = false;
180
			$this->db->query('SELECT position FROM galactic_post_writer WHERE ' . $this->SQL);
181
			if ($this->db->nextRecord()) {
182
				$this->gpWriter = $this->db->getField('position');
183
			}
184
		}
185
		return $this->gpWriter;
186
	}
187
188
	public function isGPEditor() {
189
		return $this->getGPWriter() == 'editor';
190
	}
191
192
	public function getSafeAttackRating() {
193
		return max(0, min(8, $this->getAlignment() / 150 + 4));
194
	}
195
196
	public function hasFederalProtection() {
197
		$sector = SmrSector::getSector($this->getGameID(), $this->getSectorID());
198
		if (!$sector->offersFederalProtection()) {
199
			return false;
200
		}
201
202
		$ship = $this->getShip();
203
		if ($ship->hasIllegalGoods()) {
204
			return false;
205
		}
206
207
		if ($ship->getAttackRating() <= $this->getSafeAttackRating()) {
208
			foreach ($sector->getFedRaceIDs() as $fedRaceID) {
209
				if ($this->canBeProtectedByRace($fedRaceID)) {
210
					return true;
211
				}
212
			}
213
		}
214
215
		return false;
216
	}
217
218
	public function canBeProtectedByRace($raceID) {
219
		if (!isset($this->canFed)) {
220
			$this->canFed = array();
0 ignored issues
show
Bug Best Practice introduced by
The property canFed does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
221
			$RACES = Globals::getRaces();
222
			foreach ($RACES as $raceID2 => $raceName) {
223
				$this->canFed[$raceID2] = $this->getRelation($raceID2) >= ALIGN_FED_PROTECTION;
224
			}
225
			$this->db->query('SELECT race_id, allowed FROM player_can_fed
226
								WHERE ' . $this->SQL . ' AND expiry > ' . $this->db->escapeNumber(TIME));
227
			while ($this->db->nextRecord()) {
228
				$this->canFed[$this->db->getInt('race_id')] = $this->db->getBoolean('allowed');
229
			}
230
		}
231
		return $this->canFed[$raceID];
232
	}
233
234
	/**
235
	 * Returns a boolean identifying if the player can currently
236
	 * participate in battles.
237
	 */
238
	public function canFight() {
239
		return !($this->hasNewbieTurns() ||
240
		         $this->isDead() ||
241
		         $this->isLandedOnPlanet() ||
242
		         $this->hasFederalProtection());
243
	}
244
245
	public function setDead($bool) {
246
		if ($this->dead == $bool) {
247
			return;
248
		}
249
		$this->dead = $bool;
250
		$this->hasChanged = true;
251
	}
252
253
	public function getKills() {
254
		return $this->kills;
255
	}
256
257
	public function increaseKills($kills) {
258
		if ($kills < 0) {
259
			throw new Exception('Trying to increase negative kills.');
260
		}
261
		$this->setKills($this->kills + $kills);
262
	}
263
264
	public function setKills($kills) {
265
		if ($this->kills == $kills) {
266
			return;
267
		}
268
		$this->kills = $kills;
269
		$this->hasChanged = true;
270
	}
271
272
	public function getDeaths() {
273
		return $this->deaths;
274
	}
275
276
	public function increaseDeaths($deaths) {
277
		if ($deaths < 0) {
278
			throw new Exception('Trying to increase negative deaths.');
279
		}
280
		$this->setDeaths($this->getDeaths() + $deaths);
281
	}
282
283
	public function setDeaths($deaths) {
284
		if ($this->deaths == $deaths) {
285
			return;
286
		}
287
		$this->deaths = $deaths;
288
		$this->hasChanged = true;
289
	}
290
291
	public function getAssists() {
292
		return $this->assists;
293
	}
294
295
	public function increaseAssists($assists) {
296
		if ($assists < 1) {
297
			throw new Exception('Must increase by a positive number.');
298
		}
299
		$this->assists += $assists;
300
		$this->hasChanged = true;
301
	}
302
303
	public function getAlignment() {
304
		return $this->alignment;
305
	}
306
307
	public function increaseAlignment($align) {
308
		if ($align < 0) {
309
			throw new Exception('Trying to increase negative align.');
310
		}
311
		if ($align == 0) {
312
			return;
313
		}
314
		$align += $this->alignment;
315
		$this->setAlignment($align);
316
	}
317
	public function decreaseAlignment($align) {
318
		if ($align < 0) {
319
			throw new Exception('Trying to decrease negative align.');
320
		}
321
		if ($align == 0) {
322
			return;
323
		}
324
		$align = $this->alignment - $align;
325
		$this->setAlignment($align);
326
	}
327
	public function setAlignment($align) {
328
		if ($this->alignment == $align) {
329
			return;
330
		}
331
		$this->alignment = $align;
332
		$this->hasChanged = true;
333
	}
334
335
	public function getCredits() {
336
		return $this->credits;
337
	}
338
339
	public function getExperience() {
340
		return $this->experience;
341
	}
342
343
	/**
344
	 * Returns the percent progress towards the next level.
345
	 * This value is rounded because it is used primarily in HTML img widths.
346
	 */
347
	public function getNextLevelPercentAcquired() : int {
348
		if ($this->getNextLevelExperience() == $this->getThisLevelExperience()) {
349
			return 100;
350
		}
351
		return max(0, min(100, IRound(($this->getExperience() - $this->getThisLevelExperience()) / ($this->getNextLevelExperience() - $this->getThisLevelExperience()) * 100)));
352
	}
353
354
	public function getNextLevelPercentRemaining() {
355
		return 100 - $this->getNextLevelPercentAcquired();
356
	}
357
358
	public function getNextLevelExperience() {
359
		$LEVELS_REQUIREMENTS = Globals::getLevelRequirements();
360
		if (!isset($LEVELS_REQUIREMENTS[$this->getLevelID() + 1])) {
361
			return $this->getThisLevelExperience(); //Return current level experience if on last level.
362
		}
363
		return $LEVELS_REQUIREMENTS[$this->getLevelID() + 1]['Requirement'];
364
	}
365
366
	public function getThisLevelExperience() {
367
		$LEVELS_REQUIREMENTS = Globals::getLevelRequirements();
368
		return $LEVELS_REQUIREMENTS[$this->getLevelID()]['Requirement'];
369
	}
370
371
	public function setExperience($experience) {
372
		if ($this->experience == $experience) {
373
			return;
374
		}
375
		if ($experience < MIN_EXPERIENCE) {
376
			$experience = MIN_EXPERIENCE;
377
		}
378
		if ($experience > MAX_EXPERIENCE) {
379
			$experience = MAX_EXPERIENCE;
380
		}
381
		$this->experience = $experience;
382
		$this->hasChanged = true;
383
384
		// Since exp has changed, invalidate the player level so that it can
385
		// be recomputed next time it is queried (in case it has changed).
386
		$this->level = null;
387
	}
388
389
	public function increaseCredits($credits) {
390
		if ($credits < 0) {
391
			throw new Exception('Trying to increase negative credits.');
392
		}
393
		if ($credits == 0) {
394
			return;
395
		}
396
		$credits += $this->credits;
397
		$this->setCredits($credits);
398
	}
399
	public function decreaseCredits($credits) {
400
		if ($credits < 0) {
401
			throw new Exception('Trying to decrease negative credits.');
402
		}
403
		if ($credits == 0) {
404
			return;
405
		}
406
		$credits = $this->credits - $credits;
407
		$this->setCredits($credits);
408
	}
409
	public function setCredits($credits) {
410
		if ($this->credits == $credits) {
411
			return;
412
		}
413
		if ($credits < 0) {
414
			throw new Exception('Trying to set negative credits.');
415
		}
416
		if ($credits > MAX_MONEY) {
417
			$credits = MAX_MONEY;
418
		}
419
		$this->credits = $credits;
420
		$this->hasChanged = true;
421
	}
422
423
	public function increaseExperience($experience) {
424
		if ($experience < 0) {
425
			throw new Exception('Trying to increase negative experience.');
426
		}
427
		if ($experience == 0) {
428
			return;
429
		}
430
		$newExperience = $this->experience + $experience;
431
		$this->setExperience($newExperience);
432
		$this->increaseHOF($experience, array('Experience', 'Total', 'Gain'), HOF_PUBLIC);
433
	}
434
	public function decreaseExperience($experience) {
435
		if ($experience < 0) {
436
			throw new Exception('Trying to decrease negative experience.');
437
		}
438
		if ($experience == 0) {
439
			return;
440
		}
441
		$newExperience = $this->experience - $experience;
442
		$this->setExperience($newExperience);
443
		$this->decreaseHOF($experience, array('Experience', 'Total', 'Loss'), HOF_PUBLIC);
444
	}
445
446
	public function isLandedOnPlanet() {
447
		return $this->landedOnPlanet;
448
	}
449
450
	public function setLandedOnPlanet($bool) {
451
		if ($this->landedOnPlanet == $bool) {
452
			return;
453
		}
454
		$this->landedOnPlanet = $bool;
455
		$this->hasChanged = true;
456
	}
457
458
	/**
459
	 * Returns the numerical level of the player (e.g. 1-50).
460
	 */
461
	public function getLevelID() {
462
		// The level is cached for performance reasons unless `setExperience`
463
		// is called and the player's experience changes.
464
		if ($this->level === null) {
465
			$LEVELS_REQUIREMENTS = Globals::getLevelRequirements();
466
			foreach ($LEVELS_REQUIREMENTS as $level_id => $require) {
467
				if ($this->getExperience() >= $require['Requirement']) {
468
					continue;
469
				}
470
				$this->level = $level_id - 1;
471
				return $this->level;
472
			}
473
			$this->level = max(array_keys($LEVELS_REQUIREMENTS));
474
		}
475
		return $this->level;
476
	}
477
478
	public function getLevelName() {
479
		$level_name = Globals::getLevelRequirements()[$this->getLevelID()]['Name'];
480
		if ($this->isPresident()) {
0 ignored issues
show
Bug introduced by
The method isPresident() does not exist on AbstractSmrPlayer. It seems like you code against a sub-type of AbstractSmrPlayer such as SmrPlayer. ( Ignorable by Annotation )

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

480
		if ($this->/** @scrutinizer ignore-call */ isPresident()) {
Loading history...
481
			$level_name = '<img src="images/council_president.png" title="' . Globals::getRaceName($this->getRaceID()) . ' President" height="12" width="16" />&nbsp;' . $level_name;
482
		}
483
		return $level_name;
484
	}
485
486
	public function getMaxLevel() {
487
		return max(array_keys(Globals::getLevelRequirements()));
488
	}
489
490
	public function getPlayerID() {
491
		return $this->playerID;
492
	}
493
494
	public function getPlayerName() {
495
		return $this->playerName;
496
	}
497
498
	public function setPlayerName($name) {
499
		$this->playerName = $name;
500
		$this->hasChanged = true;
501
	}
502
503
	public function getDisplayName($includeAlliance = false) {
504
		$return = get_colored_text($this->getAlignment(), $this->playerName . ' (' . $this->getPlayerID() . ')');
505
		if ($this->isNPC()) {
506
			$return .= ' <span class="npcColour">[NPC]</span>';
507
		}
508
		if ($includeAlliance) {
509
			$return .= ' (' . $this->getAllianceDisplayName() . ')';
510
		}
511
		return $return;
512
	}
513
514
	public function getBBLink() {
515
			return '[player=' . $this->getPlayerID() . ']';
516
	}
517
518
	public function getLinkedDisplayName($includeAlliance = true) {
519
		$return = '<a href="' . $this->getTraderSearchHREF() . '">' . $this->getDisplayName() . '</a>';
520
		if ($includeAlliance) {
521
			$return .= ' (' . $this->getAllianceDisplayName(true) . ')';
522
		}
523
		return $return;
524
	}
525
526
	public function getRaceID() {
527
		return $this->raceID;
528
	}
529
530
	public function getRaceName() {
531
		return Globals::getRaceName($this->getRaceID());
532
	}
533
534
	public static function getColouredRaceNameOrDefault($otherRaceID, AbstractSmrPlayer $player = null, $linked = false) {
535
		$relations = 0;
536
		if ($player !== null) {
537
			$relations = $player->getRelation($otherRaceID);
538
		}
539
		return Globals::getColouredRaceName($otherRaceID, $relations, $linked);
540
	}
541
542
	public function getColouredRaceName($otherRaceID, $linked = false) {
543
		return self::getColouredRaceNameOrDefault($otherRaceID, $this, $linked);
544
	}
545
546
	public function setRaceID($raceID) {
547
		if ($this->raceID == $raceID) {
548
			return;
549
		}
550
		$this->raceID = $raceID;
551
		$this->hasChanged = true;
552
	}
553
554
	public function isAllianceLeader($forceUpdate = false) {
555
		return $this->getAccountID() == $this->getAlliance($forceUpdate)->getLeaderID();
556
	}
557
558
	public function getAlliance($forceUpdate = false) {
559
		return SmrAlliance::getAlliance($this->getAllianceID(), $this->getGameID(), $forceUpdate);
560
	}
561
562
	public function getAllianceID() {
563
		return $this->allianceID;
564
	}
565
566
	public function hasAlliance() {
567
		return $this->getAllianceID() != 0;
568
	}
569
570
	protected function setAllianceID($ID) {
571
		if ($this->allianceID == $ID) {
572
			return;
573
		}
574
		$this->allianceID = $ID;
575
		if ($this->allianceID != 0) {
576
			$status = $this->hasNewbieStatus() ? 'NEWBIE' : 'VETERAN';
577
			$this->db->query('INSERT IGNORE INTO player_joined_alliance (account_id,game_id,alliance_id,status) ' .
578
				'VALUES (' . $this->db->escapeNumber($this->getAccountID()) . ',' . $this->db->escapeNumber($this->getGameID()) . ',' . $this->db->escapeNumber($this->getAllianceID()) . ',' . $this->db->escapeString($status) . ')');
579
		}
580
		$this->hasChanged = true;
581
	}
582
583
	public function getAllianceBBLink() {
584
		return $this->hasAlliance() ? $this->getAlliance()->getAllianceBBLink() : $this->getAllianceDisplayName();
585
	}
586
587
	public function getAllianceDisplayName($linked = false, $includeAllianceID = false) {
588
		if ($this->hasAlliance()) {
589
			return $this->getAlliance()->getAllianceDisplayName($linked, $includeAllianceID);
590
		} else {
591
			return 'No Alliance';
592
		}
593
	}
594
595
	public function getAllianceRole($allianceID = false) {
596
		if ($allianceID === false) {
597
			$allianceID = $this->getAllianceID();
598
		}
599
		if (!isset($this->allianceRoles[$allianceID])) {
600
			$this->allianceRoles[$allianceID] = 0;
601
			$this->db->query('SELECT role_id
602
						FROM player_has_alliance_role
603
						WHERE ' . $this->SQL . '
604
						AND alliance_id=' . $this->db->escapeNumber($allianceID) . '
605
						LIMIT 1');
606
			if ($this->db->nextRecord()) {
607
				$this->allianceRoles[$allianceID] = $this->db->getInt('role_id');
608
			}
609
		}
610
		return $this->allianceRoles[$allianceID];
611
	}
612
613
	public function isCombatDronesKamikazeOnMines() {
614
		return $this->combatDronesKamikazeOnMines;
615
	}
616
617
	public function setCombatDronesKamikazeOnMines($bool) {
618
		if ($this->combatDronesKamikazeOnMines == $bool) {
619
			return;
620
		}
621
		$this->combatDronesKamikazeOnMines = $bool;
0 ignored issues
show
Bug Best Practice introduced by
The property combatDronesKamikazeOnMines does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
622
		$this->hasChanged = true;
623
	}
624
625
	protected abstract function getPureRelationsData();
626
627
	public function getPureRelations() {
628
		$this->getPureRelationsData();
629
		return $this->pureRelations;
630
	}
631
632
	/**
633
	 * Get personal relations with a race
634
	 */
635
	public function getPureRelation($raceID) {
636
		$rels = $this->getPureRelations();
637
		return $rels[$raceID];
638
	}
639
640
	public function getRelations() {
641
		if (!isset($this->relations)) {
642
			//get relations
643
			$RACES = Globals::getRaces();
644
			$raceRelations = Globals::getRaceRelations($this->getGameID(), $this->getRaceID());
645
			$pureRels = $this->getPureRelations(); // make sure they're initialised.
646
			$this->relations = array();
647
			foreach ($RACES as $raceID => $raceName) {
648
				$this->relations[$raceID] = $pureRels[$raceID] + $raceRelations[$raceID];
649
			}
650
		}
651
		return $this->relations;
652
	}
653
654
	/**
655
	 * Get total relations with a race (personal + political)
656
	 */
657
	public function getRelation($raceID) {
658
		$rels = $this->getRelations();
659
		return $rels[$raceID];
660
	}
661
662
	abstract public function getShip();
663
664
	public function &shootPlayer(AbstractSmrPlayer $targetPlayer) {
665
		return $this->getShip()->shootPlayer($targetPlayer);
666
	}
667
668
	public function &shootForces(SmrForce $forces) {
669
		return $this->getShip()->shootForces($forces);
670
	}
671
672
	public function &shootPort(SmrPort $port) {
673
		return $this->getShip()->shootPort($port);
674
	}
675
676
	public function &shootPlanet(SmrPlanet $planet, $delayed) {
677
		return $this->getShip()->shootPlanet($planet, $delayed);
678
	}
679
680
	public function &shootPlayers(array $targetPlayers) {
681
		return $this->getShip()->shootPlayers($targetPlayers);
682
	}
683
684
	public function getMilitaryPayment() {
685
		return $this->militaryPayment;
686
	}
687
688
	public function hasMilitaryPayment() {
689
		return $this->getMilitaryPayment() > 0;
690
	}
691
692
	public function setMilitaryPayment($amount) {
693
		if ($this->militaryPayment == $amount) {
694
			return;
695
		}
696
		$this->militaryPayment = $amount;
697
		$this->hasChanged = true;
698
	}
699
700
	public function increaseMilitaryPayment($amount) {
701
		if ($amount < 0) {
702
			throw new Exception('Trying to increase negative military payment.');
703
		}
704
		$this->setMilitaryPayment($this->getMilitaryPayment() + $amount);
705
	}
706
707
	public function decreaseMilitaryPayment($amount) {
708
		if ($amount < 0) {
709
			throw new Exception('Trying to decrease negative military payment.');
710
		}
711
		$this->setMilitaryPayment($this->getMilitaryPayment() - $amount);
712
	}
713
714
	abstract protected function getBountiesData();
715
716
	public function getBounties() : array {
717
		$this->getBountiesData();
718
		return $this->bounties;
719
	}
720
721
	public function hasBounties() : bool {
722
		return count($this->getBounties()) > 0;
723
	}
724
725
	protected function getBounty(int $bountyID) : array {
726
		if (!$this->hasBounty($bountyID)) {
727
			throw new Exception('BountyID does not exist: ' . $bountyID);
728
		}
729
		return $this->bounties[$bountyID];
730
	}
731
732
	public function hasBounty(int $bountyID) : bool {
733
		$bounties = $this->getBounties();
734
		return isset($bounties[$bountyID]);
735
	}
736
737
	protected function getBountyAmount(int $bountyID) : int {
738
		$bounty = $this->getBounty($bountyID);
739
		return $bounty['Amount'];
740
	}
741
742
	protected function createBounty(string $type) : array {
743
		$bounty = array('Amount' => 0,
744
						'SmrCredits' => 0,
745
						'Type' => $type,
746
						'Claimer' => 0,
747
						'Time' => TIME,
748
						'ID' => $this->getNextBountyID(),
749
						'New' => true);
750
		$this->setBounty($bounty);
751
		return $bounty;
752
	}
753
754
	protected function getNextBountyID() : int {
755
		$keys = array_keys($this->getBounties());
756
		if (count($keys) > 0) {
757
			return max($keys) + 1;
758
		} else {
759
			return 0;
760
		}
761
	}
762
763
	protected function setBounty(array $bounty) : void {
764
		$this->bounties[$bounty['ID']] = $bounty;
765
		$this->hasBountyChanged[$bounty['ID']] = true;
766
	}
767
768
	protected function setBountyAmount(int $bountyID, int $amount) : void {
769
		$bounty = $this->getBounty($bountyID);
770
		$bounty['Amount'] = $amount;
771
		$this->setBounty($bounty);
772
	}
773
774
	public function getCurrentBounty(string $type) : array {
775
		$bounties = $this->getBounties();
776
		foreach ($bounties as $bounty) {
777
			if ($bounty['Claimer'] == 0 && $bounty['Type'] == $type) {
778
				return $bounty;
779
			}
780
		}
781
		return $this->createBounty($type);
782
	}
783
784
	public function hasCurrentBounty(string $type) : bool {
785
		$bounties = $this->getBounties();
786
		foreach ($bounties as $bounty) {
787
			if ($bounty['Claimer'] == 0 && $bounty['Type'] == $type) {
788
				return true;
789
			}
790
		}
791
		return false;
792
	}
793
794
	protected function getCurrentBountyAmount(string $type) : int {
795
		$bounty = $this->getCurrentBounty($type);
796
		return $bounty['Amount'];
797
	}
798
799
	protected function setCurrentBountyAmount(string $type, int $amount) : void {
800
		$bounty = $this->getCurrentBounty($type);
801
		if ($bounty['Amount'] == $amount) {
802
			return;
803
		}
804
		$bounty['Amount'] = $amount;
805
		$this->setBounty($bounty);
806
	}
807
808
	public function increaseCurrentBountyAmount(string $type, int $amount) : void {
809
		if ($amount < 0) {
810
			throw new Exception('Trying to increase negative current bounty.');
811
		}
812
		$this->setCurrentBountyAmount($type, $this->getCurrentBountyAmount($type) + $amount);
813
	}
814
815
	public function decreaseCurrentBountyAmount(string $type, int $amount) : void {
816
		if ($amount < 0) {
817
			throw new Exception('Trying to decrease negative current bounty.');
818
		}
819
		$this->setCurrentBountyAmount($type, $this->getCurrentBountyAmount($type) - $amount);
820
	}
821
822
	protected function getCurrentBountySmrCredits(string $type) : int {
823
		$bounty = $this->getCurrentBounty($type);
824
		return $bounty['SmrCredits'];
825
	}
826
827
	protected function setCurrentBountySmrCredits(string $type, int $credits) : void {
828
		$bounty = $this->getCurrentBounty($type);
829
		if ($bounty['SmrCredits'] == $credits) {
830
			return;
831
		}
832
		$bounty['SmrCredits'] = $credits;
833
		$this->setBounty($bounty);
834
	}
835
836
	public function increaseCurrentBountySmrCredits(string $type, int $credits) : void {
837
		if ($credits < 0) {
838
			throw new Exception('Trying to increase negative current bounty.');
839
		}
840
		$this->setCurrentBountySmrCredits($type, $this->getCurrentBountySmrCredits($type) + $credits);
841
	}
842
843
	public function decreaseCurrentBountySmrCredits(string $type, int $credits) : void {
844
		if ($credits < 0) {
845
			throw new Exception('Trying to decrease negative current bounty.');
846
		}
847
		$this->setCurrentBountySmrCredits($type, $this->getCurrentBountySmrCredits($type) - $credits);
848
	}
849
850
	public function setBountiesClaimable(AbstractSmrPlayer $claimer) : void {
851
		foreach ($this->getBounties() as $bounty) {
852
			if ($bounty['Claimer'] == 0) {
853
				$bounty['Claimer'] = $claimer->getAccountID();
854
				$this->setBounty($bounty);
855
			}
856
		}
857
	}
858
859
860
	abstract protected function getHOFData();
861
862
	public function getHOF(array $typeList = null) {
863
		$this->getHOFData();
864
		if ($typeList == null) {
865
			return $this->HOF;
866
		}
867
		$hof = $this->HOF;
868
		foreach ($typeList as $type) {
869
			if (!isset($hof[$type])) {
870
				return 0;
871
			}
872
			$hof = $hof[$type];
873
		}
874
		return $hof;
875
	}
876
877
	public function increaseHOF($amount, array $typeList, $visibility) {
878
		if ($amount < 0) {
879
			throw new Exception('Trying to increase negative HOF: ' . implode(':', $typeList));
880
		}
881
		if ($amount == 0) {
882
			return;
883
		}
884
		$this->setHOF($this->getHOF($typeList) + $amount, $typeList, $visibility);
885
	}
886
887
	public function decreaseHOF($amount, array $typeList, $visibility) {
888
		if ($amount < 0) {
889
			throw new Exception('Trying to decrease negative HOF: ' . implode(':', $typeList));
890
		}
891
		if ($amount == 0) {
892
			return;
893
		}
894
		$this->setHOF($this->getHOF($typeList) - $amount, $typeList, $visibility);
895
	}
896
897
	public function setHOF($amount, array $typeList, $visibility) {
898
		if (is_array($this->getHOF($typeList))) {
899
			throw new Exception('Trying to overwrite a HOF type: ' . implode(':', $typeList));
900
		}
901
		if ($this->isNPC()) {
902
			// Don't store HOF for NPCs.
903
			return;
904
		}
905
		if ($this->getHOF($typeList) == $amount) {
906
			return;
907
		}
908
		if ($amount < 0) {
909
			$amount = 0;
910
		}
911
		$this->getHOF();
912
913
		$hofType = implode(':', $typeList);
914
		if (!isset(self::$HOFVis[$hofType])) {
915
			self::$hasHOFVisChanged[$hofType] = self::HOF_NEW;
916
		} elseif (self::$HOFVis[$hofType] != $visibility) {
917
			self::$hasHOFVisChanged[$hofType] = self::HOF_CHANGED;
918
		}
919
		self::$HOFVis[$hofType] = $visibility;
920
921
		$hof =& $this->HOF;
922
		$hofChanged =& $this->hasHOFChanged;
923
		$new = false;
924
		foreach ($typeList as $type) {
925
			if (!isset($hofChanged[$type])) {
926
				$hofChanged[$type] = array();
927
			}
928
			if (!isset($hof[$type])) {
929
				$hof[$type] = array();
930
				$new = true;
931
			}
932
			$hof =& $hof[$type];
933
			$hofChanged =& $hofChanged[$type];
934
		}
935
		if ($hofChanged == null) {
936
			$hofChanged = self::HOF_CHANGED;
937
			if ($new) {
938
				$hofChanged = self::HOF_NEW;
939
			}
940
		}
941
		$hof = $amount;
942
	}
943
944
	abstract public function killPlayer($sectorID);
945
	abstract public function &killPlayerByPlayer(AbstractSmrPlayer $killer);
946
	abstract public function &killPlayerByForces(SmrForce $forces);
947
	abstract public function &killPlayerByPort(SmrPort $port);
948
	abstract public function &killPlayerByPlanet(SmrPlanet $planet);
949
950
951
	public function getTurns() {
952
		return $this->turns;
953
	}
954
955
	public function hasTurns() {
956
		return $this->turns > 0;
957
	}
958
959
	public function getMaxTurns() {
960
		return $this->getGame()->getMaxTurns();
961
	}
962
963
	public function setTurns($turns) {
964
		if ($this->turns == $turns) {
965
			return;
966
		}
967
		// Make sure turns are in range [0, MaxTurns]
968
		$this->turns = max(0, min($turns, $this->getMaxTurns()));
969
		$this->hasChanged = true;
970
	}
971
972
	public function takeTurns($take, $takeNewbie = 0) {
973
		if ($take < 0 || $takeNewbie < 0) {
974
			throw new Exception('Trying to take negative turns.');
975
		}
976
		$take = ICeil($take);
977
		// Only take up to as many newbie turns as we have remaining
978
		$takeNewbie = min($this->getNewbieTurns(), $takeNewbie);
979
980
		$this->setTurns($this->getTurns() - $take);
981
		$this->setNewbieTurns($this->getNewbieTurns() - $takeNewbie);
982
		$this->increaseHOF($take, array('Movement', 'Turns Used', 'Since Last Death'), HOF_ALLIANCE);
983
		$this->increaseHOF($take, array('Movement', 'Turns Used', 'Total'), HOF_ALLIANCE);
984
		$this->increaseHOF($takeNewbie, array('Movement', 'Turns Used', 'Newbie'), HOF_ALLIANCE);
985
986
		// Player has taken an action
987
		$this->setLastActive(TIME);
988
		$this->updateLastCPLAction();
989
	}
990
991
	public function giveTurns(int $give, $giveNewbie = 0) {
992
		if ($give < 0 || $giveNewbie < 0) {
993
			throw new Exception('Trying to give negative turns.');
994
		}
995
		$this->setTurns($this->getTurns() + $give);
996
		$this->setNewbieTurns($this->getNewbieTurns() + $giveNewbie);
997
	}
998
999
	public function getLastActive() {
1000
		return $this->lastActive;
1001
	}
1002
1003
	public function setLastActive($lastActive) {
1004
		if ($this->lastActive == $lastActive) {
1005
			return;
1006
		}
1007
		$this->lastActive = $lastActive;
1008
		$this->hasChanged = true;
1009
	}
1010
1011
	public function getLastCPLAction() {
1012
		return $this->lastCPLAction;
1013
	}
1014
1015
	public function setLastCPLAction($time) {
1016
		if ($this->lastCPLAction == $time) {
1017
			return;
1018
		}
1019
		$this->lastCPLAction = $time;
1020
		$this->hasChanged = true;
1021
	}
1022
1023
	public function updateLastCPLAction() {
1024
		$this->setLastCPLAction(TIME);
1025
	}
1026
1027
	public function getMissions() {
1028
		if (!isset($this->missions)) {
1029
			$this->db->query('SELECT * FROM player_has_mission WHERE ' . $this->SQL);
1030
			$this->missions = array();
1031
			while ($this->db->nextRecord()) {
1032
				$missionID = $this->db->getInt('mission_id');
1033
				$this->missions[$missionID] = array(
1034
					'On Step' => $this->db->getInt('on_step'),
1035
					'Progress' => $this->db->getInt('progress'),
1036
					'Unread' => $this->db->getBoolean('unread'),
1037
					'Expires' => $this->db->getInt('step_fails'),
1038
					'Sector' => $this->db->getInt('mission_sector'),
1039
					'Starting Sector' => $this->db->getInt('starting_sector')
1040
				);
1041
				$this->rebuildMission($missionID);
1042
			}
1043
		}
1044
		return $this->missions;
1045
	}
1046
1047
	public function getActiveMissions() {
1048
		$missions = $this->getMissions();
1049
		foreach ($missions as $missionID => $mission) {
1050
			if ($mission['On Step'] >= count(MISSIONS[$missionID]['Steps'])) {
1051
				unset($missions[$missionID]);
1052
			}
1053
		}
1054
		return $missions;
1055
	}
1056
1057
	protected function getMission($missionID) {
1058
		$missions = $this->getMissions();
1059
		if (isset($missions[$missionID])) {
1060
			return $missions[$missionID];
1061
		}
1062
		return false;
1063
	}
1064
1065
	protected function hasMission($missionID) {
1066
		return $this->getMission($missionID) !== false;
1067
	}
1068
1069
	protected function updateMission($missionID) {
1070
		$this->getMissions();
1071
		if (isset($this->missions[$missionID])) {
1072
			$mission = $this->missions[$missionID];
1073
			$this->db->query('
1074
				UPDATE player_has_mission
1075
				SET on_step = ' . $this->db->escapeNumber($mission['On Step']) . ',
1076
					progress = ' . $this->db->escapeNumber($mission['Progress']) . ',
1077
					unread = ' . $this->db->escapeBoolean($mission['Unread']) . ',
1078
					starting_sector = ' . $this->db->escapeNumber($mission['Starting Sector']) . ',
1079
					mission_sector = ' . $this->db->escapeNumber($mission['Sector']) . ',
1080
					step_fails = ' . $this->db->escapeNumber($mission['Expires']) . '
1081
				WHERE ' . $this->SQL . ' AND mission_id = ' . $this->db->escapeNumber($missionID) . ' LIMIT 1'
1082
			);
1083
			return true;
1084
		}
1085
		return false;
1086
	}
1087
1088
	private function setupMissionStep($missionID) {
1089
		$mission =& $this->missions[$missionID];
1090
		if ($mission['On Step'] >= count(MISSIONS[$missionID]['Steps'])) {
1091
			// Nothing to do if this mission is already completed
1092
			return;
1093
		}
1094
		$step = MISSIONS[$missionID]['Steps'][$mission['On Step']];
1095
		if (isset($step['PickSector'])) {
1096
			$realX = Plotter::getX($step['PickSector']['Type'], $step['PickSector']['X'], $this->getGameID());
1097
			if ($realX === false) {
1098
				throw new Exception('Invalid PickSector definition in mission: ' . $missionID);
1099
			}
1100
			$path = Plotter::findDistanceToX($realX, $this->getSector(), true, null, $this);
1101
			if ($path === false) {
1102
				throw new Exception('Cannot find location: ' . $missionID);
1103
			}
1104
			$mission['Sector'] = $path->getEndSectorID();
1105
		}
1106
	}
1107
1108
	/**
1109
	 * Declining a mission will permanently hide it from the player
1110
	 * by adding it in its completed state.
1111
	 */
1112
	public function declineMission($missionID) {
1113
		$finishedStep = count(MISSIONS[$missionID]['Steps']);
1114
		$this->addMission($missionID, $finishedStep);
1115
	}
1116
1117
	public function addMission($missionID, $step = 0) {
1118
		$this->getMissions();
1119
1120
		if (isset($this->missions[$missionID])) {
1121
			return;
1122
		}
1123
		$sector = 0;
1124
1125
		$mission = array(
1126
			'On Step' => $step,
1127
			'Progress' => 0,
1128
			'Unread' => true,
1129
			'Expires' => (TIME + 86400),
1130
			'Sector' => $sector,
1131
			'Starting Sector' => $this->getSectorID()
1132
		);
1133
1134
		$this->missions[$missionID] =& $mission;
1135
		$this->setupMissionStep($missionID);
1136
		$this->rebuildMission($missionID);
1137
1138
		$this->db->query('
1139
			REPLACE INTO player_has_mission (game_id,account_id,mission_id,on_step,progress,unread,starting_sector,mission_sector,step_fails)
1140
			VALUES ('.$this->db->escapeNumber($this->gameID) . ',' . $this->db->escapeNumber($this->accountID) . ',' . $this->db->escapeNumber($missionID) . ',' . $this->db->escapeNumber($mission['On Step']) . ',' . $this->db->escapeNumber($mission['Progress']) . ',' . $this->db->escapeBoolean($mission['Unread']) . ',' . $this->db->escapeNumber($mission['Starting Sector']) . ',' . $this->db->escapeNumber($mission['Sector']) . ',' . $this->db->escapeNumber($mission['Expires']) . ')'
1141
		);
1142
	}
1143
1144
	private function rebuildMission($missionID) {
1145
		$mission = $this->missions[$missionID];
1146
		$this->missions[$missionID]['Name'] = MISSIONS[$missionID]['Name'];
1147
1148
		if ($mission['On Step'] >= count(MISSIONS[$missionID]['Steps'])) {
1149
			// If we have completed this mission just use false to indicate no current task.
1150
			$currentStep = false;
1151
		} else {
1152
			$currentStep = MISSIONS[$missionID]['Steps'][$mission['On Step']];
1153
			$currentStep['Text'] = str_replace(array('<Race>', '<Sector>', '<Starting Sector>', '<trader>'), array($this->getRaceID(), $mission['Sector'], $mission['Starting Sector'], $this->playerName), $currentStep['Text']);
1154
			if (isset($currentStep['Task'])) {
1155
				$currentStep['Task'] = str_replace(array('<Race>', '<Sector>', '<Starting Sector>', '<trader>'), array($this->getRaceID(), $mission['Sector'], $mission['Starting Sector'], $this->playerName), $currentStep['Task']);
1156
			}
1157
			if (isset($currentStep['Level'])) {
1158
				$currentStep['Level'] = str_replace('<Player Level>', $this->getLevelID(), $currentStep['Level']);
1159
			} else {
1160
				$currentStep['Level'] = 0;
1161
			}
1162
		}
1163
		$this->missions[$missionID]['Task'] = $currentStep;
1164
	}
1165
1166
	public function deleteMission($missionID) {
1167
		$this->getMissions();
1168
		if (isset($this->missions[$missionID])) {
1169
			unset($this->missions[$missionID]);
1170
			$this->db->query('DELETE FROM player_has_mission WHERE ' . $this->SQL . ' AND mission_id = ' . $this->db->escapeNumber($missionID) . ' LIMIT 1');
1171
			return true;
1172
		}
1173
		return false;
1174
	}
1175
1176
	public function markMissionsRead() {
1177
		$this->getMissions();
1178
		$unreadMissions = array();
1179
		foreach ($this->missions as $missionID => &$mission) {
1180
			if ($mission['Unread']) {
1181
				$unreadMissions[] = $missionID;
1182
				$mission['Unread'] = false;
1183
				$this->updateMission($missionID);
1184
			}
1185
		}
1186
		return $unreadMissions;
1187
	}
1188
1189
	public function claimMissionReward($missionID) {
1190
		$this->getMissions();
1191
		$mission =& $this->missions[$missionID];
1192
		if ($mission === false) {
1193
			throw new Exception('Unknown mission: ' . $missionID);
1194
		}
1195
		if ($mission['Task'] === false || $mission['Task']['Step'] != 'Claim') {
1196
			throw new Exception('Cannot claim mission: ' . $missionID . ', for step: ' . $mission['On Step']);
1197
		}
1198
		$mission['On Step']++;
1199
		$mission['Unread'] = true;
1200
		foreach ($mission['Task']['Rewards'] as $rewardItem => $amount) {
1201
			switch ($rewardItem) {
1202
				case 'Credits':
1203
					$this->increaseCredits($amount);
1204
				break;
1205
				case 'Experience':
1206
					$this->increaseExperience($amount);
1207
				break;
1208
			}
1209
		}
1210
		$rewardText = $mission['Task']['Rewards']['Text'];
1211
		if ($mission['On Step'] < count(MISSIONS[$missionID]['Steps'])) {
1212
			// If we haven't finished the mission yet then 
1213
			$this->setupMissionStep($missionID);
1214
		}
1215
		$this->rebuildMission($missionID);
1216
		$this->updateMission($missionID);
1217
		return $rewardText;
1218
	}
1219
1220
	public function getAvailableMissions() {
1221
		$availableMissions = array();
1222
		foreach (MISSIONS as $missionID => $mission) {
1223
			if ($this->hasMission($missionID)) {
1224
				continue;
1225
			}
1226
			$realX = Plotter::getX($mission['HasX']['Type'], $mission['HasX']['X'], $this->getGameID());
1227
			if ($realX === false) {
1228
				throw new Exception('Invalid HasX definition in mission: ' . $missionID);
1229
			}
1230
			if ($this->getSector()->hasX($realX)) {
1231
				$availableMissions[$missionID] = $mission;
1232
			}
1233
		}
1234
		return $availableMissions;
1235
	}
1236
1237
	public function actionTaken($actionID, array $values) {
1238
		if (!in_array($actionID, MISSION_ACTIONS)) {
1239
			throw new Exception('Unknown action: ' . $actionID);
1240
		}
1241
// TODO: Reenable this once tested.		if($this->getAccount()->isLoggingEnabled())
1242
			switch ($actionID) {
1243
				case 'WalkSector':
1244
					$this->getAccount()->log(LOG_TYPE_MOVEMENT, 'Walks to sector: ' . $values['Sector']->getSectorID(), $this->getSectorID());
1245
				break;
1246
				case 'JoinAlliance':
1247
					$this->getAccount()->log(LOG_TYPE_ALLIANCE, 'joined alliance: ' . $values['Alliance']->getAllianceName(), $this->getSectorID());
1248
				break;
1249
				case 'LeaveAlliance':
1250
					$this->getAccount()->log(LOG_TYPE_ALLIANCE, 'left alliance: ' . $values['Alliance']->getAllianceName(), $this->getSectorID());
1251
				break;
1252
				case 'DisbandAlliance':
1253
					$this->getAccount()->log(LOG_TYPE_ALLIANCE, 'disbanded alliance ' . $values['Alliance']->getAllianceName(), $this->getSectorID());
1254
				break;
1255
				case 'KickPlayer':
1256
					$this->getAccount()->log(LOG_TYPE_ALLIANCE, 'kicked ' . $values['Player']->getAccount()->getLogin() . ' (' . $values['Player']->getPlayerName() . ') from alliance ' . $values['Alliance']->getAllianceName(), 0);
1257
				break;
1258
				case 'PlayerKicked':
1259
					$this->getAccount()->log(LOG_TYPE_ALLIANCE, 'was kicked from alliance ' . $values['Alliance']->getAllianceName() . ' by ' . $values['Player']->getAccount()->getLogin() . ' (' . $values['Player']->getPlayerName() . ')', 0);
1260
				break;
1261
1262
			}
1263
		$this->getMissions();
1264
		foreach ($this->missions as $missionID => &$mission) {
1265
			if ($mission['Task'] !== false && $mission['Task']['Step'] == $actionID) {
1266
				if (checkMissionRequirements($values, $mission, $this) === true) {
1267
					$mission['On Step']++;
1268
					$mission['Unread'] = true;
1269
					$this->setupMissionStep($missionID);
1270
					$this->rebuildMission($missionID);
1271
					$this->updateMission($missionID);
1272
				}
1273
			}
1274
		}
1275
	}
1276
1277
	public function canSeeAny(array $otherPlayerArray) {
1278
		foreach ($otherPlayerArray as $otherPlayer) {
1279
			if ($this->canSee($otherPlayer)) {
1280
				return true;
1281
			}
1282
		}
1283
		return false;
1284
	}
1285
1286
	public function canSee(AbstractSmrPlayer $otherPlayer) {
1287
		if (!$otherPlayer->getShip()->isCloaked()) {
1288
			return true;
1289
		}
1290
		if ($this->sameAlliance($otherPlayer)) {
1291
			return true;
1292
		}
1293
		if ($this->getExperience() >= $otherPlayer->getExperience()) {
1294
			return true;
1295
		}
1296
		return false;
1297
	}
1298
1299
	public function equals(AbstractSmrPlayer $otherPlayer = null) {
1300
		return $otherPlayer !== null && $this->getAccountID() == $otherPlayer->getAccountID() && $this->getGameID() == $otherPlayer->getGameID();
1301
	}
1302
1303
	public function sameAlliance(AbstractSmrPlayer $otherPlayer = null) {
1304
		return $this->equals($otherPlayer) || (!is_null($otherPlayer) && $this->getGameID() == $otherPlayer->getGameID() && $this->hasAlliance() && $this->getAllianceID() == $otherPlayer->getAllianceID());
1305
	}
1306
1307
	public function sharedForceAlliance(AbstractSmrPlayer $otherPlayer = null) {
1308
		return $this->sameAlliance($otherPlayer);
1309
	}
1310
1311
	public function forceNAPAlliance(AbstractSmrPlayer $otherPlayer = null) {
1312
		return $this->sameAlliance($otherPlayer);
1313
	}
1314
1315
	public function planetNAPAlliance(AbstractSmrPlayer $otherPlayer = null) {
1316
		return $this->sameAlliance($otherPlayer);
1317
	}
1318
1319
	public function traderNAPAlliance(AbstractSmrPlayer $otherPlayer = null) {
1320
		return $this->sameAlliance($otherPlayer);
1321
	}
1322
1323
	public function traderMAPAlliance(AbstractSmrPlayer $otherPlayer = null) {
1324
		return $this->traderAttackTraderAlliance($otherPlayer) && $this->traderDefendTraderAlliance($otherPlayer);
1325
	}
1326
1327
	public function traderAttackTraderAlliance(AbstractSmrPlayer $otherPlayer = null) {
1328
		return $this->sameAlliance($otherPlayer);
1329
	}
1330
1331
	public function traderDefendTraderAlliance(AbstractSmrPlayer $otherPlayer = null) {
1332
		return $this->sameAlliance($otherPlayer);
1333
	}
1334
1335
	public function traderAttackForceAlliance(AbstractSmrPlayer $otherPlayer = null) {
1336
		return $this->sameAlliance($otherPlayer);
1337
	}
1338
1339
	public function traderAttackPortAlliance(AbstractSmrPlayer $otherPlayer = null) {
1340
		return $this->sameAlliance($otherPlayer);
1341
	}
1342
1343
	public function traderAttackPlanetAlliance(AbstractSmrPlayer $otherPlayer = null) {
1344
		return $this->sameAlliance($otherPlayer);
1345
	}
1346
1347
	public function meetsAlignmentRestriction($restriction) {
1348
		if ($restriction < 0) {
1349
			return $this->getAlignment() <= $restriction;
1350
		}
1351
		if ($restriction > 0) {
1352
			return $this->getAlignment() >= $restriction;
1353
		}
1354
		return true;
1355
	}
1356
1357
	// Get an array of goods that are visible to the player
1358
	public function getVisibleGoods() {
1359
		$goods = Globals::getGoods();
1360
		$visibleGoods = array();
1361
		foreach ($goods as $key => $good) {
1362
			if ($this->meetsAlignmentRestriction($good['AlignRestriction'])) {
1363
				$visibleGoods[$key] = $good;
1364
			}
1365
		}
1366
		return $visibleGoods;
1367
	}
1368
1369
	/**
1370
	 * Will retrieve all visited sectors, use only when you are likely to check a large number of these
1371
	 */
1372
	public function hasVisitedSector($sectorID) {
1373
		if (!isset($this->visitedSectors)) {
1374
			$this->visitedSectors = array();
1375
			$this->db->query('SELECT sector_id FROM player_visited_sector WHERE ' . $this->SQL);
1376
			while ($this->db->nextRecord()) {
1377
				$this->visitedSectors[$this->db->getInt('sector_id')] = false;
1378
			}
1379
		}
1380
		return !isset($this->visitedSectors[$sectorID]);
1381
	}
1382
1383
	public function getLeaveNewbieProtectionHREF() {
1384
		return SmrSession::getNewHREF(create_container('leave_newbie_processing.php'));
1385
	}
1386
1387
	public function getExamineTraderHREF() {
1388
		$container = create_container('skeleton.php', 'trader_examine.php');
1389
		$container['target'] = $this->getAccountID();
1390
		return SmrSession::getNewHREF($container);
1391
	}
1392
1393
	public function getAttackTraderHREF() {
1394
		return Globals::getAttackTraderHREF($this->getAccountID());
1395
	}
1396
1397
	public function getPlanetKickHREF() {
1398
		$container = create_container('planet_kick_processing.php', 'trader_attack_processing.php');
1399
		$container['account_id'] = $this->getAccountID();
1400
		return SmrSession::getNewHREF($container);
1401
	}
1402
1403
	public function getTraderSearchHREF() {
1404
		$container = create_container('skeleton.php', 'trader_search_result.php');
1405
		$container['player_id'] = $this->getPlayerID();
1406
		return SmrSession::getNewHREF($container);
1407
	}
1408
1409
	public function getAllianceRosterHREF() {
1410
		return Globals::getAllianceRosterHREF($this->getAllianceID());
1411
	}
1412
1413
	public function getToggleWeaponHidingHREF($ajax = false) {
1414
		$container = create_container('toggle_processing.php');
1415
		$container['toggle'] = 'WeaponHiding';
1416
		$container['AJAX'] = $ajax;
1417
		return SmrSession::getNewHREF($container);
1418
	}
1419
}
1420