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 ( 287493...da8ddf )
by Dan
52s queued 13s
created

AbstractSmrPlayer::setupMissionStep()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 2 Features 0
Metric Value
eloc 10
c 4
b 2
f 0
dl 0
loc 13
rs 9.9332
cc 4
nc 4
nop 1
1
<?php
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 $gadgets;
33
	protected $stats;
34
	protected $pureRelations;
35
	protected $relations;
36
	protected $militaryPayment;
37
	protected $bounties;
38
	protected $turns;
39
	protected $lastCPLAction;
40
	protected $completedMissions;
41
	protected $missions;
42
43
	protected $visitedSectors;
44
	protected $allianceRoles = array(
45
		0 => 0
46
	);
47
48
	protected $draftLeader;
49
	protected $gpWriter;
50
	protected $HOF;
51
	protected static $HOFVis;
52
53
	protected $hasChanged=false;
54
	protected $hasHOFChanged=false;
55
	protected static $hasHOFVisChanged=array();
56
	protected $hasBountyChanged = array();
57
58
	protected function __construct() {
59
	}
60
61
	public function getAccountID() {
62
		return $this->accountID;
63
	}
64
65
	public function getGameID() {
66
		return $this->gameID;
67
	}
68
69
	public function &getGame() {
70
		return SmrGame::getGame($this->gameID);
71
	}
72
73
	public function getNewbieTurns() {
74
		return $this->newbieTurns;
75
	}
76
77
	public function hasNewbieTurns() {
78
		return $this->getNewbieTurns()>0;
79
	}
80
	public function setNewbieTurns($newbieTurns) {
81
		if($this->newbieTurns == $newbieTurns)
82
			return;
83
		$this->newbieTurns=$newbieTurns;
84
		$this->hasChanged=true;
85
	}
86
87
	public function getShipTypeID() {
88
		return $this->shipID;
89
	}
90
91
	public function setShipTypeID($shipID) {
92
		if($this->shipID == $shipID)
93
			return;
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 isGPWriter() {
193
//		return $this->isGPEditor() || $this->getGPWriter() == 'writer';
194
		// Lets always allow people to write for the GP? The less hoops to jump through the more writers we'll have surely?
195
		return true;
196
	}
197
198
	public function getSafeAttackRating() {
199
		return max(0, min(8, $this->getAlignment() / 150 + 4));
200
	}
201
202
	public function hasFederalProtection() {
203
		$sector = SmrSector::getSector($this->getGameID(),$this->getSectorID());
204
		if (!$sector->offersFederalProtection()) {
205
			return false;
206
		}
207
208
		$ship = $this->getShip();
209
		if ($ship->hasIllegalGoods())
210
			return false;
211
212
		if ($ship->getAttackRating() <= $this->getSafeAttackRating()) {
213
			foreach($sector->getFedRaceIDs() as $fedRaceID) {
214
				if($this->canBeProtectedByRace($fedRaceID)) {
215
					return true;
216
				}
217
			}
218
		}
219
220
		return false;
221
	}
222
223
	public function canBeProtectedByRace($raceID) {
224
		if(!isset($this->canFed)) {
225
			$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...
226
			$RACES = Globals::getRaces();
227
			foreach($RACES as $raceID2 => $raceName) {
228
				$this->canFed[$raceID2] = $this->getRelation($raceID2) >= ALIGN_FED_PROTECTION;
229
			}
230
			$this->db->query('SELECT race_id, allowed FROM player_can_fed
231
								WHERE ' . $this->SQL . ' AND expiry > ' . $this->db->escapeNumber(TIME));
232
			while($this->db->nextRecord()) {
233
				$this->canFed[$this->db->getInt('race_id')] = $this->db->getBoolean('allowed');
234
			}
235
		}
236
		return $this->canFed[$raceID];
237
	}
238
239
	/**
240
	 * Returns a boolean identifying if the player can currently
241
	 * participate in battles.
242
	 */
243
	public function canFight() {
244
		return !($this->hasNewbieTurns() ||
245
		         $this->isDead() ||
246
		         $this->isLandedOnPlanet() ||
247
		         $this->hasFederalProtection());
248
	}
249
250
	public function setDead($bool) {
251
		if($this->dead == $bool)
252
			return;
253
		$this->dead=$bool;
254
		$this->hasChanged=true;
255
	}
256
257
	public function getKills() {
258
		return $this->kills;
259
	}
260
261
	public function increaseKills($kills) {
262
		if($kills < 0)
263
			throw new Exception('Trying to increase negative kills.');
264
		$this->setKills($this->kills+$kills);
265
	}
266
267
	public function setKills($kills) {
268
		if($this->kills == $kills)
269
			return;
270
		$this->kills=$kills;
271
		$this->hasChanged=true;
272
	}
273
274
	public function getDeaths() {
275
		return $this->deaths;
276
	}
277
278
	public function increaseDeaths($deaths) {
279
		if($deaths < 0)
280
			throw new Exception('Trying to increase negative deaths.');
281
		$this->setDeaths($this->getDeaths()+$deaths);
282
	}
283
284
	public function setDeaths($deaths) {
285
		if($this->deaths == $deaths)
286
			return;
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
		if($align == 0)
311
			return;
312
		$align += $this->alignment;
313
		$this->setAlignment($align);
314
	}
315
	public function decreaseAlignment($align) {
316
		if($align < 0)
317
			throw new Exception('Trying to decrease negative align.');
318
		if($align == 0)
319
			return;
320
		$align = $this->alignment - $align;
321
		$this->setAlignment($align);
322
	}
323
	public function setAlignment($align) {
324
		if($this->alignment == $align)
325
			return;
326
		$this->alignment = $align;
327
		$this->hasChanged=true;
328
	}
329
330
	public function getCredits() {
331
		return $this->credits;
332
	}
333
334
	public function getExperience() {
335
		return $this->experience;
336
	}
337
338
	public function getNextLevelPercentAcquired() {
339
		if($this->getNextLevelExperience() == $this->getThisLevelExperience())
340
			return 100;
341
		return max(0,min(100,round(($this->getExperience() - $this->getThisLevelExperience()) / ($this->getNextLevelExperience() - $this->getThisLevelExperience())*100)));
342
	}
343
344
	public function getNextLevelPercentRemaining() {
345
		return 100 - $this->getNextLevelPercentAcquired();
346
	}
347
348
	public function getNextLevelExperience() {
349
		$LEVELS_REQUIREMENTS = Globals::getLevelRequirements();
350
		if(!isset($LEVELS_REQUIREMENTS[$this->getLevelID()+1]))
351
			return $this->getThisLevelExperience(); //Return current level experience if on last level.
352
		return $LEVELS_REQUIREMENTS[$this->getLevelID()+1]['Requirement'];
353
	}
354
355
	public function getThisLevelExperience() {
356
		$LEVELS_REQUIREMENTS = Globals::getLevelRequirements();
357
		return $LEVELS_REQUIREMENTS[$this->getLevelID()]['Requirement'];
358
	}
359
360
	public function setExperience($experience) {
361
		if($this->experience == $experience)
362
			return;
363
		if($experience<MIN_EXPERIENCE)
364
			$experience = MIN_EXPERIENCE;
365
		if($experience>MAX_EXPERIENCE)
366
			$experience = MAX_EXPERIENCE;
367
		$this->experience = $experience;
368
		$this->hasChanged=true;
369
370
		// Since exp has changed, invalidate the player level so that it can
371
		// be recomputed next time it is queried (in case it has changed).
372
		$this->level = null;
373
	}
374
375
	public function increaseCredits($credits) {
376
		if($credits < 0)
377
			throw new Exception('Trying to increase negative credits.');
378
		if($credits == 0)
379
			return;
380
		$credits += $this->credits;
381
		$this->setCredits($credits);
382
	}
383
	public function decreaseCredits($credits) {
384
		if($credits < 0)
385
			throw new Exception('Trying to decrease negative credits.');
386
		if($credits == 0)
387
			return;
388
		$credits = $this->credits - $credits;
389
		$this->setCredits($credits);
390
	}
391
	public function setCredits($credits) {
392
		if($this->credits == $credits)
393
			return;
394
		if($credits < 0)
395
			throw new Exception('Trying to set negative credits.');
396
		if($credits > MAX_MONEY)
397
			$credits = MAX_MONEY;
398
		$this->credits = $credits;
399
		$this->hasChanged=true;
400
	}
401
402
	public function increaseExperience($experience) {
403
		if($experience < 0)
404
			throw new Exception('Trying to increase negative experience.');
405
		if($experience == 0)
406
			return;
407
		$newExperience = $this->experience + $experience;
408
		$this->setExperience($newExperience);
409
		$this->increaseHOF($experience,array('Experience','Total','Gain'), HOF_PUBLIC);
410
	}
411
	public function decreaseExperience($experience) {
412
		if($experience < 0)
413
			throw new Exception('Trying to decrease negative experience.');
414
		if($experience == 0)
415
			return;
416
		$newExperience = $this->experience - $experience;
417
		$this->setExperience($newExperience);
418
		$this->decreaseHOF($experience,array('Experience','Total','Loss'), HOF_PUBLIC);
419
	}
420
421
	public function isLandedOnPlanet() {
422
		return $this->landedOnPlanet;
423
	}
424
425
	public function setLandedOnPlanet($bool) {
426
		if($this->landedOnPlanet == $bool)
427
			return;
428
		$this->landedOnPlanet=$bool;
429
		$this->hasChanged=true;
430
	}
431
432
	/**
433
	 * Returns the numerical level of the player (e.g. 1-50).
434
	 */
435
	public function getLevelID() {
436
		// The level is cached for performance reasons unless `setExperience`
437
		// is called and the player's experience changes.
438
		if ($this->level === null) {
439
			$LEVELS_REQUIREMENTS = Globals::getLevelRequirements();
440
			foreach ($LEVELS_REQUIREMENTS as $level_id => $require) {
441
				if ($this->getExperience() >= $require['Requirement']) continue;
442
				$this->level = $level_id - 1;
443
				return $this->level;
444
			}
445
			$this->level = max(array_keys($LEVELS_REQUIREMENTS));
446
		}
447
		return $this->level;
448
	}
449
450
	public function getLevelName() {
451
		$level_name = Globals::getLevelRequirements()[$this->getLevelID()]['Name'];
452
		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

452
		if ($this->/** @scrutinizer ignore-call */ isPresident()) {
Loading history...
453
			$level_name = '<img src="images/council_president.png" title="' . Globals::getRaceName($this->getRaceID()) . ' President"></img>&nbsp;' . $level_name;
454
		}
455
		return $level_name;
456
	}
457
458
	public function getMaxLevel() {
459
		return max(array_keys(Globals::getLevelRequirements()));
460
	}
461
462
	public function getPlayerID() {
463
		return $this->playerID;
464
	}
465
466
	public function getPlayerName() {
467
		return $this->playerName . ($this->isNPC() ? ' <span class="npcColour">[NPC]</span>' : '');
468
	}
469
470
	public function setPlayerName($name) {
471
		$this->playerName = $name;
472
		$this->hasChanged = true;
473
	}
474
475
	public function getDisplayName($includeAlliance=false) {
476
		$return = get_colored_text($this->getAlignment(),$this->playerName.' ('.$this->getPlayerID().')');
477
		if($this->isNPC()) {
478
			$return .= ' <span class="npcColour">[NPC]</span>';
479
		}
480
		if($includeAlliance) {
481
			$return.= ' (' . $this->getAllianceName() . '</a>' . ')';
482
		}
483
		return $return;
484
	}
485
486
	public function getBBLink() {
487
			return '[player='.$this->getPlayerID().']';
488
	}
489
490
	public function getLinkedDisplayName($includeAlliance=true) {
491
		$return = '<a href="'.$this->getTraderSearchHREF().'">'.$this->getDisplayName().'</a>';
492
		if($includeAlliance) {
493
			$return .= ' (' . $this->getAllianceName(true) . ')';
494
		}
495
		return $return;
496
	}
497
498
	public function getRaceID() {
499
		return $this->raceID;
500
	}
501
502
	public function getRaceName() {
503
		return Globals::getRaceName($this->getRaceID());
504
	}
505
506
	public static function getColouredRaceNameOrDefault($otherRaceID, AbstractSmrPlayer $player = null, $linked = false) {
507
		$relations = 0;
508
		if($player !== null) {
509
			$relations = $player->getRelation($otherRaceID);
510
		}
511
		return Globals::getColouredRaceName($otherRaceID, $relations, $linked);
512
	}
513
514
	public function getColouredRaceName($otherRaceID, $linked = false) {
515
		return self::getColouredRaceNameOrDefault($otherRaceID, $this, $linked);
516
	}
517
518
	public function setRaceID($raceID) {
519
		if($this->raceID == $raceID)
520
			return;
521
		$this->raceID=$raceID;
522
		$this->hasChanged=true;
523
	}
524
525
	public function isAllianceLeader($forceUpdate = false) {
526
		return $this->getAccountID() == $this->getAlliance($forceUpdate)->getLeaderID();
527
	}
528
529
	public function &getAlliance($forceUpdate = false) {
530
		return SmrAlliance::getAlliance($this->getAllianceID(), $this->getGameID(), $forceUpdate);
531
	}
532
533
	public function getAllianceID() {
534
		return $this->allianceID;
535
	}
536
537
	public function hasAlliance() {
538
		return $this->getAllianceID()!=0;
539
	}
540
541
	public function setAllianceID($ID) {
542
		if($this->allianceID == $ID)
543
			return;
544
		$this->allianceID=$ID;
545
		if ($this->allianceID != 0) {
546
			$status = $this->hasNewbieStatus() ? 'NEWBIE' : 'VETERAN';
547
			$this->db->query('INSERT IGNORE INTO player_joined_alliance (account_id,game_id,alliance_id,status) ' .
548
				'VALUES ('.$this->db->escapeNumber($this->getAccountID()).','.$this->db->escapeNumber($this->getGameID()).','.$this->db->escapeNumber($this->getAllianceID()).','.$this->db->escapeString($status).')');
549
		}
550
		$this->hasChanged=true;
551
	}
552
553
	public function getAllianceBBLink() {
554
		return $this->hasAlliance()?'[alliance='.$this->getAllianceID().']':$this->getAllianceName();
555
	}
556
557
	public function getAllianceName($linked=false, $includeAllianceID=false) {
558
		if($this->hasAlliance()) {
559
			return $this->getAlliance()->getAllianceName($linked, $includeAllianceID);
560
		}
561
		else {
562
			return 'No Alliance';
563
		}
564
	}
565
566
	public function getAllianceRole($allianceID = false) {
567
		if ($allianceID === false) {
568
			$allianceID = $this->getAllianceID();
569
		}
570
		if(!isset($this->allianceRoles[$allianceID])) {
571
			$this->allianceRoles[$allianceID] = 0;
572
			$this->db->query('SELECT role_id
573
						FROM player_has_alliance_role
574
						WHERE ' . $this->SQL . '
575
						AND alliance_id=' . $this->db->escapeNumber($allianceID) . '
576
						LIMIT 1');
577
			if ($this->db->nextRecord()) {
578
				$this->allianceRoles[$allianceID] = $this->db->getInt('role_id');
579
			}
580
		}
581
		return $this->allianceRoles[$allianceID];
582
	}
583
584
	public function isCombatDronesKamikazeOnMines() {
585
		return $this->combatDronesKamikazeOnMines;
586
	}
587
588
	public function setCombatDronesKamikazeOnMines($bool) {
589
		if($this->combatDronesKamikazeOnMines == $bool)
590
			return;
591
		$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...
592
		$this->hasChanged=true;
593
	}
594
595
	protected abstract function getGadgetsData();
596
	public function getGadgets() {
597
		$this->getGadgetsData();
598
		return $this->gadgets;
599
	}
600
601
	public function getGadget($gadgetID) {
602
		if(!is_numeric($gadgetID)) {
603
			global $GADGETS;
604
			$gadgetID = $GADGETS[$gadgetID]['ID'];
605
		}
606
		$gadgets = $this->getGadgets();
607
		if(isset($gadgets[$gadgetID]))
608
			return $gadgets[$gadgetID];
609
		return false;
610
	}
611
612
	public function isGadgetEquipped($gadgetID) {
613
		$gadget = $this->getGadget($gadgetID);
614
		if($gadget===false)
615
			return false;
616
		return $gadget['Equipped'] > 0 && $gadget['Equipped'] < TIME && ($gadget['Expires'] == 0 || $gadget['Expires'] > TIME) && $gadget['Cooldown'] <= TIME;
617
	}
618
619
	protected abstract function getPureRelationsData();
620
621
	public function getPureRelations() {
622
		$this->getPureRelationsData();
623
		return $this->pureRelations;
624
	}
625
626
	/**
627
	 * Get personal relations with a race
628
	 */
629
	public function getPureRelation($raceID) {
630
		$rels = $this->getPureRelations();
631
		return $rels[$raceID];
632
	}
633
634
	public function getRelations() {
635
		if(!isset($this->relations)) {
636
			//get relations
637
			$RACES = Globals::getRaces();
638
			$raceRelations = Globals::getRaceRelations($this->getGameID(),$this->getRaceID());
639
			$pureRels = $this->getPureRelations(); // make sure they're initialised.
640
			$this->relations = array();
641
			foreach ($RACES as $raceID => $raceName) {
642
				$this->relations[$raceID] = $pureRels[$raceID] + $raceRelations[$raceID];
643
			}
644
		}
645
		return $this->relations;
646
	}
647
648
	/**
649
	 * Get total relations with a race (personal + political)
650
	 */
651
	public function getRelation($raceID) {
652
		$rels = $this->getRelations();
653
		return $rels[$raceID];
654
	}
655
656
	abstract public function &getShip();
657
658
	public function &shootPlayer(AbstractSmrPlayer $targetPlayer) {
659
		return $this->getShip()->shootPlayer($targetPlayer);
660
	}
661
662
	public function &shootForces(SmrForce $forces) {
663
		return $this->getShip()->shootForces($forces);
664
	}
665
666
	public function &shootPort(SmrPort $port) {
667
		return $this->getShip()->shootPort($port);
668
	}
669
670
	public function &shootPlanet(SmrPlanet $planet, $delayed) {
671
		return $this->getShip()->shootPlanet($planet, $delayed);
672
	}
673
674
	public function &shootPlayers(array $targetPlayers) {
675
		return $this->getShip()->shootPlayers($targetPlayers);
676
	}
677
678
	public function getMilitaryPayment() {
679
		return $this->militaryPayment;
680
	}
681
682
	public function hasMilitaryPayment() {
683
		return $this->getMilitaryPayment()>0;
684
	}
685
686
	public function setMilitaryPayment($amount) {
687
		if($this->militaryPayment == $amount)
688
			return;
689
		$this->militaryPayment = $amount;
690
		$this->hasChanged=true;
691
	}
692
693
	public function increaseMilitaryPayment($amount) {
694
		if($amount < 0)
695
			throw new Exception('Trying to increase negative military payment.');
696
		$this->setMilitaryPayment($this->getMilitaryPayment()+$amount);
697
	}
698
699
	public function decreaseMilitaryPayment($amount) {
700
		if($amount < 0)
701
			throw new Exception('Trying to decrease negative military payment.');
702
		$this->setMilitaryPayment($this->getMilitaryPayment()-$amount);
703
	}
704
705
	abstract protected function getBountiesData();
706
707
	public function getBounties() {
708
		$this->getBountiesData();
709
		return $this->bounties;
710
	}
711
712
	public function hasBounties() {
713
		return count($this->getBounties())>0;
714
	}
715
716
	public function getBounty($bountyID) {
717
		$bounties = $this->getBounties();
718
		return isset($bounties[$bountyID]) ? $bounties[$bountyID] : false;
719
	}
720
721
	public function hasBounty($bountyID) {
722
		return $this->getBounty($bountyID)!==false;
723
	}
724
725
	public function getBountyAmount($bountyID) {
726
		$bounty = $this->getBounty($bountyID);
727
		return $bounty['Amount'];
728
	}
729
730
	protected function createBounty($type) {
731
		$bounty = array('Amount' => 0,
732
						'SmrCredits' => 0,
733
						'Type' => $type,
734
						'Claimer' => 0,
735
						'Time' => TIME,
736
						'ID' => $this->getNextBountyID(),
737
						'New' => true);
738
		$this->setBounty($bounty);
739
	}
740
741
	public function getNextBountyID() {
742
		$keys = array_keys($this->getBounties());
743
		if(count($keys)>0)
744
			return max($keys)+1;
745
		else
746
			return 0;
747
	}
748
749
	public function setBounty(array $bounty) {
750
		$this->bounties[$bounty['ID']] = $bounty;
751
		$this->hasBountyChanged[$bounty['ID']]=true;
752
	}
753
754
	public function setBountyAmount($bountyID, $amount) {
755
		$bounty = $this->getBounty($bountyID);
756
		$bounty['Amount'] = $amount;
757
		$this->setBounty($bounty);
0 ignored issues
show
Bug introduced by
It seems like $bounty can also be of type false; however, parameter $bounty of AbstractSmrPlayer::setBounty() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

757
		$this->setBounty(/** @scrutinizer ignore-type */ $bounty);
Loading history...
758
	}
759
760
	public function increaseBountyAmount($bountyID,$amount) {
761
		if($amount < 0)
762
			throw new Exception('Trying to increase negative bounty.');
763
		$this->setBountyAmount($this->getBountyAmount($bountyID)+$amount);
0 ignored issues
show
Bug introduced by
The call to AbstractSmrPlayer::setBountyAmount() has too few arguments starting with amount. ( Ignorable by Annotation )

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

763
		$this->/** @scrutinizer ignore-call */ 
764
         setBountyAmount($this->getBountyAmount($bountyID)+$amount);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
764
	}
765
766
	public function decreaseBountyAmount($bountyID,$amount) {
767
		if($amount < 0)
768
			throw new Exception('Trying to decrease negative bounty.');
769
		$this->setBountyAmount($this->getBountyAmount($bountyID)+$amount);
0 ignored issues
show
Bug introduced by
The call to AbstractSmrPlayer::setBountyAmount() has too few arguments starting with amount. ( Ignorable by Annotation )

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

769
		$this->/** @scrutinizer ignore-call */ 
770
         setBountyAmount($this->getBountyAmount($bountyID)+$amount);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
770
	}
771
772
	public function getCurrentBounty($type) {
773
		$bounties = $this->getBounties();
774
		foreach($bounties as $bounty) {
775
			if($bounty['Claimer'] == 0 && $bounty['Type']==$type)
776
				return $bounty;
777
		}
778
		return $this->createBounty($type);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->createBounty($type) targeting AbstractSmrPlayer::createBounty() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
779
	}
780
781
	public function hasCurrentBounty($type) {
782
		$bounties = $this->getBounties();
783
		foreach($bounties as $bounty) {
784
			if($bounty['Claimer'] == 0 && $bounty['Type']==$type)
785
				return true;
786
		}
787
		return false;
788
	}
789
790
	public function getCurrentBountyAmount($type) {
791
		$bounty = $this->getCurrentBounty($type);
792
		return $bounty['Amount'];
793
	}
794
795
	public function setCurrentBountyAmount($type, $amount) {
796
		$bounty = $this->getCurrentBounty($type);
797
		if($bounty['Amount'] == $amount)
798
			return;
799
		$bounty['Amount'] = $amount;
800
		$this->setBounty($bounty);
0 ignored issues
show
Bug introduced by
It seems like $bounty can also be of type null; however, parameter $bounty of AbstractSmrPlayer::setBounty() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

800
		$this->setBounty(/** @scrutinizer ignore-type */ $bounty);
Loading history...
801
	}
802
803
	public function increaseCurrentBountyAmount($type,$amount) {
804
		if($amount < 0)
805
			throw new Exception('Trying to increase negative current bounty.');
806
		$this->setCurrentBountyAmount($type,$this->getCurrentBountyAmount($type)+$amount);
807
	}
808
809
	public function decreaseCurrentBountyAmount($type,$amount) {
810
		if($amount < 0)
811
			throw new Exception('Trying to decrease negative current bounty.');
812
		$this->setCurrentBountyAmount($type,$this->getCurrentBountyAmount($type)-$amount);
813
	}
814
815
	public function getCurrentBountySmrCredits($type) {
816
		$bounty = $this->getCurrentBounty($type);
817
		return $bounty['SmrCredits'];
818
	}
819
820
	public function setCurrentBountySmrCredits($type, $credits) {
821
		$bounty = $this->getCurrentBounty($type);
822
		if($bounty['SmrCredits'] == $credits)
823
			return;
824
		$bounty['SmrCredits'] = $credits;
825
		$this->setBounty($bounty);
0 ignored issues
show
Bug introduced by
It seems like $bounty can also be of type null; however, parameter $bounty of AbstractSmrPlayer::setBounty() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

825
		$this->setBounty(/** @scrutinizer ignore-type */ $bounty);
Loading history...
826
	}
827
828
	public function increaseCurrentBountySmrCredits($type,$credits) {
829
		if($credits<0)
830
			throw new Exception('Trying to increase negative current bounty.');
831
		$this->setCurrentBountySmrCredits($type,$this->getCurrentBountySmrCredits($type)+$credits);
832
	}
833
834
	public function decreaseCurrentBountySmrCredits($type,$credits) {
835
		if($credits<0)
836
			throw new Exception('Trying to decrease negative current bounty.');
837
		$this->setCurrentBountySmrCredits($type,$this->getCurrentBountySmrCredits($type)-$credits);
838
	}
839
840
	public function setBountiesClaimable(AbstractSmrPlayer $claimer) {
841
		$bounties = $this->getBounties();
842
		if(is_array($bounties)) {
843
			foreach($bounties as $bounty) {
844
				if($bounty['Claimer'] == 0) {
845
					$bounty['Claimer'] = $claimer->getAccountID();
846
					$this->setBounty($bounty);
847
				}
848
			}
849
		}
850
	}
851
852
853
	abstract protected function getHOFData();
854
855
	public function getHOF(array $typeList = null) {
856
		$this->getHOFData();
857
		if($typeList==null)
858
			return $this->HOF;
859
		$hof=$this->HOF;
860
		foreach($typeList as $type) {
861
			if(!isset($hof[$type]))
862
				return 0;
863
			$hof = $hof[$type];
864
		}
865
		return $hof;
866
	}
867
868
	public function increaseHOF($amount,array $typeList, $visibility) {
869
		if($amount < 0)
870
			throw new Exception('Trying to increase negative HOF: '.implode(':',$typeList));
871
		if($amount == 0)
872
			return;
873
		$this->setHOF($this->getHOF($typeList)+$amount,$typeList, $visibility);
874
	}
875
876
	public function decreaseHOF($amount,array $typeList, $visibility) {
877
		if($amount < 0)
878
			throw new Exception('Trying to decrease negative HOF: '.implode(':',$typeList));
879
		if($amount == 0)
880
			return;
881
		$this->setHOF($this->getHOF($typeList)-$amount,$typeList, $visibility);
882
	}
883
884
	public function setHOF($amount,array $typeList, $visibility) {
885
		if(is_array($this->getHOF($typeList)))
886
			throw new Exception('Trying to overwrite a HOF type: '.implode(':',$typeList));
887
		if($this->isNPC()) {
888
			// Don't store HOF for NPCs.
889
			return;
890
		}
891
		if($this->getHOF($typeList)==$amount)
892
			return;
893
		if($amount < 0)
894
			$amount=0;
895
		$this->getHOF();
896
897
		$hofType = implode(':',$typeList);
898
		if(!isset(self::$HOFVis[$hofType])) {
899
			self::$hasHOFVisChanged[$hofType] = self::HOF_NEW;
900
		}
901
		else if(self::$HOFVis[$hofType] != $visibility) {
902
			self::$hasHOFVisChanged[$hofType] = self::HOF_CHANGED;
903
		}
904
		self::$HOFVis[$hofType] = $visibility;
905
906
		$hof =& $this->HOF;
907
		$hofChanged =& $this->hasHOFChanged;
908
		$new = false;
909
		foreach($typeList as $type) {
910
			if(!isset($hofChanged[$type]))
911
				$hofChanged[$type] = array();
912
			if(!isset($hof[$type])) {
913
				$hof[$type] = array();
914
				$new = true;
915
			}
916
			$hof =& $hof[$type];
917
			$hofChanged =& $hofChanged[$type];
918
		}
919
		if($hofChanged==null) {
920
			$hofChanged = self::HOF_CHANGED;
921
			if($new)
922
				$hofChanged = self::HOF_NEW;
923
		}
924
		$hof = $amount;
925
	}
926
927
	abstract public function killPlayer($sectorID);
928
	abstract public function &killPlayerByPlayer(AbstractSmrPlayer $killer);
929
	abstract public function &killPlayerByForces(SmrForce $forces);
930
	abstract public function &killPlayerByPort(SmrPort $port);
931
	abstract public function &killPlayerByPlanet(SmrPlanet $planet);
932
933
934
	public function getTurns() {
935
		return $this->turns;
936
	}
937
938
	public function hasTurns() {
939
		return $this->turns>0;
940
	}
941
942
	public function getMaxTurns() {
943
		return Globals::getGameMaxTurns($this->getGameID());
944
//		round(DEFAULT_MAX_TURNS * Globals::getGameSpeed($this->getGameID()));
945
	}
946
947
	public function setTurns($turns,$newNoob = false,$updateLastActive = false) {
948
		if($this->turns == $turns && ($this->newbieTurns == $newNoob || $newNoob==false) && !$updateLastActive)
949
			return;
950
951
		// Make sure turns are in range [0, MaxTurns]
952
		$this->turns = max(0, min($turns, $this->getMaxTurns()));
953
954
		if($newNoob !== false)
955
			$this->newbieTurns = $newNoob;
956
		if ($this->newbieTurns < 0)
957
			$this->newbieTurns = 0;
958
959
		$this->hasChanged=true;
960
		if($updateLastActive === true) {
961
			$this->setLastActive(TIME);
962
			$this->updateLastCPLAction();
963
		}
964
	}
965
966
	public function takeTurns($take, $noob = 0, $updateLastActive = true) {
967
		if($take < 0 || $noob < 0)
968
			throw new Exception('Trying to take negative turns.');
969
		$take = ceil($take);
970
		$new_turns = $this->getTurns() - $take;
971
		$newbiesTaken = min($this->getNewbieTurns(),$noob);
972
		$new_noob = $this->getNewbieTurns() - $noob;
973
974
		$this->setTurns($new_turns, $new_noob, $updateLastActive);
975
		$this->increaseHOF($take,array('Movement','Turns Used','Since Last Death'), HOF_ALLIANCE);
976
		$this->increaseHOF($take,array('Movement','Turns Used','Total'), HOF_ALLIANCE);
977
		$this->increaseHOF($newbiesTaken,array('Movement','Turns Used','Newbie'), HOF_ALLIANCE);
978
	}
979
980
	public function giveTurns($give, $noob = 0,$updateLastActive = false) {
981
		if($give < 0 || $noob < 0)
982
			throw new Exception('Trying to give negative turns.');
983
		$give = floor($give);
984
985
		$this->setTurns($this->getTurns() + $give, $this->getNewbieTurns() + $noob, $updateLastActive);
986
	}
987
988
	public function getLastActive() {
989
		return $this->lastActive;
990
	}
991
992
	public function setLastActive($lastActive) {
993
		if($this->lastActive == $lastActive)
994
			return;
995
		$this->lastActive=$lastActive;
996
		$this->hasChanged=true;
997
	}
998
999
	public function getLastCPLAction() {
1000
		return $this->lastCPLAction;
1001
	}
1002
1003
	public function setLastCPLAction($time) {
1004
		if($this->lastCPLAction == $time)
1005
			return;
1006
		$this->lastCPLAction=$time;
1007
		$this->hasChanged=true;
1008
	}
1009
1010
	public function updateLastCPLAction() {
1011
		$this->setLastCPLAction(TIME);
1012
	}
1013
1014
1015
	function getCompletedMissions() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1016
		if(!isset($this->completedMissions)) {
1017
			//Get Player missions
1018
			$this->db->query('SELECT mission_id FROM player_completed_mission WHERE ' . $this->SQL);
1019
			$this->completedMissions = array();
1020
			while ($this->db->nextRecord())
1021
				$this->completedMissions[$this->db->getField('mission_id')] = $this->db->getField('mission_id');
1022
		}
1023
		return $this->completedMissions;
1024
	}
1025
1026
	public function getMissions() {
1027
		if(!isset($this->missions)) {
1028
			$this->db->query('SELECT * FROM player_has_mission WHERE ' . $this->SQL);
1029
			$this->missions = array();
1030
			while ($this->db->nextRecord()) {
1031
				$missionID = $this->db->getInt('mission_id');
1032
				$this->missions[$missionID] = array(
1033
					'On Step' => $this->db->getInt('on_step'),
1034
					'Progress' => $this->db->getInt('progress'),
1035
					'Unread' => $this->db->getBoolean('unread'),
1036
					'Expires' => $this->db->getInt('step_fails'),
1037
					'Sector' => $this->db->getInt('mission_sector'),
1038
					'Starting Sector' => $this->db->getInt('starting_sector')
1039
				);
1040
				$this->rebuildMission($missionID);
1041
			}
1042
		}
1043
		return $this->missions;
1044
	}
1045
1046
	public function getActiveMissions() {
1047
		$missions = $this->getMissions();
1048
		foreach($missions as $missionID => $mission) {
1049
			if ($mission['On Step'] >= count(MISSIONS[$missionID]['Steps'])) {
1050
				unset($missions[$missionID]);
1051
			}
1052
		}
1053
		return $missions;
1054
	}
1055
1056
	function getMission($missionID) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1057
		$missions = $this->getMissions();
1058
		if(isset($missions[$missionID]))
1059
			return $missions[$missionID];
1060
		return false;
1061
	}
1062
1063
	function hasMission($missionID) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1064
		return $this->getMission($missionID) !== false;
1065
	}
1066
1067
	function updateMission($missionID) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1068
		$this->getMissions();
1069
		if(isset($this->missions[$missionID])) {
1070
			$mission = $this->missions[$missionID];
1071
			$this->db->query('
1072
				UPDATE player_has_mission
1073
				SET on_step = ' . $this->db->escapeNumber($mission['On Step']) . ',
1074
					progress = ' . $this->db->escapeNumber($mission['Progress']) . ',
1075
					unread = ' . $this->db->escapeBoolean($mission['Unread']) . ',
1076
					starting_sector = ' . $this->db->escapeNumber($mission['Starting Sector']) . ',
1077
					mission_sector = ' . $this->db->escapeNumber($mission['Sector']) . ',
1078
					step_fails = ' . $this->db->escapeNumber($mission['Expires']) . '
1079
				WHERE ' . $this->SQL . ' AND mission_id = ' . $this->db->escapeNumber($missionID) . ' LIMIT 1'
1080
			);
1081
			return true;
1082
		}
1083
		return false;
1084
	}
1085
1086
	private function setupMissionStep($missionID) {
1087
		$mission =& $this->missions[$missionID];
1088
		$step = MISSIONS[$missionID]['Steps'][$mission['On Step']];
1089
		if(isset($step['PickSector'])) {
1090
			$realX = Plotter::getX($step['PickSector']['Type'], $step['PickSector']['X'], $this->getGameID());
1091
			if($realX === false) {
1092
				throw new Exception('Invalid PickSector definition in mission: ' . $missionID);
1093
			}
1094
			$path = Plotter::findDistanceToX($realX, $this->getSector(), true, null, $this);
1095
			if($path === false) {
1096
				throw new Exception('Cannot find location: ' . $missionID);
1097
			}
1098
			$mission['Sector'] = $path->getEndSectorID();
1099
		}
1100
	}
1101
1102
	function addMission($missionID) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1103
		$this->getMissions();
1104
1105
		if(isset($this->missions[$missionID]))
1106
			return;
1107
		$sector = 0;
1108
1109
		$mission = array(
1110
			'On Step' => 0,
1111
			'Progress' => 0,
1112
			'Unread' => true,
1113
			'Expires' => (TIME + 86400),
1114
			'Sector' => $sector,
1115
			'Starting Sector' => $this->getSectorID()
1116
		);
1117
1118
		$this->missions[$missionID] =& $mission;
1119
		$this->setupMissionStep($missionID);
1120
		$this->rebuildMission($missionID);
1121
1122
		$this->db->query('
1123
			REPLACE INTO player_has_mission (game_id,account_id,mission_id,on_step,progress,unread,starting_sector,mission_sector,step_fails)
1124
			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']).')'
1125
		);
1126
	}
1127
1128
	function rebuildMission($missionID) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1129
		$mission = $this->missions[$missionID];
1130
		$this->missions[$missionID]['Name'] = MISSIONS[$missionID]['Name'];
1131
1132
		if ($mission['On Step'] >= count(MISSIONS[$missionID]['Steps'])) {
1133
			// If we have completed this mission just use false to indicate no current task.
1134
			$currentStep = false;
1135
		}
1136
		else {
1137
			$currentStep = MISSIONS[$missionID]['Steps'][$mission['On Step']];
1138
			$currentStep['Text'] = str_replace(array('<Race>','<Sector>','<Starting Sector>','<trader>'),array($this->getRaceID(),$mission['Sector'],$mission['Starting Sector'],$this->playerName),$currentStep['Text']);
1139
			if (isset($currentStep['Task'])) {
1140
				$currentStep['Task'] = str_replace(array('<Race>','<Sector>','<Starting Sector>','<trader>'),array($this->getRaceID(),$mission['Sector'],$mission['Starting Sector'],$this->playerName),$currentStep['Task']);
1141
			}
1142
			if (isset($currentStep['Level'])) {
1143
				$currentStep['Level'] = str_replace('<Player Level>', $this->getLevelID(), $currentStep['Level']);
1144
			}
1145
			else {
1146
				$currentStep['Level'] = 0;
1147
			}
1148
		}
1149
		$this->missions[$missionID]['Task'] = $currentStep;
1150
	}
1151
1152
	function deleteMission($missionID) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1153
		$this->getMissions();
1154
		if(isset($this->missions[$missionID])) {
1155
			unset($this->missions[$missionID]);
1156
			$this->db->query('DELETE FROM player_has_mission WHERE '.$this->SQL.' AND mission_id = '.$this->db->escapeNumber($missionID).' LIMIT 1');
1157
			return true;
1158
		}
1159
		return false;
1160
	}
1161
1162
	public function markMissionsRead() {
1163
		$this->getMissions();
1164
		$unreadMissions = array();
1165
		foreach($this->missions as $missionID => &$mission) {
1166
			if($mission['Unread']) {
1167
				$unreadMissions[] = $missionID;
1168
				$mission['Unread'] = false;
1169
				$this->updateMission($missionID);
1170
			}
1171
		}
1172
		return $unreadMissions;
1173
	}
1174
1175
	public function claimMissionReward($missionID) {
1176
		$this->getMissions();
1177
		$mission =& $this->missions[$missionID];
1178
		if($mission === false) {
1179
			throw new Exception('Unknown mission: ' . $missionID);
1180
		}
1181
		if($mission['Task'] === false || $mission['Task']['Step'] != 'Claim') {
1182
			throw new Exception('Cannot claim mission: ' . $missionID . ', for step: ' . $mission['On Step']);
1183
		}
1184
		$mission['On Step']++;
1185
		$mission['Unread'] = true;
1186
		foreach($mission['Task']['Rewards'] as $rewardItem => $amount) {
1187
			switch($rewardItem) {
1188
				case 'Credits':
1189
					$this->increaseCredits($amount);
1190
				break;
1191
				case 'Experience':
1192
					$this->increaseExperience($amount);
1193
				break;
1194
			}
1195
		}
1196
		$rewardText = $mission['Task']['Rewards']['Text'];
1197
		if ($mission['On Step'] < count(MISSIONS[$missionID]['Steps'])) {
1198
			// If we haven't finished the mission yet then 
1199
			$this->setupMissionStep($missionID);
1200
		}
1201
		$this->rebuildMission($missionID);
1202
		$this->updateMission($missionID);
1203
		return $rewardText;
1204
	}
1205
1206
	public function getAvailableMissions() {
1207
		$availableMissions = array();
1208
		foreach (MISSIONS as $missionID => $mission) {
1209
			if($this->hasMission($missionID)) {
1210
				continue;
1211
			}
1212
			$realX = Plotter::getX($mission['HasX']['Type'], $mission['HasX']['X'], $this->getGameID());
1213
			if($realX === false) {
1214
				throw new Exception('Invalid HasX definition in mission: ' . $missionID);
1215
			}
1216
			if($this->getSector()->hasX($realX)) {
1217
				$availableMissions[$missionID] = $mission;
1218
			}
1219
		}
1220
		return $availableMissions;
1221
	}
1222
1223
	public function actionTaken($actionID, array $values) {
1224
		if (!in_array($actionID, MISSION_ACTIONS)) {
1225
			throw new Exception('Unknown action: ' . $actionID);
1226
		}
1227
// TODO: Reenable this once tested.		if($this->getAccount()->isLoggingEnabled())
1228
			switch($actionID) {
1229
				case 'WalkSector':
1230
					$this->getAccount()->log(LOG_TYPE_MOVEMENT, 'Walks to sector: ' . $values['Sector']->getSectorID(), $this->getSectorID());
1231
				break;
1232
				case 'JoinAlliance':
1233
					$this->getAccount()->log(LOG_TYPE_ALLIANCE, 'joined alliance: '.$values['Alliance']->getAllianceName(), $this->getSectorID());
1234
				break;
1235
				case 'LeaveAlliance':
1236
					$this->getAccount()->log(LOG_TYPE_ALLIANCE, 'left alliance: '.$values['Alliance']->getAllianceName(), $this->getSectorID());
1237
				break;
1238
				case 'DisbandAlliance':
1239
					$this->getAccount()->log(LOG_TYPE_ALLIANCE, 'disbanded alliance '.$values['Alliance']->getAllianceName(), $this->getSectorID());
1240
				break;
1241
				case 'KickPlayer':
1242
					$this->getAccount()->log(LOG_TYPE_ALLIANCE, 'kicked '.$values['Player']->getAccount()->getLogin().' ('.$values['Player']->getPlayerName().') from alliance '.$values['Alliance']->getAllianceName(), 0);
1243
				break;
1244
				case 'PlayerKicked':
1245
					$this->getAccount()->log(LOG_TYPE_ALLIANCE, 'was kicked from alliance '.$values['Alliance']->getAllianceName().' by '.$values['Player']->getAccount()->getLogin().' ('.$values['Player']->getPlayerName().')', 0);
1246
				break;
1247
1248
			}
1249
		$this->getMissions();
1250
		foreach($this->missions as $missionID => &$mission) {
1251
			if($mission['Task'] !== false && $mission['Task']['Step'] == $actionID) {
1252
				if(checkMissionRequirements($values, $mission, $this) === true) {
1253
					$mission['On Step']++;
1254
					$mission['Unread'] = true;
1255
					$this->setupMissionStep($missionID);
1256
					$this->rebuildMission($missionID);
1257
					$this->updateMission($missionID);
1258
				}
1259
			}
1260
		}
1261
	}
1262
1263
	public function canSeeAny(array $otherPlayerArray) {
1264
		foreach($otherPlayerArray as $otherPlayer) {
1265
			if($this->canSee($otherPlayer)) {
1266
				return true;
1267
			}
1268
		}
1269
		return false;
1270
	}
1271
1272
	public function canSee(AbstractSmrPlayer $otherPlayer) {
1273
		if(!$otherPlayer->getShip()->isCloaked())
1274
			return true;
1275
		if($this->sameAlliance($otherPlayer))
1276
			return true;
1277
		if($this->getExperience()>=$otherPlayer->getExperience())
1278
			return true;
1279
		return false;
1280
	}
1281
1282
	public function equals(AbstractSmrPlayer $otherPlayer = null) {
1283
		return $otherPlayer!==null && $this->getAccountID()==$otherPlayer->getAccountID() && $this->getGameID()==$otherPlayer->getGameID();
1284
	}
1285
1286
	public function sameAlliance(AbstractSmrPlayer $otherPlayer = null) {
1287
		return $otherPlayer != null && ($this->equals($otherPlayer) || ($this->hasAlliance() && $this->getAllianceID()==$otherPlayer->getAllianceID()));
1288
	}
1289
1290
	public function sharedForceAlliance(AbstractSmrPlayer $otherPlayer = null) {
1291
		return $this->sameAlliance($otherPlayer);
1292
	}
1293
1294
	public function forceNAPAlliance(AbstractSmrPlayer $otherPlayer = null) {
1295
		return $this->sameAlliance($otherPlayer);
1296
	}
1297
1298
	public function planetNAPAlliance(AbstractSmrPlayer $otherPlayer = null) {
1299
		return $this->sameAlliance($otherPlayer);
1300
	}
1301
1302
	public function traderNAPAlliance(AbstractSmrPlayer $otherPlayer = null) {
1303
		return $this->sameAlliance($otherPlayer);
1304
	}
1305
1306
	public function traderMAPAlliance(AbstractSmrPlayer $otherPlayer = null) {
1307
		return $this->traderAttackTraderAlliance($otherPlayer) && $this->traderDefendTraderAlliance($otherPlayer);
1308
	}
1309
1310
	public function traderAttackTraderAlliance(AbstractSmrPlayer $otherPlayer = null) {
1311
		return $this->sameAlliance($otherPlayer);
1312
	}
1313
1314
	public function traderDefendTraderAlliance(AbstractSmrPlayer $otherPlayer = null) {
1315
		return $this->sameAlliance($otherPlayer);
1316
	}
1317
1318
	public function traderAttackForceAlliance(AbstractSmrPlayer $otherPlayer = null) {
1319
		return $this->sameAlliance($otherPlayer);
1320
	}
1321
1322
	public function traderAttackPortAlliance(AbstractSmrPlayer $otherPlayer = null) {
1323
		return $this->sameAlliance($otherPlayer);
1324
	}
1325
1326
	public function traderAttackPlanetAlliance(AbstractSmrPlayer $otherPlayer = null) {
1327
		return $this->sameAlliance($otherPlayer);
1328
	}
1329
1330
	public function meetsAlignmentRestriction($restriction) {
1331
		if($restriction<0)
1332
			return $this->getAlignment()<=$restriction;
1333
		if($restriction>0)
1334
			return $this->getAlignment()>=$restriction;
1335
		return true;
1336
	}
1337
1338
	// Get an array of goods that are visible to the player
1339
	public function getVisibleGoods() {
1340
		$goods = Globals::getGoods();
1341
		$visibleGoods = array();
1342
		foreach ($goods as $key => $good) {
1343
			if ($this->meetsAlignmentRestriction($good['AlignRestriction'])) {
1344
				$visibleGoods[$key] = $good;
1345
			}
1346
		}
1347
		return $visibleGoods;
1348
	}
1349
1350
	/**
1351
	 * Will retrieve all visited sectors, use only when you are likely to check a large number of these
1352
	 */
1353
	public function hasVisitedSector($sectorID) {
1354
		if(!isset($this->visitedSectors)) {
1355
			$this->visitedSectors = array();
1356
			$this->db->query('SELECT sector_id FROM player_visited_sector WHERE ' . $this->SQL);
1357
			while($this->db->nextRecord())
1358
				$this->visitedSectors[$this->db->getField('sector_id')] = false;
1359
		}
1360
		return !isset($this->visitedSectors[$sectorID]);
1361
	}
1362
1363
	public function getLeaveNewbieProtectionHREF() {
1364
		return SmrSession::getNewHREF(create_container('leave_newbie_processing.php'));
1365
	}
1366
1367
	public function getExamineTraderHREF() {
1368
		$container = create_container('skeleton.php','trader_examine.php');
1369
		$container['target'] = $this->getAccountID();
1370
		return SmrSession::getNewHREF($container);
1371
	}
1372
1373
	public function getAttackTraderHREF() {
1374
		return Globals::getAttackTraderHREF($this->getAccountID());
1375
	}
1376
1377
	public function getPlanetKickHREF() {
1378
		$container = create_container('planet_kick_processing.php','trader_attack_processing.php');
1379
		$container['account_id'] = $this->getAccountID();
1380
		return SmrSession::getNewHREF($container);
1381
	}
1382
1383
	public function getTraderSearchHREF() {
1384
		$container = create_container('skeleton.php','trader_search_result.php');
1385
		$container['player_id'] = $this->getPlayerID();
1386
		return SmrSession::getNewHREF($container);
1387
	}
1388
1389
	public function getAllianceRosterHREF() {
1390
		return Globals::getAllianceRosterHREF($this->getAllianceID());
1391
	}
1392
1393
	public function getToggleWeaponHidingHREF() {
1394
		$container = create_container('skeleton.php','toggle_processing.php');
1395
		$container['toggle'] = 'WeaponHiding';
1396
		return SmrSession::getNewHREF($container);
1397
	}
1398
}
1399