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

Completed
Push — master ( 1adc02...750da7 )
by Dan
23s queued 16s
created

SmrPlayer::sendAllianceInvitation()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 3
dl 0
loc 7
rs 10
1
<?php declare(strict_types=1);
2
3
// Exception thrown when a player cannot be found in the database
4
class PlayerNotFoundException extends Exception {}
5
6
class SmrPlayer extends AbstractSmrPlayer {
7
	const TIME_FOR_FEDERAL_BOUNTY_ON_PR = 10800;
8
	const TIME_FOR_ALLIANCE_SWITCH = 0;
9
	protected static $CACHE_SECTOR_PLAYERS = array();
10
	protected static $CACHE_PLANET_PLAYERS = array();
11
	protected static $CACHE_ALLIANCE_PLAYERS = array();
12
	protected static $CACHE_PLAYERS = array();
13
14
	protected $db;
15
	protected $SQL;
16
17
	protected $newbieWarning;
18
	protected $tickers;
19
	protected $lastTurnUpdate;
20
	protected $lastNewsUpdate;
21
	protected $attackColour;
22
//	protected $pastKnowledge;
23
	protected $allianceJoinable;
24
	protected $lastPort;
25
	protected $bank;
26
	protected $zoom;
27
	protected $displayMissions;
28
	protected $displayWeapons;
29
	protected $ignoreGlobals;
30
	protected $plottedCourse;
31
	protected $plottedCourseFrom;
32
	protected $nameChanged;
33
	protected $combatDronesKamikazeOnMines;
34
	protected $customShipName;
35
	protected $storedDestinations;
36
37
38
	public static function refreshCache() {
39
		foreach (self::$CACHE_PLAYERS as $gameID => &$gamePlayers) {
40
			foreach ($gamePlayers as $accountID => &$player) {
41
				$player = self::getPlayer($accountID, $gameID, true);
42
			}
43
		}
44
	}
45
46
	public static function clearCache() {
47
		self::$CACHE_PLAYERS = array();
48
		self::$CACHE_SECTOR_PLAYERS = array();
49
	}
50
51
	public static function savePlayers() {
52
		foreach (self::$CACHE_PLAYERS as $gamePlayers) {
53
			foreach ($gamePlayers as $player) {
54
				$player->save();
55
			}
56
		}
57
	}
58
59
	public static function getSectorPlayersByAlliances($gameID, $sectorID, array $allianceIDs, $forceUpdate = false) {
60
		$players = self::getSectorPlayers($gameID, $sectorID, $forceUpdate); // Don't use & as we do an unset
61
		foreach ($players as $accountID => $player) {
62
			if (!in_array($player->getAllianceID(), $allianceIDs)) {
63
				unset($players[$accountID]);
64
			}
65
		}
66
		return $players;
67
	}
68
69
	/**
70
	 * Returns the same players as getSectorPlayers (e.g. not on planets),
71
	 * but for an entire galaxy rather than a single sector. This is useful
72
	 * for reducing the number of queries in galaxy-wide processing.
73
	 */
74
	public static function getGalaxyPlayers($gameID, $galaxyID, $forceUpdate = false) {
75
		$db = new SmrMySqlDatabase();
76
		$db->query('SELECT player.*, sector_id FROM sector LEFT JOIN player USING(game_id, sector_id) WHERE game_id = ' . $db->escapeNumber($gameID) . ' AND land_on_planet = ' . $db->escapeBoolean(false) . ' AND (last_cpl_action > ' . $db->escapeNumber(TIME - TIME_BEFORE_INACTIVE) . ' OR newbie_turns = 0) AND galaxy_id = ' . $db->escapeNumber($galaxyID));
77
		$galaxyPlayers = [];
78
		while ($db->nextRecord()) {
79
			$sectorID = $db->getInt('sector_id');
80
			if (!$db->hasField('account_id')) {
81
				self::$CACHE_SECTOR_PLAYERS[$gameID][$sectorID] = [];
82
			} else {
83
				$accountID = $db->getInt('account_id');
84
				$player = self::getPlayer($accountID, $gameID, $forceUpdate, $db);
85
				self::$CACHE_SECTOR_PLAYERS[$gameID][$sectorID][$accountID] = $player;
86
				$galaxyPlayers[$sectorID][$accountID] = $player;
87
			}
88
		}
89
		return $galaxyPlayers;
90
	}
91
92
	public static function getSectorPlayers($gameID, $sectorID, $forceUpdate = false) {
93
		if ($forceUpdate || !isset(self::$CACHE_SECTOR_PLAYERS[$gameID][$sectorID])) {
94
			$db = new SmrMySqlDatabase();
95
			$db->query('SELECT * FROM player WHERE sector_id = ' . $db->escapeNumber($sectorID) . ' AND game_id=' . $db->escapeNumber($gameID) . ' AND land_on_planet = ' . $db->escapeBoolean(false) . ' AND (last_cpl_action > ' . $db->escapeNumber(TIME - TIME_BEFORE_INACTIVE) . ' OR newbie_turns = 0) AND account_id NOT IN (' . $db->escapeArray(Globals::getHiddenPlayers()) . ') ORDER BY last_cpl_action DESC');
96
			$players = array();
97
			while ($db->nextRecord()) {
98
				$accountID = $db->getInt('account_id');
99
				$players[$accountID] = self::getPlayer($accountID, $gameID, $forceUpdate, $db);
100
			}
101
			self::$CACHE_SECTOR_PLAYERS[$gameID][$sectorID] = $players;
102
		}
103
		return self::$CACHE_SECTOR_PLAYERS[$gameID][$sectorID];
104
	}
105
106
	public static function getPlanetPlayers($gameID, $sectorID, $forceUpdate = false) {
107
		if ($forceUpdate || !isset(self::$CACHE_PLANET_PLAYERS[$gameID][$sectorID])) {
108
			$db = new SmrMySqlDatabase();
109
			$db->query('SELECT * FROM player WHERE sector_id = ' . $db->escapeNumber($sectorID) . ' AND game_id=' . $db->escapeNumber($gameID) . ' AND land_on_planet = ' . $db->escapeBoolean(true) . ' AND account_id NOT IN (' . $db->escapeArray(Globals::getHiddenPlayers()) . ') ORDER BY last_cpl_action DESC');
110
			$players = array();
111
			while ($db->nextRecord()) {
112
				$accountID = $db->getInt('account_id');
113
				$players[$accountID] = self::getPlayer($accountID, $gameID, $forceUpdate, $db);
114
			}
115
			self::$CACHE_PLANET_PLAYERS[$gameID][$sectorID] = $players;
116
		}
117
		return self::$CACHE_PLANET_PLAYERS[$gameID][$sectorID];
118
	}
119
120
	public static function getAlliancePlayers($gameID, $allianceID, $forceUpdate = false) {
121
		if ($forceUpdate || !isset(self::$CACHE_ALLIANCE_PLAYERS[$gameID][$allianceID])) {
122
			$db = new SmrMySqlDatabase();
123
			$db->query('SELECT * FROM player WHERE alliance_id = ' . $db->escapeNumber($allianceID) . ' AND game_id=' . $db->escapeNumber($gameID) . ' ORDER BY experience DESC');
124
			$players = array();
125
			while ($db->nextRecord()) {
126
				$accountID = $db->getInt('account_id');
127
				$players[$accountID] = self::getPlayer($accountID, $gameID, $forceUpdate, $db);
128
			}
129
			self::$CACHE_ALLIANCE_PLAYERS[$gameID][$allianceID] = $players;
130
		}
131
		return self::$CACHE_ALLIANCE_PLAYERS[$gameID][$allianceID];
132
	}
133
134
	public static function getPlayer($accountID, $gameID, $forceUpdate = false, $db = null) {
135
		if ($forceUpdate || !isset(self::$CACHE_PLAYERS[$gameID][$accountID])) {
136
			self::$CACHE_PLAYERS[$gameID][$accountID] = new SmrPlayer($gameID, $accountID, $db);
137
		}
138
		return self::$CACHE_PLAYERS[$gameID][$accountID];
139
	}
140
141
	public static function getPlayerByPlayerID($playerID, $gameID, $forceUpdate = false) {
142
		$db = new SmrMySqlDatabase();
143
		$db->query('SELECT * FROM player WHERE game_id = ' . $db->escapeNumber($gameID) . ' AND player_id = ' . $db->escapeNumber($playerID) . ' LIMIT 1');
144
		if ($db->nextRecord()) {
145
			return self::getPlayer($db->getInt('account_id'), $gameID, $forceUpdate, $db);
146
		}
147
		throw new PlayerNotFoundException('Player ID not found.');
148
	}
149
150
	public static function getPlayerByPlayerName($playerName, $gameID, $forceUpdate = false) {
151
		$db = new SmrMySqlDatabase();
152
		$db->query('SELECT * FROM player WHERE game_id = ' . $db->escapeNumber($gameID) . ' AND player_name = ' . $db->escapeString($playerName) . ' LIMIT 1');
153
		if ($db->nextRecord()) {
154
			return self::getPlayer($db->getInt('account_id'), $gameID, $forceUpdate, $db);
155
		}
156
		throw new PlayerNotFoundException('Player Name not found.');
157
	}
158
159
	protected function __construct($gameID, $accountID, $db = null) {
160
		parent::__construct();
161
		$this->db = new SmrMySqlDatabase();
162
		$this->SQL = 'account_id = ' . $this->db->escapeNumber($accountID) . ' AND game_id = ' . $this->db->escapeNumber($gameID);
163
164
		if (isset($db)) {
165
			$playerExists = true;
166
		} else {
167
			$db = $this->db;
168
			$this->db->query('SELECT * FROM player WHERE ' . $this->SQL . ' LIMIT 1');
169
			$playerExists = $db->nextRecord();
170
		}
171
172
		if ($playerExists) {
173
			$this->accountID = (int)$accountID;
174
			$this->gameID = (int)$gameID;
175
			$this->playerName = $db->getField('player_name');
176
			$this->playerID = $db->getInt('player_id');
177
			$this->sectorID = $db->getInt('sector_id');
178
			$this->lastSectorID = $db->getInt('last_sector_id');
179
			$this->turns = $db->getInt('turns');
180
			$this->lastTurnUpdate = $db->getInt('last_turn_update');
181
			$this->newbieTurns = $db->getInt('newbie_turns');
182
			$this->lastNewsUpdate = $db->getInt('last_news_update');
183
			$this->attackColour = $db->getField('attack_warning');
184
			$this->dead = $db->getBoolean('dead');
185
			$this->npc = $db->getBoolean('npc');
186
			$this->newbieStatus = $db->getBoolean('newbie_status');
187
			$this->landedOnPlanet = $db->getBoolean('land_on_planet');
188
			$this->lastActive = $db->getInt('last_active');
189
			$this->lastCPLAction = $db->getInt('last_cpl_action');
190
			$this->raceID = $db->getInt('race_id');
191
			$this->credits = $db->getInt('credits');
192
			$this->experience = $db->getInt('experience');
193
			$this->alignment = $db->getInt('alignment');
194
			$this->militaryPayment = $db->getInt('military_payment');
195
			$this->allianceID = $db->getInt('alliance_id');
196
			$this->allianceJoinable = $db->getInt('alliance_join');
197
			$this->shipID = $db->getInt('ship_type_id');
198
			$this->kills = $db->getInt('kills');
199
			$this->deaths = $db->getInt('deaths');
200
			$this->assists = $db->getInt('assists');
201
			$this->lastPort = $db->getInt('last_port');
202
			$this->bank = $db->getInt('bank');
203
			$this->zoom = $db->getInt('zoom');
204
			$this->displayMissions = $db->getBoolean('display_missions');
205
			$this->displayWeapons = $db->getBoolean('display_weapons');
206
			$this->forceDropMessages = $db->getBoolean('force_drop_messages');
0 ignored issues
show
Bug Best Practice introduced by
The property forceDropMessages does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
207
			$this->groupScoutMessages = $db->getField('group_scout_messages');
0 ignored issues
show
Bug Best Practice introduced by
The property groupScoutMessages does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
208
			$this->ignoreGlobals = $db->getBoolean('ignore_globals');
209
			$this->newbieWarning = $db->getBoolean('newbie_warning');
210
			$this->nameChanged = $db->getBoolean('name_changed');
211
			$this->combatDronesKamikazeOnMines = $db->getBoolean('combat_drones_kamikaze_on_mines');
212
		} else {
213
			throw new PlayerNotFoundException('Invalid accountID: ' . $accountID . ' OR gameID:' . $gameID);
214
		}
215
	}
216
217
	/**
218
	 * Insert a new player into the database. Returns the new player object.
219
	 */
220
	public static function createPlayer($accountID, $gameID, $playerName, $raceID, $isNewbie, $npc=false) {
221
		// Put the player in a sector with an HQ
222
		$startSectorID = self::getHome($gameID, $raceID);
223
224
		$db = new SmrMySqlDatabase();
225
		$db->lockTable('player');
226
227
		// Escape html elements so the name displays correctly
228
		$playerName = htmlentities($playerName);
229
230
		// Player names must be unique within each game
231
		$db->query('SELECT 1 FROM player WHERE game_id = ' . $db->escapeNumber($gameID) . ' AND player_name = ' . $db->escapeString($playerName) . ' LIMIT 1');
232
		if ($db->nextRecord() > 0) {
233
			$db->unlock();
234
			create_error('The player name already exists.');
235
		}
236
237
		// get last registered player id in that game and increase by one.
238
		$db->query('SELECT MAX(player_id) FROM player WHERE game_id = ' . $db->escapeNumber($gameID));
239
		if ($db->nextRecord()) {
240
			$playerID = $db->getInt('MAX(player_id)') + 1;
241
		} else {
242
			$playerID = 1;
243
		}
244
245
		$db->query('INSERT INTO player (account_id, game_id, player_id, player_name, race_id, sector_id, last_cpl_action, last_active, npc, newbie_status)
246
					VALUES(' . $db->escapeNumber($accountID) . ', ' . $db->escapeNumber($gameID) . ', ' . $db->escapeNumber($playerID) . ', ' . $db->escapeString($playerName) . ', ' . $db->escapeNumber($raceID) . ', ' . $db->escapeNumber($startSectorID) . ', ' . $db->escapeNumber(TIME) . ', ' . $db->escapeNumber(TIME) . ',' . $db->escapeBoolean($npc) . ',' . $db->escapeBoolean($isNewbie) . ')');
247
248
		$db->unlock();
249
250
		return SmrPlayer::getPlayer($accountID, $gameID);
251
	}
252
253
	// Get array of players whose info can be accessed by this player.
254
	// Skips players who are not in the same alliance as this player.
255
	public function getSharingPlayers($forceUpdate = false) {
256
		$results = array($this);
257
258
		// Only return this player if not in an alliance
259
		if (!$this->hasAlliance()) {
260
			return $results;
261
		}
262
263
		// Get other players who are sharing info for this game.
264
		// NOTE: game_id=0 means that player shares info for all games.
265
		$this->db->query('SELECT from_account_id FROM account_shares_info WHERE to_account_id=' . $this->db->escapeNumber($this->getAccountID()) . ' AND (game_id=0 OR game_id=' . $this->db->escapeNumber($this->getGameID()) . ')');
266
		while ($this->db->nextRecord()) {
267
			try {
268
				$otherPlayer = SmrPlayer::getPlayer($this->db->getInt('from_account_id'),
269
				                                    $this->getGameID(), $forceUpdate);
270
			} catch (PlayerNotFoundException $e) {
271
				// Skip players that have not joined this game
272
				continue;
273
			}
274
275
			// players must be in the same alliance
276
			if ($this->sameAlliance($otherPlayer)) {
277
				$results[] = $otherPlayer;
278
			}
279
		}
280
		return $results;
281
	}
282
283
	public function getShip($forceUpdate = false) {
284
		return SmrShip::getShip($this, $forceUpdate);
285
	}
286
287
	public function getAccount() {
288
		return SmrAccount::getAccount($this->getAccountID());
289
	}
290
291
	public function getZoom() {
292
		return $this->zoom;
293
	}
294
295
	protected function setZoom($zoom) {
296
		// Set the zoom level between [1, 9]
297
		$zoom = max(1, min(9, $zoom));
298
		if ($this->zoom == $zoom) {
299
			return;
300
		}
301
		$this->zoom = $zoom;
302
		$this->hasChanged = true;
303
//		$this->db->query('UPDATE player SET zoom = ' . $zoom . ' WHERE ' . $this->SQL . ' LIMIT 1');
304
	}
305
306
	public function increaseZoom($zoom) {
307
		if ($zoom < 0) {
308
			throw new Exception('Trying to increase negative zoom.');
309
		}
310
		$this->setZoom($this->getZoom() + $zoom);
311
	}
312
313
	public function decreaseZoom($zoom) {
314
		if ($zoom < 0) {
315
			throw new Exception('Trying to decrease negative zoom.');
316
		}
317
		$this->setZoom($this->getZoom() - $zoom);
318
	}
319
320
	public function setSectorID($sectorID) {
321
		$port = SmrPort::getPort($this->getGameID(), $this->getSectorID());
322
		$port->addCachePort($this->getAccountID()); //Add port of sector we were just in, to make sure it is left totally up to date.
323
324
		parent::setSectorID($sectorID);
325
326
		$port = SmrPort::getPort($this->getGameID(), $sectorID);
327
		$port->addCachePort($this->getAccountID()); //Add the port of sector we are now in.
328
	}
329
330
	public function setLastSectorID($lastSectorID) {
331
		if ($this->lastSectorID == $lastSectorID) {
332
			return;
333
		}
334
		$this->lastSectorID = $lastSectorID;
335
		$this->hasChanged = true;
336
//		$this->db->query('UPDATE player SET last_sector_id = '.$this->lastSectorID.' WHERE '.$this->SQL.' LIMIT 1');
337
	}
338
339
	public function leaveAlliance(AbstractSmrPlayer $kickedBy = null) {
340
		$allianceID = $this->getAllianceID();
341
		$alliance = $this->getAlliance();
342
		if ($kickedBy != null) {
343
			$kickedBy->sendMessage($this->getAccountID(), MSG_PLAYER, 'You were kicked out of the alliance!', false);
0 ignored issues
show
Bug introduced by
The method sendMessage() 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

343
			$kickedBy->/** @scrutinizer ignore-call */ 
344
              sendMessage($this->getAccountID(), MSG_PLAYER, 'You were kicked out of the alliance!', false);
Loading history...
344
			$this->actionTaken('PlayerKicked', array('Alliance' => $alliance, 'Player' => $kickedBy));
345
			$kickedBy->actionTaken('KickPlayer', array('Alliance' => $alliance, 'Player' => $this));
346
		} elseif ($this->isAllianceLeader()) {
347
			$this->actionTaken('DisbandAlliance', array('Alliance' => $alliance));
348
		} else {
349
			$this->actionTaken('LeaveAlliance', array('Alliance' => $alliance));
350
			if ($alliance->getLeaderID() != 0 && $alliance->getLeaderID() != ACCOUNT_ID_NHL) {
351
				$this->sendMessage($alliance->getLeaderID(), MSG_PLAYER, 'I left your alliance!', false);
352
			}
353
		}
354
355
		$this->setAllianceID(0);
356
		$this->db->query('DELETE FROM player_has_alliance_role WHERE ' . $this->SQL);
357
358
		if (!$this->isAllianceLeader() && $allianceID != NHA_ID) { // Don't have a delay for switching alliance after leaving NHA, or for disbanding an alliance.
359
			$this->setAllianceJoinable(TIME + self::TIME_FOR_ALLIANCE_SWITCH);
360
			$alliance->getLeader()->setAllianceJoinable(TIME + self::TIME_FOR_ALLIANCE_SWITCH); //We set the joinable time for leader here, that way a single player alliance won't cause a player to wait before switching.
361
		}
362
	}
363
364
	/**
365
	 * Join an alliance (used for both Leader and New Member roles)
366
	 */
367
	public function joinAlliance($allianceID) {
368
		$this->setAllianceID($allianceID);
369
		$alliance = $this->getAlliance();
370
371
		if (!$this->isAllianceLeader()) {
372
			// Do not throw an exception if the NHL account doesn't exist.
373
			try {
374
				$this->sendMessage($alliance->getLeaderID(), MSG_PLAYER, 'I joined your alliance!', false);
375
			} catch (AccountNotFoundException $e) {
376
				if ($alliance->getLeaderID() != ACCOUNT_ID_NHL) {
377
					throw $e;
378
				}
379
			}
380
381
			$roleID = ALLIANCE_ROLE_NEW_MEMBER;
382
		} else {
383
			$roleID = ALLIANCE_ROLE_LEADER;
384
		}
385
		$this->db->query('INSERT INTO player_has_alliance_role (game_id, account_id, role_id, alliance_id) VALUES (' . $this->db->escapeNumber($this->getGameID()) . ', ' . $this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber($roleID) . ',' . $this->db->escapeNumber($this->getAllianceID()) . ')');
386
387
		$this->actionTaken('JoinAlliance', array('Alliance' => $alliance));
388
	}
389
390
	public function getAllianceJoinable() {
391
		return $this->allianceJoinable;
392
	}
393
394
	private function setAllianceJoinable($time) {
395
		if ($this->allianceJoinable == $time) {
396
			return;
397
		}
398
		$this->allianceJoinable = $time;
399
		$this->hasChanged = true;
400
	}
401
402
	/**
403
	 * Invites player with $accountID to this player's alliance.
404
	 */
405
	public function sendAllianceInvitation(int $accountID, string $message, int $expires) : void {
406
		if (!$this->hasAlliance()) {
407
			throw new Exception('Must be in an alliance to send alliance invitations');
408
		}
409
		// Send message to invited player
410
		$messageID = $this->sendMessage($accountID, MSG_PLAYER, $message, false, true, $expires, true);
411
		SmrInvitation::send($this->getAllianceID(), $this->getGameID(), $accountID, $this->getAccountID(), $messageID, $expires);
412
	}
413
414
	public function getAttackColour() {
415
		return $this->attackColour;
416
	}
417
418
	public function setAttackColour($colour) {
419
		if ($this->attackColour == $colour) {
420
			return;
421
		}
422
		$this->attackColour = $colour;
423
		$this->hasChanged = true;
424
//		$this->db->query('UPDATE player SET attack_warning = ' . $this->db->escapeString($this->attackColour) . ' WHERE ' . $this->SQL . ' LIMIT 1');
425
	}
426
427
	public function getBank() {
428
		return $this->bank;
429
	}
430
431
	public function increaseBank($credits) {
432
		if ($credits < 0) {
433
			throw new Exception('Trying to increase negative credits.');
434
		}
435
		if ($credits == 0) {
436
			return;
437
		}
438
		$credits += $this->bank;
439
		$this->setBank($credits);
440
	}
441
	public function decreaseBank($credits) {
442
		if ($credits < 0) {
443
			throw new Exception('Trying to decrease negative credits.');
444
		}
445
		if ($credits == 0) {
446
			return;
447
		}
448
		$credits = $this->bank - $credits;
449
		$this->setBank($credits);
450
	}
451
	public function setBank($credits) {
452
		if ($this->bank == $credits) {
453
			return;
454
		}
455
		if ($credits < 0) {
456
			throw new Exception('Trying to set negative credits.');
457
		}
458
		if ($credits > MAX_MONEY) {
459
			throw new Exception('Trying to set more than max credits.');
460
		}
461
		$this->bank = $credits;
462
		$this->hasChanged = true;
463
//		$this->db->query('UPDATE player SET bank = '.$this->bank.' WHERE '.$this->SQL.' LIMIT 1');
464
	}
465
466
	public function getLastNewsUpdate() {
467
		return $this->lastNewsUpdate;
468
	}
469
470
	private function setLastNewsUpdate($time) {
471
		if ($this->lastNewsUpdate == $time) {
472
			return;
473
		}
474
		$this->lastNewsUpdate = $time;
475
		$this->hasChanged = true;
476
//		$this->db->query('UPDATE player SET last_news_update = ' . $time . ' WHERE ' . $this->SQL . ' LIMIT 1');
477
	}
478
479
	public function updateLastNewsUpdate() {
480
		$this->setLastNewsUpdate(TIME);
481
	}
482
483
//	function getPastKnowledge() {
484
//		return $this->pastKnowledge;
485
//	}
486
487
	/**
488
	 * Calculate the time in seconds between the given time and when the
489
	 * player will be at max turns.
490
	 */
491
	public function getTimeUntilMaxTurns($time, $forceUpdate = false) {
492
		$timeDiff = $time - $this->getLastTurnUpdate();
493
		$turnsDiff = $this->getMaxTurns() - $this->getTurns();
494
		$ship = $this->getShip($forceUpdate);
495
		$maxTurnsTime = ICeil(($turnsDiff * 3600 / $ship->getRealSpeed())) - $timeDiff;
496
		// If already at max turns, return 0
497
		return max(0, $maxTurnsTime);
498
	}
499
500
	/**
501
	 * Grant the player their starting turns.
502
	 */
503
	public function giveStartingTurns() {
504
		$startTurns = IFloor($this->getShip()->getRealSpeed() * $this->getGame()->getStartTurnHours());
505
		$this->giveTurns($startTurns);
506
		$this->setLastTurnUpdate($this->getGame()->getStartTime());
507
	}
508
509
	// Turns only update when player is active.
510
	// Calculate turns gained between given time and the last turn update
511
	public function getTurnsGained($time, $forceUpdate = false) : int {
512
		$timeDiff = $time - $this->getLastTurnUpdate();
513
		$ship = $this->getShip($forceUpdate);
514
		$extraTurns = IFloor($timeDiff * $ship->getRealSpeed() / 3600);
515
		return $extraTurns;
516
	}
517
518
	public function updateTurns() {
519
		// is account validated?
520
		if (!$this->getAccount()->isValidated()) {
521
			return;
522
		}
523
524
		// how many turns would he get right now?
525
		$extraTurns = $this->getTurnsGained(TIME);
526
527
		// do we have at least one turn to give?
528
		if ($extraTurns > 0) {
529
			// recalc the time to avoid rounding errors
530
			$newLastTurnUpdate = $this->getLastTurnUpdate() + ICeil($extraTurns * 3600 / $this->getShip()->getRealSpeed());
531
			$this->setLastTurnUpdate($newLastTurnUpdate);
532
			$this->giveTurns($extraTurns);
533
		}
534
	}
535
536
	public function isIgnoreGlobals() {
537
		return $this->ignoreGlobals;
538
	}
539
540
	public function setIgnoreGlobals($bool) {
541
		if ($this->ignoreGlobals == $bool) {
542
			return;
543
		}
544
		$this->ignoreGlobals = $bool;
545
		$this->hasChanged = true;
546
//		$this->db->query('UPDATE player SET ignore_globals = '.$this->db->escapeBoolean($bool).' WHERE '.$this->SQL.' LIMIT 1');
547
	}
548
549
550
	public function getLastPort() {
551
		return $this->lastPort;
552
	}
553
554
	public function setLastPort($lastPort) {
555
		if ($this->lastPort == $lastPort) {
556
			return;
557
		}
558
		$this->lastPort = $lastPort;
559
		$this->hasChanged = true;
560
//		$this->db->query('UPDATE player SET last_port = ' . $this->lastPort . ' WHERE ' . $this->SQL . ' LIMIT 1');
561
	}
562
563
	public function isDisplayMissions() {
564
		return $this->displayMissions;
565
	}
566
567
	public function setDisplayMissions($bool) {
568
		if ($this->displayMissions == $bool) {
569
			return;
570
		}
571
		$this->displayMissions = $bool;
572
		$this->hasChanged = true;
573
	}
574
575
	public function isDisplayWeapons() {
576
		return $this->displayWeapons;
577
	}
578
579
	/**
580
	 * Should weapons be displayed in the right panel?
581
	 * This updates the player database directly because it is used with AJAX,
582
	 * which does not acquire a sector lock.
583
	 */
584
	public function setDisplayWeapons($bool) {
585
		if ($this->displayWeapons == $bool) {
586
			return;
587
		}
588
		$this->displayWeapons = $bool;
589
		$this->db->query('UPDATE player SET display_weapons=' . $this->db->escapeBoolean($this->displayWeapons) . ' WHERE ' . $this->SQL);
590
	}
591
592
	public function isForceDropMessages() {
593
		return $this->forceDropMessages;
594
	}
595
596
	public function setForceDropMessages($bool) {
597
		if ($this->forceDropMessages == $bool) {
598
			return;
599
		}
600
		$this->forceDropMessages = $bool;
0 ignored issues
show
Bug Best Practice introduced by
The property forceDropMessages does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
601
		$this->hasChanged = true;
602
	}
603
604
	public function getScoutMessageGroupLimit() {
605
		if ($this->groupScoutMessages == 'ALWAYS') {
606
			return 0;
607
		} elseif ($this->groupScoutMessages == 'AUTO') {
608
			return MESSAGES_PER_PAGE;
609
		} elseif ($this->groupScoutMessages == 'NEVER') {
610
			return PHP_INT_MAX;
611
		}
612
	}
613
614
	public function getGroupScoutMessages() {
615
		return $this->groupScoutMessages;
616
	}
617
618
	public function setGroupScoutMessages($setting) {
619
		if ($this->groupScoutMessages == $setting) {
620
			return;
621
		}
622
		$this->groupScoutMessages = $setting;
0 ignored issues
show
Bug Best Practice introduced by
The property groupScoutMessages does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
623
		$this->hasChanged = true;
624
	}
625
626
	public function getLastTurnUpdate() {
627
		return $this->lastTurnUpdate;
628
	}
629
630
	public function setLastTurnUpdate($time) {
631
		if ($this->lastTurnUpdate == $time) {
632
			return;
633
		}
634
		$this->lastTurnUpdate = $time;
635
		$this->hasChanged = true;
636
//		$sql = $this->db->query('UPDATE player SET last_turn_update = ' . $this->lastTurnUpdate . ' WHERE '. $this->SQL . ' LIMIT 1');
637
	}
638
639
	protected function getPureRelationsData() {
640
		if (!isset($this->pureRelations)) {
641
			//get relations
642
			$RACES = Globals::getRaces();
643
			$this->pureRelations = array();
644
			foreach ($RACES as $raceID => $raceName) {
645
				$this->pureRelations[$raceID] = 0;
646
			}
647
			$this->db->query('SELECT race_id,relation FROM player_has_relation WHERE ' . $this->SQL . ' LIMIT ' . count($RACES));
648
			while ($this->db->nextRecord()) {
649
				$this->pureRelations[$this->db->getInt('race_id')] = $this->db->getInt('relation');
650
			}
651
		}
652
	}
653
654
	/**
655
	 * Increases personal relations from trading $numGoods units with the race
656
	 * of the port given by $raceID.
657
	 */
658
	public function increaseRelationsByTrade($numGoods, $raceID) {
659
		$relations = ICeil(min($numGoods, 300) / 30);
660
		//Cap relations to a max of 1 after 500 have been reached
661
		if ($this->getPureRelation($raceID) + $relations >= 500) {
662
			$relations = max(1, min($relations, 500 - $this->getPureRelation($raceID)));
663
		}
664
		$this->increaseRelations($relations, $raceID);
665
	}
666
667
	public function decreaseRelationsByTrade($numGoods, $raceID) {
668
		$relations = ICeil(min($numGoods, 300) / 30);
669
		$this->decreaseRelations($relations, $raceID);
670
	}
671
672
	public function increaseRelations($relations, $raceID) {
673
		if ($relations < 0) {
674
			throw new Exception('Trying to increase negative relations.');
675
		}
676
		if ($relations == 0) {
677
			return;
678
		}
679
		$relations += $this->getPureRelation($raceID);
680
		$this->setRelations($relations, $raceID);
681
	}
682
	public function decreaseRelations($relations, $raceID) {
683
		if ($relations < 0) {
684
			throw new Exception('Trying to decrease negative relations.');
685
		}
686
		if ($relations == 0) {
687
			return;
688
		}
689
		$relations = $this->getPureRelation($raceID) - $relations;
690
		$this->setRelations($relations, $raceID);
691
	}
692
	public function setRelations($relations, $raceID) {
693
		$this->getRelations();
694
		if ($this->pureRelations[$raceID] == $relations) {
695
			return;
696
		}
697
		if ($relations < MIN_RELATIONS) {
698
			$relations = MIN_RELATIONS;
699
		}
700
		$relationsDiff = IRound($relations - $this->pureRelations[$raceID]);
701
		$this->pureRelations[$raceID] = $relations;
702
		$this->relations[$raceID] += $relationsDiff;
703
		$this->db->query('REPLACE INTO player_has_relation (account_id,game_id,race_id,relation) values (' . $this->db->escapeNumber($this->getAccountID()) . ',' . $this->db->escapeNumber($this->getGameID()) . ',' . $this->db->escapeNumber($raceID) . ',' . $this->db->escapeNumber($this->pureRelations[$raceID]) . ')');
704
	}
705
706
	/**
707
	 * Use this method when the player is changing their own name.
708
	 * This will flag the player as having used their free name change.
709
	 */
710
	public function setPlayerNameByPlayer($playerName) {
711
		$this->playerName = $playerName;
712
		$this->setNameChanged(true);
713
		$this->hasChanged = true;
714
	}
715
716
	public function isNameChanged() {
717
		return $this->nameChanged;
718
	}
719
720
	public function setNameChanged($bool) {
721
		$this->nameChanged = $bool;
722
		$this->hasChanged = true;
723
	}
724
725
	public function hasCustomShipName() {
726
		return $this->getCustomShipName() !== false;
727
	}
728
729
	public function getCustomShipName() {
730
		if (!isset($this->customShipName)) {
731
			$this->db->query('SELECT * FROM ship_has_name WHERE ' . $this->SQL . ' LIMIT 1');
732
			if ($this->db->nextRecord()) {
733
				$this->customShipName = $this->db->getField('ship_name');
734
			} else {
735
				$this->customShipName = false;
736
			}
737
		}
738
		return $this->customShipName;
739
	}
740
741
	public function setCustomShipName(string $name) {
742
		$this->db->query('REPLACE INTO ship_has_name (game_id, account_id, ship_name)
743
			VALUES (' . $this->db->escapeNumber($this->getGameID()) . ', ' . $this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeString($name) . ')');
744
	}
745
746
	public function getKnowledge($knowledgeType = false) {
747
		if (!isset($this->knowledge)) {
748
			//get players faction knowledge
749
			$this->db->query('SELECT * FROM player_knows_faction WHERE ' . $this->SQL . ' LIMIT 1');
750
			if ($this->db->nextRecord()) {
751
				$this->knowledge['Erebus'] = $this->db->getInt('erebus');
0 ignored issues
show
Bug Best Practice introduced by
The property knowledge does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
752
				$this->knowledge['Aether'] = $this->db->getInt('aether');
753
				$this->knowledge['Tartarus'] = $this->db->getInt('tartarus');
754
				$this->knowledge['Nyx'] = $this->db->getInt('nyx');
755
				$this->knowledge['Federation'] = 0;
756
				$this->knowledge['Underground'] = 0;
757
			} else {
758
				$this->knowledge['Erebus'] = 0;
759
				$this->knowledge['Aether'] = 0;
760
				$this->knowledge['Tartarus'] = 0;
761
				$this->knowledge['Nyx'] = 0;
762
				$this->knowledge['Federation'] = 0;
763
				$this->knowledge['Underground'] = 0;
764
			}
765
		}
766
		if ($knowledgeType === false) {
767
			return $this->knowledge;
768
		}
769
		if (isset($this->knowledge[$knowledgeType])) {
770
			return $this->knowledge[$knowledgeType];
771
		}
772
		return false;
773
	}
774
775
	public function killPlayer($sectorID) {
776
		$sector = SmrSector::getSector($this->getGameID(), $sectorID);
777
		//msg taken care of in trader_att_proc.php
778
		// forget plotted course
779
		$this->deletePlottedCourse();
780
781
		$sector->diedHere($this);
782
783
		// if we are in an alliance we increase their deaths
784
		if ($this->hasAlliance()) {
785
			$this->db->query('UPDATE alliance SET alliance_deaths = alliance_deaths + 1
786
							WHERE game_id = ' . $this->db->escapeNumber($this->getGameID()) . ' AND alliance_id = ' . $this->db->escapeNumber($this->getAllianceID()) . ' LIMIT 1');
787
		}
788
789
		// record death stat
790
		$this->increaseHOF(1, array('Dying', 'Deaths'), HOF_PUBLIC);
791
		//record cost of ship lost
792
		$this->increaseHOF($this->getShip()->getCost(), array('Dying', 'Money', 'Cost Of Ships Lost'), HOF_PUBLIC);
793
		// reset turns since last death
794
		$this->setHOF(0, array('Movement', 'Turns Used', 'Since Last Death'), HOF_ALLIANCE);
795
796
		// 1/4 of ship value -> insurance
797
		$newCredits = IRound($this->getShip()->getCost() / 4);
798
		$old_speed = $this->getShip()->getSpeed();
799
800
		if ($newCredits < 100000) {
801
			$newCredits = 100000;
802
		}
803
		$this->setCredits($newCredits);
804
805
		$this->setSectorID($this::getHome($this->getGameID(), $this->getRaceID()));
806
		$this->increaseDeaths(1);
807
		$this->setLandedOnPlanet(false);
808
		$this->setDead(true);
809
		$this->setNewbieWarning(true);
810
		$this->getShip()->getPod($this->hasNewbieStatus());
811
812
		// Update turns due to ship change
813
		$new_speed = $this->getShip()->getSpeed();
814
		$this->setTurns(IRound($this->turns / $old_speed * $new_speed));
815
		$this->setNewbieTurns(100);
816
	}
817
818
	static public function getHome($gameID, $raceID) {
819
		// get his home sector
820
		$hq_id = GOVERNMENT + $raceID;
821
		$raceHqSectors = SmrSector::getLocationSectors($gameID, $hq_id);
822
		if (!empty($raceHqSectors)) {
823
			// If race has multiple HQ's for some reason, use the first one
824
			return key($raceHqSectors);
825
		} else {
826
			return 1;
827
		}
828
	}
829
830
	public function incrementAllianceVsKills($otherID) {
831
		$values = [$this->getGameID(), $this->getAllianceID(), $otherID, 1];
832
		$this->db->query('INSERT INTO alliance_vs_alliance (game_id, alliance_id_1, alliance_id_2, kills) VALUES (' . $this->db->escapeArray($values) . ') ON DUPLICATE KEY UPDATE kills = kills + 1');
833
	}
834
835
	public function incrementAllianceVsDeaths($otherID) {
836
		$values = [$this->getGameID(), $otherID, $this->getAllianceID(), 1];
837
		$this->db->query('INSERT INTO alliance_vs_alliance (game_id, alliance_id_1, alliance_id_2, kills) VALUES (' . $this->db->escapeArray($values) . ') ON DUPLICATE KEY UPDATE kills = kills + 1');
838
	}
839
840
	public function &killPlayerByPlayer(AbstractSmrPlayer $killer) {
841
		$return = array();
842
		$msg = $this->getBBLink();
843
844
		if ($this->hasCustomShipName()) {
845
			$named_ship = strip_tags($this->getCustomShipName(), '<font><span><img>');
846
			$msg .= ' flying <span class="yellow">' . $named_ship . '</span>';
847
		}
848
		$msg .= ' was destroyed by ' . $killer->getBBLink();
849
		if ($killer->hasCustomShipName()) {
0 ignored issues
show
Bug introduced by
The method hasCustomShipName() 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

849
		if ($killer->/** @scrutinizer ignore-call */ hasCustomShipName()) {
Loading history...
850
			$named_ship = strip_tags($killer->getCustomShipName(), '<font><span><img>');
0 ignored issues
show
Bug introduced by
The method getCustomShipName() 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

850
			$named_ship = strip_tags($killer->/** @scrutinizer ignore-call */ getCustomShipName(), '<font><span><img>');
Loading history...
851
			$msg .= ' flying <span class="yellow">' . $named_ship . '</span>';
852
		}
853
		$msg .= ' in Sector&nbsp;' . Globals::getSectorBBLink($this->getSectorID());
854
		$this->getSector()->increaseBattles(1);
855
		$this->db->query('INSERT INTO news (game_id,time,news_message,type,killer_id,killer_alliance,dead_id,dead_alliance) VALUES (' . $this->db->escapeNumber($this->getGameID()) . ',' . $this->db->escapeNumber(TIME) . ',' . $this->db->escapeString($msg, true) . ',\'regular\',' . $this->db->escapeNumber($killer->getAccountID()) . ',' . $this->db->escapeNumber($killer->getAllianceID()) . ',' . $this->db->escapeNumber($this->getAccountID()) . ',' . $this->db->escapeNumber($this->getAllianceID()) . ')');
856
857
		self::sendMessageFromFedClerk($this->getGameID(), $this->getAccountID(), 'You were <span class="red">DESTROYED</span> by ' . $killer->getBBLink() . ' in sector ' . Globals::getSectorBBLink($this->getSectorID()));
858
		self::sendMessageFromFedClerk($this->getGameID(), $killer->getAccountID(), 'You <span class="red">DESTROYED</span>&nbsp;' . $this->getBBLink() . ' in sector ' . Globals::getSectorBBLink($this->getSectorID()));
859
860
		// Dead player loses between 5% and 25% experience
861
		$expLossPercentage = 0.15 + 0.10 * ($this->getLevelID() - $killer->getLevelID()) / $this->getMaxLevel();
862
		$return['DeadExp'] = max(0, IFloor($this->getExperience() * $expLossPercentage));
863
		$this->decreaseExperience($return['DeadExp']);
864
865
		// Killer gains 50% of the lost exp
866
		$return['KillerExp'] = max(0, ICeil(0.5 * $return['DeadExp']));
867
		$killer->increaseExperience($return['KillerExp']);
868
869
		$return['KillerCredits'] = $this->getCredits();
870
		$killer->increaseCredits($return['KillerCredits']);
871
872
		// The killer may change alignment
873
		$relations = Globals::getRaceRelations($this->getGameID(), $this->getRaceID());
874
		$relation = $relations[$killer->getRaceID()];
875
876
		$alignChangePerRelation = 0.1;
877
		if ($relation >= RELATIONS_PEACE || $relation <= RELATIONS_WAR) {
878
			$alignChangePerRelation = 0.04;
879
		}
880
881
		$return['KillerAlign'] = -$relation * $alignChangePerRelation; //Lose relations when killing a peaceful race
882
		if ($return['KillerAlign'] > 0) {
883
			$killer->increaseAlignment($return['KillerAlign']);
884
		} else {
885
			$killer->decreaseAlignment(-$return['KillerAlign']);
886
		}
887
		// War setting gives them military pay
888
		if ($relation <= RELATIONS_WAR) {
889
			$killer->increaseMilitaryPayment(-IFloor($relation * 100 * pow($return['KillerExp'] / 2, 0.25)));
890
		}
891
892
		//check for federal bounty being offered for current port raiders;
893
		$this->db->query('DELETE FROM player_attacks_port WHERE time < ' . $this->db->escapeNumber(TIME - self::TIME_FOR_FEDERAL_BOUNTY_ON_PR));
894
		$query = 'SELECT 1
895
					FROM player_attacks_port
896
					JOIN port USING(game_id, sector_id)
897
					JOIN player USING(game_id, account_id)
898
					WHERE armour > 0 AND ' . $this->SQL . ' LIMIT 1';
899
		$this->db->query($query);
900
		if ($this->db->nextRecord()) {
901
			$bounty = IFloor(DEFEND_PORT_BOUNTY_PER_LEVEL * $this->getLevelID());
902
			$this->increaseCurrentBountyAmount('HQ', $bounty);
903
		}
904
905
		// Killer get marked as claimer of podded player's bounties even if they don't exist
906
		$this->setBountiesClaimable($killer);
907
908
		// If the alignment difference is greater than 200 then a bounty may be set
909
		$alignmentDiff = abs($this->getAlignment() - $killer->getAlignment());
910
		$return['BountyGained'] = array(
911
			'Type' => 'None',
912
			'Amount' => 0
913
		);
914
		if ($alignmentDiff >= 200) {
915
			// If the podded players alignment makes them deputy or member then set bounty
916
			if ($this->getAlignment() >= 100) {
917
				$return['BountyGained']['Type'] = 'HQ';
918
			} elseif ($this->getAlignment() <= 100) {
919
				$return['BountyGained']['Type'] = 'UG';
920
			}
921
922
			if ($return['BountyGained']['Type'] != 'None') {
923
				$return['BountyGained']['Amount'] = IFloor(pow($alignmentDiff, 2.56));
924
				$killer->increaseCurrentBountyAmount($return['BountyGained']['Type'], $return['BountyGained']['Amount']);
925
			}
926
		}
927
928
		if ($this->isNPC()) {
929
			$killer->increaseHOF($return['KillerExp'], array('Killing', 'NPC', 'Experience', 'Gained'), HOF_PUBLIC);
930
			$killer->increaseHOF($this->getExperience(), array('Killing', 'NPC', 'Experience', 'Of Traders Killed'), HOF_PUBLIC);
931
932
			$killer->increaseHOF($return['DeadExp'], array('Killing', 'Experience', 'Lost By NPCs Killed'), HOF_PUBLIC);
933
934
			$killer->increaseHOF($return['KillerCredits'], array('Killing', 'NPC', 'Money', 'Lost By Traders Killed'), HOF_PUBLIC);
935
			$killer->increaseHOF($return['KillerCredits'], array('Killing', 'NPC', 'Money', 'Gain'), HOF_PUBLIC);
936
			$killer->increaseHOF($this->getShip()->getCost(), array('Killing', 'NPC', 'Money', 'Cost Of Ships Killed'), HOF_PUBLIC);
937
938
			if ($return['KillerAlign'] > 0) {
939
				$killer->increaseHOF($return['KillerAlign'], array('Killing', 'NPC', 'Alignment', 'Gain'), HOF_PUBLIC);
940
			} else {
941
				$killer->increaseHOF(-$return['KillerAlign'], array('Killing', 'NPC', 'Alignment', 'Loss'), HOF_PUBLIC);
942
			}
943
944
			$killer->increaseHOF($return['BountyGained']['Amount'], array('Killing', 'NPC', 'Money', 'Bounty Gained'), HOF_PUBLIC);
945
946
			$killer->increaseHOF(1, array('Killing', 'NPC Kills'), HOF_PUBLIC);
947
		} else {
948
			$killer->increaseHOF($return['KillerExp'], array('Killing', 'Experience', 'Gained'), HOF_PUBLIC);
949
			$killer->increaseHOF($this->getExperience(), array('Killing', 'Experience', 'Of Traders Killed'), HOF_PUBLIC);
950
951
			$killer->increaseHOF($return['DeadExp'], array('Killing', 'Experience', 'Lost By Traders Killed'), HOF_PUBLIC);
952
953
			$killer->increaseHOF($return['KillerCredits'], array('Killing', 'Money', 'Lost By Traders Killed'), HOF_PUBLIC);
954
			$killer->increaseHOF($return['KillerCredits'], array('Killing', 'Money', 'Gain'), HOF_PUBLIC);
955
			$killer->increaseHOF($this->getShip()->getCost(), array('Killing', 'Money', 'Cost Of Ships Killed'), HOF_PUBLIC);
956
957
			if ($return['KillerAlign'] > 0) {
958
				$killer->increaseHOF($return['KillerAlign'], array('Killing', 'Alignment', 'Gain'), HOF_PUBLIC);
959
			} else {
960
				$killer->increaseHOF(-$return['KillerAlign'], array('Killing', 'Alignment', 'Loss'), HOF_PUBLIC);
961
			}
962
963
			$killer->increaseHOF($return['BountyGained']['Amount'], array('Killing', 'Money', 'Bounty Gained'), HOF_PUBLIC);
964
965
			if ($this->getShip()->getAttackRatingWithMaxCDs() <= MAX_ATTACK_RATING_NEWBIE && $this->hasNewbieStatus() && !$killer->hasNewbieStatus()) { //Newbie kill
966
				$killer->increaseHOF(1, array('Killing', 'Newbie Kills'), HOF_PUBLIC);
967
			} else {
968
				$killer->increaseKills(1);
969
				$killer->increaseHOF(1, array('Killing', 'Kills'), HOF_PUBLIC);
970
971
				if ($killer->hasAlliance()) {
972
					$this->db->query('UPDATE alliance SET alliance_kills=alliance_kills+1 WHERE alliance_id=' . $this->db->escapeNumber($killer->getAllianceID()) . ' AND game_id=' . $this->db->escapeNumber($killer->getGameID()) . ' LIMIT 1');
973
				}
974
975
				// alliance vs. alliance stats
976
				$this->incrementAllianceVsDeaths($killer->getAllianceID());
977
			}
978
		}
979
980
		$this->increaseHOF($return['BountyGained']['Amount'], array('Dying', 'Players', 'Money', 'Bounty Gained By Killer'), HOF_PUBLIC);
981
		$this->increaseHOF($return['KillerExp'], array('Dying', 'Players', 'Experience', 'Gained By Killer'), HOF_PUBLIC);
982
		$this->increaseHOF($return['DeadExp'], array('Dying', 'Experience', 'Lost'), HOF_PUBLIC);
983
		$this->increaseHOF($return['DeadExp'], array('Dying', 'Players', 'Experience', 'Lost'), HOF_PUBLIC);
984
		$this->increaseHOF($return['KillerCredits'], array('Dying', 'Players', 'Money Lost'), HOF_PUBLIC);
985
		$this->increaseHOF($this->getShip()->getCost(), array('Dying', 'Players', 'Money', 'Cost Of Ships Lost'), HOF_PUBLIC);
986
		$this->increaseHOF(1, array('Dying', 'Players', 'Deaths'), HOF_PUBLIC);
987
988
		$this->killPlayer($this->getSectorID());
989
		return $return;
990
	}
991
992
	public function &killPlayerByForces(SmrForce $forces) {
993
		$return = array();
994
		$owner = $forces->getOwner();
995
		// send a message to the person who died
996
		self::sendMessageFromFedClerk($this->getGameID(), $owner->getAccountID(), 'Your forces <span class="red">DESTROYED </span>' . $this->getBBLink() . ' in sector ' . Globals::getSectorBBLink($forces->getSectorID()));
997
		self::sendMessageFromFedClerk($this->getGameID(), $this->getAccountID(), 'You were <span class="red">DESTROYED</span> by ' . $owner->getBBLink() . '\'s forces in sector ' . Globals::getSectorBBLink($this->getSectorID()));
998
999
		$news_message = $this->getBBLink();
1000
		if ($this->hasCustomShipName()) {
1001
			$named_ship = strip_tags($this->getCustomShipName(), '<font><span><img>');
1002
			$news_message .= ' flying <span class="yellow">' . $named_ship . '</span>';
1003
		}
1004
		$news_message .= ' was destroyed by ' . $owner->getBBLink() . '\'s forces in sector ' . Globals::getSectorBBLink($forces->getSectorID());
1005
		// insert the news entry
1006
		$this->db->query('INSERT INTO news (game_id, time, news_message,killer_id,killer_alliance,dead_id,dead_alliance)
1007
						VALUES(' . $this->db->escapeNumber($this->getGameID()) . ', ' . $this->db->escapeNumber(TIME) . ', ' . $this->db->escapeString($news_message) . ',' . $this->db->escapeNumber($owner->getAccountID()) . ',' . $this->db->escapeNumber($owner->getAllianceID()) . ',' . $this->db->escapeNumber($this->getAccountID()) . ',' . $this->db->escapeNumber($this->getAllianceID()) . ')');
1008
1009
		// Player loses 15% experience
1010
		$expLossPercentage = .15;
1011
		$return['DeadExp'] = IFloor($this->getExperience() * $expLossPercentage);
1012
		$this->decreaseExperience($return['DeadExp']);
1013
1014
		$return['LostCredits'] = $this->getCredits();
1015
1016
		// alliance vs. alliance stats
1017
		$this->incrementAllianceVsDeaths(ALLIANCE_VS_FORCES);
1018
		$owner->incrementAllianceVsKills(ALLIANCE_VS_FORCES);
1019
1020
		$this->increaseHOF($return['DeadExp'], array('Dying', 'Experience', 'Lost'), HOF_PUBLIC);
1021
		$this->increaseHOF($return['DeadExp'], array('Dying', 'Forces', 'Experience Lost'), HOF_PUBLIC);
1022
		$this->increaseHOF($return['LostCredits'], array('Dying', 'Forces', 'Money Lost'), HOF_PUBLIC);
1023
		$this->increaseHOF($this->getShip()->getCost(), array('Dying', 'Forces', 'Cost Of Ships Lost'), HOF_PUBLIC);
1024
		$this->increaseHOF(1, array('Dying', 'Forces', 'Deaths'), HOF_PUBLIC);
1025
1026
		$this->killPlayer($forces->getSectorID());
1027
		return $return;
1028
	}
1029
1030
	public function &killPlayerByPort(SmrPort $port) {
1031
		$return = array();
1032
		// send a message to the person who died
1033
		self::sendMessageFromFedClerk($this->getGameID(), $this->getAccountID(), 'You were <span class="red">DESTROYED</span> by the defenses of ' . $port->getDisplayName());
1034
1035
		$news_message = $this->getBBLink();
1036
		if ($this->hasCustomShipName()) {
1037
			$named_ship = strip_tags($this->getCustomShipName(), '<font><span><img>');
1038
			$news_message .= ' flying <span class="yellow">' . $named_ship . '</span>';
1039
		}
1040
		$news_message .= ' was destroyed while invading ' . $port->getDisplayName() . '.';
1041
		// insert the news entry
1042
		$this->db->query('INSERT INTO news (game_id, time, news_message,killer_id,dead_id,dead_alliance)
1043
						VALUES(' . $this->db->escapeNumber($this->getGameID()) . ', ' . $this->db->escapeNumber(TIME) . ', ' . $this->db->escapeString($news_message) . ',' . $this->db->escapeNumber(ACCOUNT_ID_PORT) . ',' . $this->db->escapeNumber($this->getAccountID()) . ',' . $this->db->escapeNumber($this->getAllianceID()) . ')');
1044
1045
		// Player loses between 15% and 20% experience
1046
		$expLossPercentage = .20 - .05 * ($port->getLevel() - 1) / ($port->getMaxLevel() - 1);
1047
		$return['DeadExp'] = max(0, IFloor($this->getExperience() * $expLossPercentage));
1048
		$this->decreaseExperience($return['DeadExp']);
1049
1050
		$return['LostCredits'] = $this->getCredits();
1051
1052
		// alliance vs. alliance stats
1053
		$this->incrementAllianceVsDeaths(ALLIANCE_VS_PORTS);
1054
1055
		$this->increaseHOF($return['DeadExp'], array('Dying', 'Experience', 'Lost'), HOF_PUBLIC);
1056
		$this->increaseHOF($return['DeadExp'], array('Dying', 'Ports', 'Experience Lost'), HOF_PUBLIC);
1057
		$this->increaseHOF($return['LostCredits'], array('Dying', 'Ports', 'Money Lost'), HOF_PUBLIC);
1058
		$this->increaseHOF($this->getShip()->getCost(), array('Dying', 'Ports', 'Cost Of Ships Lost'), HOF_PUBLIC);
1059
		$this->increaseHOF(1, array('Dying', 'Ports', 'Deaths'), HOF_PUBLIC);
1060
1061
		$this->killPlayer($port->getSectorID());
1062
		return $return;
1063
	}
1064
1065
	public function &killPlayerByPlanet(SmrPlanet $planet) {
1066
		$return = array();
1067
		// send a message to the person who died
1068
		$planetOwner = $planet->getOwner();
1069
		self::sendMessageFromFedClerk($this->getGameID(), $planetOwner->getAccountID(), 'Your planet <span class="red">DESTROYED</span>&nbsp;' . $this->getBBLink() . ' in sector ' . Globals::getSectorBBLink($planet->getSectorID()));
1070
		self::sendMessageFromFedClerk($this->getGameID(), $this->getAccountID(), 'You were <span class="red">DESTROYED</span> by the planetary defenses of ' . $planet->getCombatName());
1071
1072
		$news_message = $this->getBBLink();
1073
		if ($this->hasCustomShipName()) {
1074
			$named_ship = strip_tags($this->getCustomShipName(), '<font><span><img>');
1075
			$news_message .= ' flying <span class="yellow">' . $named_ship . '</span>';
1076
		}
1077
		$news_message .= ' was destroyed by ' . $planet->getCombatName() . '\'s planetary defenses in sector ' . Globals::getSectorBBLink($planet->getSectorID()) . '.';
1078
		// insert the news entry
1079
		$this->db->query('INSERT INTO news (game_id, time, news_message,killer_id,killer_alliance,dead_id,dead_alliance)
1080
						VALUES(' . $this->db->escapeNumber($this->getGameID()) . ', ' . $this->db->escapeNumber(TIME) . ', ' . $this->db->escapeString($news_message) . ',' . $this->db->escapeNumber($planetOwner->getAccountID()) . ',' . $this->db->escapeNumber($planetOwner->getAllianceID()) . ',' . $this->db->escapeNumber($this->getAccountID()) . ',' . $this->db->escapeNumber($this->getAllianceID()) . ')');
1081
1082
		// Player loses between 15% and 20% experience
1083
		$expLossPercentage = .20 - .05 * $planet->getLevel() / $planet->getMaxLevel();
1084
		$return['DeadExp'] = max(0, IFloor($this->getExperience() * $expLossPercentage));
1085
		$this->decreaseExperience($return['DeadExp']);
1086
1087
		$return['LostCredits'] = $this->getCredits();
1088
1089
		// alliance vs. alliance stats
1090
		$this->incrementAllianceVsDeaths(ALLIANCE_VS_PLANETS);
1091
		$planetOwner->incrementAllianceVsKills(ALLIANCE_VS_PLANETS);
1092
1093
		$this->increaseHOF($return['DeadExp'], array('Dying', 'Experience', 'Lost'), HOF_PUBLIC);
1094
		$this->increaseHOF($return['DeadExp'], array('Dying', 'Planets', 'Experience Lost'), HOF_PUBLIC);
1095
		$this->increaseHOF($return['LostCredits'], array('Dying', 'Planets', 'Money Lost'), HOF_PUBLIC);
1096
		$this->increaseHOF($this->getShip()->getCost(), array('Dying', 'Planets', 'Cost Of Ships Lost'), HOF_PUBLIC);
1097
		$this->increaseHOF(1, array('Dying', 'Planets', 'Deaths'), HOF_PUBLIC);
1098
1099
		$this->killPlayer($planet->getSectorID());
1100
		return $return;
1101
	}
1102
1103
	public function save() {
1104
		if ($this->hasChanged === true) {
1105
			$this->db->query('UPDATE player SET player_name=' . $this->db->escapeString($this->playerName) .
1106
				', player_id=' . $this->db->escapeNumber($this->playerID) .
1107
				', sector_id=' . $this->db->escapeNumber($this->sectorID) .
1108
				', last_sector_id=' . $this->db->escapeNumber($this->lastSectorID) .
1109
				', turns=' . $this->db->escapeNumber($this->turns) .
1110
				', last_turn_update=' . $this->db->escapeNumber($this->lastTurnUpdate) .
1111
				', newbie_turns=' . $this->db->escapeNumber($this->newbieTurns) .
1112
				', last_news_update=' . $this->db->escapeNumber($this->lastNewsUpdate) .
1113
				', attack_warning=' . $this->db->escapeString($this->attackColour) .
1114
				', dead=' . $this->db->escapeBoolean($this->dead) .
1115
				', newbie_status=' . $this->db->escapeBoolean($this->newbieStatus) .
1116
				', land_on_planet=' . $this->db->escapeBoolean($this->landedOnPlanet) .
1117
				', last_active=' . $this->db->escapeNumber($this->lastActive) .
1118
				', last_cpl_action=' . $this->db->escapeNumber($this->lastCPLAction) .
1119
				', race_id=' . $this->db->escapeNumber($this->raceID) .
1120
				', credits=' . $this->db->escapeNumber($this->credits) .
1121
				', experience=' . $this->db->escapeNumber($this->experience) .
1122
				', alignment=' . $this->db->escapeNumber($this->alignment) .
1123
				', military_payment=' . $this->db->escapeNumber($this->militaryPayment) .
1124
//				', past_knowledge='.$this->db->escapeString($this->pastKnowledge).
1125
				', alliance_id=' . $this->db->escapeNumber($this->allianceID) .
1126
				', alliance_join=' . $this->db->escapeNumber($this->allianceJoinable) .
1127
				', ship_type_id=' . $this->db->escapeNumber($this->shipID) .
1128
				', kills=' . $this->db->escapeNumber($this->kills) .
1129
				', deaths=' . $this->db->escapeNumber($this->deaths) .
1130
				', assists=' . $this->db->escapeNumber($this->assists) .
1131
				', last_port=' . $this->db->escapeNumber($this->lastPort) .
1132
				', bank=' . $this->db->escapeNumber($this->bank) .
1133
				', zoom=' . $this->db->escapeNumber($this->zoom) .
1134
				', display_missions=' . $this->db->escapeBoolean($this->displayMissions) .
1135
				', force_drop_messages=' . $this->db->escapeBoolean($this->forceDropMessages) .
1136
				', group_scout_messages=' . $this->db->escapeString($this->groupScoutMessages) .
1137
				', ignore_globals=' . $this->db->escapeBoolean($this->ignoreGlobals) .
1138
				', newbie_warning = ' . $this->db->escapeBoolean($this->newbieWarning) .
1139
				', name_changed = ' . $this->db->escapeBoolean($this->nameChanged) .
1140
				', combat_drones_kamikaze_on_mines = ' . $this->db->escapeBoolean($this->combatDronesKamikazeOnMines) .
1141
				' WHERE ' . $this->SQL . ' LIMIT 1');
1142
			$this->hasChanged = false;
1143
		}
1144
		foreach ($this->hasBountyChanged as $key => &$bountyChanged) {
1145
			if ($bountyChanged === true) {
1146
				$bountyChanged = false;
1147
				$bounty = $this->getBounty($key);
1148
				if ($bounty['New'] === true) {
1149
					if ($bounty['Amount'] > 0 || $bounty['SmrCredits'] > 0) {
1150
						$this->db->query('INSERT INTO bounty (account_id,game_id,type,amount,smr_credits,claimer_id,time) VALUES (' . $this->db->escapeNumber($this->getAccountID()) . ',' . $this->db->escapeNumber($this->getGameID()) . ',' . $this->db->escapeString($bounty['Type']) . ',' . $this->db->escapeNumber($bounty['Amount']) . ',' . $this->db->escapeNumber($bounty['SmrCredits']) . ',' . $this->db->escapeNumber($bounty['Claimer']) . ',' . $this->db->escapeNumber($bounty['Time']) . ')');
1151
					}
1152
				} else {
1153
					if ($bounty['Amount'] > 0 || $bounty['SmrCredits'] > 0) {
1154
						$this->db->query('UPDATE bounty
1155
							SET amount=' . $this->db->escapeNumber($bounty['Amount']) . ',
1156
							smr_credits=' . $this->db->escapeNumber($bounty['SmrCredits']) . ',
1157
							type=' . $this->db->escapeString($bounty['Type']) . ',
1158
							claimer_id=' . $this->db->escapeNumber($bounty['Claimer']) . ',
1159
							time=' . $this->db->escapeNumber($bounty['Time']) . '
1160
							WHERE bounty_id=' . $this->db->escapeNumber($bounty['ID']) . ' AND ' . $this->SQL . ' LIMIT 1');
1161
					} else {
1162
						$this->db->query('DELETE FROM bounty WHERE bounty_id=' . $this->db->escapeNumber($bounty['ID']) . ' AND ' . $this->SQL . ' LIMIT 1');
1163
					}
1164
				}
1165
			}
1166
		}
1167
		$this->saveHOF();
1168
	}
1169
1170
	public function saveHOF() {
1171
		if ($this->hasHOFChanged !== false) {
1172
			$this->doHOFSave($this->hasHOFChanged);
0 ignored issues
show
Bug introduced by
$this->hasHOFChanged of type true is incompatible with the type array expected by parameter $hasChangedList of SmrPlayer::doHOFSave(). ( Ignorable by Annotation )

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

1172
			$this->doHOFSave(/** @scrutinizer ignore-type */ $this->hasHOFChanged);
Loading history...
1173
		}
1174
		if (!empty(self::$hasHOFVisChanged)) {
1175
			foreach (self::$hasHOFVisChanged as $hofType => $changeType) {
1176
				if ($changeType == self::HOF_NEW) {
1177
					$this->db->query('INSERT INTO hof_visibility (type, visibility) VALUES (' . $this->db->escapeString($hofType) . ',' . $this->db->escapeString(self::$HOFVis[$hofType]) . ')');
1178
				} else {
1179
					$this->db->query('UPDATE hof_visibility SET visibility = ' . $this->db->escapeString(self::$HOFVis[$hofType]) . ' WHERE type = ' . $this->db->escapeString($hofType) . ' LIMIT 1');
1180
				}
1181
				unset(self::$hasHOFVisChanged[$hofType]);
1182
			}
1183
		}
1184
	}
1185
	protected function doHOFSave(array &$hasChangedList, array $typeList = array()) {
1186
		foreach ($hasChangedList as $type => &$hofChanged) {
1187
			$tempTypeList = $typeList;
1188
			$tempTypeList[] = $type;
1189
			if (is_array($hofChanged)) {
1190
				$this->doHOFSave($hofChanged, $tempTypeList);
1191
			} else {
1192
				$amount = $this->getHOF($tempTypeList);
1193
				if ($hofChanged == self::HOF_NEW) {
1194
					if ($amount > 0) {
1195
						$this->db->query('INSERT INTO player_hof (account_id,game_id,type,amount) VALUES (' . $this->db->escapeNumber($this->getAccountID()) . ',' . $this->db->escapeNumber($this->getGameID()) . ',' . $this->db->escapeArray($tempTypeList, false, true, ':', false) . ',' . $this->db->escapeNumber($amount) . ')');
1196
					}
1197
				} elseif ($hofChanged == self::HOF_CHANGED) {
1198
	//				if($amount > 0)
1199
						$this->db->query('UPDATE player_hof
1200
							SET amount=' . $this->db->escapeNumber($amount) . '
1201
							WHERE ' . $this->SQL . ' AND type = ' . $this->db->escapeArray($tempTypeList, false, true, ':', false) . ' LIMIT 1');
1202
	//				else
1203
	//					$this->db->query('DELETE FROM player_hof WHERE account_id=' . $this->getAccountID() . ' AND game_id = ' . $this->getGameID() . ' AND type = ' . $this->db->escapeArray($tempTypeList,false,true,':',false) . ' LIMIT 1');
1204
	//				}
1205
				}
1206
				$hofChanged = false;
1207
			}
1208
		}
1209
	}
1210
1211
	protected function getHOFData() {
1212
		if (!isset($this->HOF)) {
1213
			//Get Player HOF
1214
			$this->db->query('SELECT type,amount FROM player_hof WHERE ' . $this->SQL);
1215
			$this->HOF = array();
1216
			while ($this->db->nextRecord()) {
1217
				$hof =& $this->HOF;
1218
				$typeList = explode(':', $this->db->getField('type'));
1219
				foreach ($typeList as $type) {
1220
					if (!isset($hof[$type])) {
1221
						$hof[$type] = array();
1222
					}
1223
					$hof =& $hof[$type];
1224
				}
1225
				$hof = $this->db->getFloat('amount');
1226
			}
1227
			self::getHOFVis();
1228
		}
1229
	}
1230
1231
	public static function getHOFVis() {
1232
		if (!isset(self::$HOFVis)) {
1233
			//Get Player HOF Vis
1234
			$db = new SmrMySqlDatabase();
1235
			$db->query('SELECT type,visibility FROM hof_visibility');
1236
			self::$HOFVis = array();
1237
			while ($db->nextRecord()) {
1238
				self::$HOFVis[$db->getField('type')] = $db->getField('visibility');
1239
			}
1240
		}
1241
	}
1242
1243
	protected function getBountiesData() {
1244
		if (!isset($this->bounties)) {
1245
			$this->bounties = array();
1246
			$this->db->query('SELECT * FROM bounty WHERE ' . $this->SQL);
1247
			while ($this->db->nextRecord()) {
1248
				$this->bounties[$this->db->getInt('bounty_id')] = array(
1249
							'Amount' => $this->db->getInt('amount'),
1250
							'SmrCredits' => $this->db->getInt('smr_credits'),
1251
							'Type' => $this->db->getField('type'),
1252
							'Claimer' => $this->db->getInt('claimer_id'),
1253
							'Time' => $this->db->getInt('time'),
1254
							'ID' => $this->db->getInt('bounty_id'),
1255
							'New' => false);
1256
			}
1257
		}
1258
	}
1259
1260
	// Get bounties that can be claimed by this player
1261
	// Type must be 'HQ' or 'UG'
1262
	public function getClaimableBounties($type) {
1263
		$bounties = array();
1264
		$this->db->query('SELECT * FROM bounty WHERE claimer_id=' . $this->db->escapeNumber($this->getAccountID()) . ' AND game_id=' . $this->db->escapeNumber($this->getGameID()) . ' AND type=' . $this->db->escapeString($type));
1265
		while ($this->db->nextRecord()) {
1266
			$bounties[] = array(
1267
				'player' => SmrPlayer::getPlayer($this->db->getInt('account_id'), $this->getGameID()),
1268
				'bounty_id' => $this->db->getInt('bounty_id'),
1269
				'credits' => $this->db->getInt('amount'),
1270
				'smr_credits' => $this->db->getInt('smr_credits'),
1271
			);
1272
		}
1273
		return $bounties;
1274
	}
1275
1276
	/**
1277
	 * Has this player been designated as the alliance flagship?
1278
	 */
1279
	public function isFlagship() {
1280
		return $this->hasAlliance() && $this->getAlliance()->getFlagshipID() == $this->getAccountID();
1281
	}
1282
1283
	public function isPresident() {
1284
		return Council::getPresidentID($this->getGameID(), $this->getRaceID()) == $this->getAccountID();
1285
	}
1286
1287
	public function isOnCouncil() {
1288
		return Council::isOnCouncil($this->getGameID(), $this->getRaceID(), $this->getAccountID());
1289
	}
1290
1291
	public function setNewbieWarning($bool) {
1292
		if ($this->newbieWarning == $bool) {
1293
			return;
1294
		}
1295
		$this->newbieWarning = $bool;
1296
		$this->hasChanged = true;
1297
	}
1298
1299
	public function getNewbieWarning() {
1300
		return $this->newbieWarning;
1301
	}
1302
1303
	public function getTickers() {
1304
		if (!isset($this->tickers)) {
1305
			$this->tickers = array();
1306
			//get ticker info
1307
			$this->db->query('SELECT type,time,expires,recent FROM player_has_ticker WHERE ' . $this->SQL . ' AND expires > ' . $this->db->escapeNumber(TIME));
1308
			while ($this->db->nextRecord()) {
1309
				$this->tickers[$this->db->getField('type')] = array('Type' => $this->db->getField('type'),
1310
																				'Time' => $this->db->getInt('time'),
1311
																				'Expires' => $this->db->getInt('expires'),
1312
																				'Recent' => $this->db->getField('recent'));
1313
			}
1314
		}
1315
		return $this->tickers;
1316
	}
1317
1318
	public function hasTickers() {
1319
		return count($this->getTickers()) > 0;
1320
	}
1321
1322
	public function getTicker($tickerType) {
1323
		$tickers = $this->getTickers();
1324
		if (isset($tickers[$tickerType])) {
1325
			return $tickers[$tickerType];
1326
		}
1327
		return false;
1328
	}
1329
1330
	public function hasTicker($tickerType) {
1331
		return $this->getTicker($tickerType) !== false;
1332
	}
1333
1334
	public function getTurnsLevel() {
1335
		if (!$this->hasTurns()) {
1336
			return 'NONE';
1337
		}
1338
		if ($this->getTurns() <= 25) {
1339
			return 'LOW';
1340
		}
1341
		if ($this->getTurns() <= 75) {
1342
			return 'MEDIUM';
1343
		}
1344
		return 'HIGH';
1345
	}
1346
1347
	/**
1348
	 * Returns the CSS class color to use when displaying the player's turns
1349
	 */
1350
	public function getTurnsColor() {
1351
		switch ($this->getTurnsLevel()) {
1352
			case 'NONE':
1353
			case 'LOW':
1354
				return 'red';
1355
			break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
1356
			case 'MEDIUM':
1357
				return 'yellow';
1358
			break;
1359
			default:
1360
				return 'green';
1361
		}
1362
	}
1363
1364
	public function update() {
1365
		$this->save();
1366
	}
1367
1368
	protected static function doMessageSending($senderID, $receiverID, $gameID, $messageTypeID, $message, $expires, $senderDelete = false, $unread = true) {
1369
		$message = trim($message);
1370
		$db = new SmrMySqlDatabase();
1371
		// send him the message
1372
		$db->query('INSERT INTO message
1373
			(account_id,game_id,message_type_id,message_text,
1374
			sender_id,send_time,expire_time,sender_delete) VALUES(' .
1375
			$db->escapeNumber($receiverID) . ',' .
1376
			$db->escapeNumber($gameID) . ',' .
1377
			$db->escapeNumber($messageTypeID) . ',' .
1378
			$db->escapeString($message) . ',' .
1379
			$db->escapeNumber($senderID) . ',' .
1380
			$db->escapeNumber(TIME) . ',' .
1381
			$db->escapeNumber($expires) . ',' .
1382
			$db->escapeBoolean($senderDelete) . ')'
1383
		);
1384
		// Keep track of the message_id so it can be returned
1385
		$insertID = $db->getInsertID();
1386
1387
		if ($unread === true) {
1388
			// give him the message icon
1389
			$db->query('REPLACE INTO player_has_unread_messages (game_id, account_id, message_type_id) VALUES
1390
						(' . $db->escapeNumber($gameID) . ', ' . $db->escapeNumber($receiverID) . ', ' . $db->escapeNumber($messageTypeID) . ')');
1391
		}
1392
1393
		switch ($messageTypeID) {
1394
			case MSG_PLAYER:
1395
				$receiverAccount = SmrAccount::getAccount($receiverID);
1396
				if ($receiverAccount->isValidated() && $receiverAccount->isReceivingMessageNotifications($messageTypeID) && !$receiverAccount->isLoggedIn()) {
1397
					require_once(get_file_loc('message.functions.inc'));
1398
					$sender = getMessagePlayer($senderID, $gameID, $messageTypeID);
1399
					if ($sender instanceof SmrPlayer) {
1400
						$sender = $sender->getDisplayName();
1401
					}
1402
					$mail = setupMailer();
1403
					$mail->Subject = 'Message Notification';
1404
					$mail->setFrom('[email protected]', 'SMR Notifications');
1405
					$bbifiedMessage = 'From: ' . $sender . ' Date: ' . date($receiverAccount->getShortDateFormat() . ' ' . $receiverAccount->getShortTimeFormat(), TIME) . "<br/>\r\n<br/>\r\n" . bbifyMessage($message, true);
1406
					$mail->msgHTML($bbifiedMessage);
1407
					$mail->AltBody = strip_tags($bbifiedMessage);
1408
					$mail->addAddress($receiverAccount->getEmail(), $receiverAccount->getHofName());
1409
					$mail->send();
1410
					$receiverAccount->decreaseMessageNotifications($messageTypeID, 1);
1411
				}
1412
			break;
1413
		}
1414
1415
		return $insertID;
1416
	}
1417
1418
	public function sendMessageToBox($boxTypeID, $message) {
1419
		// send him the message
1420
		SmrAccount::doMessageSendingToBox($this->getAccountID(), $boxTypeID, $message, $this->getGameID());
1421
	}
1422
1423
	public function sendGlobalMessage($message, $canBeIgnored = true) {
1424
		if ($canBeIgnored) {
1425
			if ($this->getAccount()->isMailBanned()) {
1426
				create_error('You are currently banned from sending messages');
1427
			}
1428
		}
1429
		$this->sendMessageToBox(BOX_GLOBALS, $message);
1430
1431
		// send to all online player
1432
		$db = new SmrMySqlDatabase();
1433
		$db->query('SELECT account_id
1434
					FROM active_session
1435
					JOIN player USING (game_id, account_id)
1436
					WHERE active_session.last_accessed >= ' . $db->escapeNumber(TIME - SmrSession::TIME_BEFORE_EXPIRY) . '
1437
						AND game_id = ' . $db->escapeNumber($this->getGameID()) . '
1438
						AND ignore_globals = \'FALSE\'
1439
						AND account_id != ' . $db->escapeNumber($this->getAccountID()));
1440
1441
		while ($db->nextRecord()) {
1442
			$this->sendMessage($db->getInt('account_id'), MSG_GLOBAL, $message, $canBeIgnored);
1443
		}
1444
		$this->sendMessage($this->getAccountID(), MSG_GLOBAL, $message, $canBeIgnored, false);
1445
	}
1446
1447
	public function sendMessage($receiverID, $messageTypeID, $message, $canBeIgnored = true, $unread = true, $expires = false, $senderDelete = false) {
1448
		//get expire time
1449
		if ($canBeIgnored) {
1450
			if ($this->getAccount()->isMailBanned()) {
1451
				create_error('You are currently banned from sending messages');
1452
			}
1453
			// Don't send messages to players ignoring us
1454
			$this->db->query('SELECT account_id FROM message_blacklist WHERE account_id=' . $this->db->escapeNumber($receiverID) . ' AND blacklisted_id=' . $this->db->escapeNumber($this->getAccountID()) . ' LIMIT 1');
1455
			if ($this->db->nextRecord()) {
1456
				return;
1457
			}
1458
		}
1459
1460
		$message = word_filter($message);
1461
1462
		// If expires not specified, use default based on message type
1463
		if ($expires === false) {
1464
			switch ($messageTypeID) {
1465
				case MSG_GLOBAL: //We don't send globals to the box here or it gets done loads of times.
1466
					$expires = 3600; // 1h
1467
				break;
1468
				case MSG_PLAYER:
1469
					$expires = 86400 * 31;
1470
				break;
1471
				case MSG_PLANET:
1472
					$expires = 86400 * 7;
1473
				break;
1474
				case MSG_SCOUT:
1475
					$expires = 86400 * 3;
1476
				break;
1477
				case MSG_POLITICAL:
1478
					$expires = 86400 * 31;
1479
				break;
1480
				case MSG_ALLIANCE:
1481
					$expires = 86400 * 31;
1482
				break;
1483
				case MSG_ADMIN:
1484
					$expires = 86400 * 365;
1485
				break;
1486
				case MSG_CASINO:
1487
					$expires = 86400 * 31;
1488
				break;
1489
				default:
1490
					$expires = 86400 * 7;
1491
			}
1492
			$expires += TIME;
1493
		}
1494
1495
		// Do not put scout messages in the sender's sent box
1496
		if ($messageTypeID == MSG_SCOUT) {
1497
			$senderDelete = true;
1498
		}
1499
1500
		// send him the message and return the message_id
1501
		return self::doMessageSending($this->getAccountID(), $receiverID, $this->getGameID(), $messageTypeID, $message, $expires, $senderDelete, $unread);
1502
	}
1503
1504
	public function sendMessageFromOpAnnounce($receiverID, $message, $expires = false) {
1505
		// get expire time if not set
1506
		if ($expires === false) {
1507
			$expires = TIME + 86400 * 14;
1508
		}
1509
		self::doMessageSending(ACCOUNT_ID_OP_ANNOUNCE, $receiverID, $this->getGameID(), MSG_ALLIANCE, $message, $expires);
1510
	}
1511
1512
	public function sendMessageFromAllianceCommand($receiverID, $message) {
1513
		$expires = TIME + 86400 * 365;
1514
		self::doMessageSending(ACCOUNT_ID_ALLIANCE_COMMAND, $receiverID, $this->getGameID(), MSG_PLAYER, $message, $expires);
1515
	}
1516
1517
	public static function sendMessageFromPlanet($gameID, $receiverID, $message) {
1518
		//get expire time
1519
		$expires = TIME + 86400 * 31;
1520
		// send him the message
1521
		self::doMessageSending(ACCOUNT_ID_PLANET, $receiverID, $gameID, MSG_PLANET, $message, $expires);
1522
	}
1523
1524
	public static function sendMessageFromPort($gameID, $receiverID, $message) {
1525
		//get expire time
1526
		$expires = TIME + 86400 * 31;
1527
		// send him the message
1528
		self::doMessageSending(ACCOUNT_ID_PORT, $receiverID, $gameID, MSG_PLAYER, $message, $expires);
1529
	}
1530
1531
	public static function sendMessageFromFedClerk($gameID, $receiverID, $message) {
1532
		$expires = TIME + 86400 * 365;
1533
		self::doMessageSending(ACCOUNT_ID_FED_CLERK, $receiverID, $gameID, MSG_PLAYER, $message, $expires);
1534
	}
1535
1536
	public static function sendMessageFromAdmin($gameID, $receiverID, $message, $expires = false) {
1537
		//get expire time
1538
		if ($expires === false) {
1539
			$expires = TIME + 86400 * 365;
1540
		}
1541
		// send him the message
1542
		self::doMessageSending(ACCOUNT_ID_ADMIN, $receiverID, $gameID, MSG_ADMIN, $message, $expires);
1543
	}
1544
1545
	public static function sendMessageFromAllianceAmbassador($gameID, $receiverID, $message, $expires = false) {
1546
		//get expire time
1547
		if ($expires === false) {
1548
			$expires = TIME + 86400 * 31;
1549
		}
1550
		// send him the message
1551
		self::doMessageSending(ACCOUNT_ID_ALLIANCE_AMBASSADOR, $receiverID, $gameID, MSG_ALLIANCE, $message, $expires);
1552
	}
1553
1554
	public static function sendMessageFromCasino($gameID, $receiverID, $message, $expires = false) {
1555
		//get expire time
1556
		if ($expires === false) {
1557
			$expires = TIME + 86400 * 7;
1558
		}
1559
		// send him the message
1560
		self::doMessageSending(ACCOUNT_ID_CASINO, $receiverID, $gameID, MSG_CASINO, $message, $expires);
1561
	}
1562
1563
	public static function sendMessageFromRace($raceID, $gameID, $receiverID, $message, $expires = false) {
1564
		//get expire time
1565
		if ($expires === false) {
1566
			$expires = TIME + 86400 * 5;
1567
		}
1568
		// send him the message
1569
		self::doMessageSending(ACCOUNT_ID_GROUP_RACES + $raceID, $receiverID, $gameID, MSG_POLITICAL, $message, $expires);
1570
	}
1571
1572
	public function setMessagesRead($messageTypeID) {
1573
		$this->db->query('DELETE FROM player_has_unread_messages
1574
							WHERE '.$this->SQL . ' AND message_type_id = ' . $this->db->escapeNumber($messageTypeID));
1575
	}
1576
1577
	public function getPlottedCourse() {
1578
		if (!isset($this->plottedCourse)) {
1579
			// check if we have a course plotted
1580
			$this->db->query('SELECT course FROM player_plotted_course WHERE ' . $this->SQL . ' LIMIT 1');
1581
1582
			if ($this->db->nextRecord()) {
1583
				// get the course back
1584
				$this->plottedCourse = unserialize($this->db->getField('course'));
1585
			} else {
1586
				$this->plottedCourse = false;
1587
			}
1588
		}
1589
1590
		// Update the plotted course if we have moved since the last query
1591
		if ($this->plottedCourse !== false && (!isset($this->plottedCourseFrom) || $this->plottedCourseFrom != $this->getSectorID())) {
1592
			$this->plottedCourseFrom = $this->getSectorID();
1593
1594
			if ($this->plottedCourse->getNextOnPath() == $this->getSectorID()) {
1595
				// We have walked into the next sector of the course
1596
				$this->plottedCourse->followPath();
1597
				$this->setPlottedCourse($this->plottedCourse);
1598
			} elseif ($this->plottedCourse->isInPath($this->getSectorID())) {
1599
				// We have skipped to some later sector in the course
1600
				$this->plottedCourse->skipToSector($this->getSectorID());
1601
				$this->setPlottedCourse($this->plottedCourse);
1602
			}
1603
		}
1604
		return $this->plottedCourse;
1605
	}
1606
1607
	public function setPlottedCourse(Distance $plottedCourse) {
1608
		$hadPlottedCourse = $this->hasPlottedCourse();
1609
		$this->plottedCourse = $plottedCourse;
1610
		if ($this->plottedCourse->getTotalSectors() > 0) {
1611
			$this->db->query('REPLACE INTO player_plotted_course
1612
				(account_id, game_id, course)
1613
				VALUES(' . $this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber($this->getGameID()) . ', ' . $this->db->escapeBinary(serialize($this->plottedCourse)) . ')');
1614
		} elseif ($hadPlottedCourse) {
1615
			$this->deletePlottedCourse();
1616
		}
1617
	}
1618
1619
	public function hasPlottedCourse() {
1620
		return $this->getPlottedCourse() !== false;
1621
	}
1622
1623
	public function isPartOfCourse($sectorOrSectorID) {
1624
		if (!$this->hasPlottedCourse()) {
1625
			return false;
1626
		}
1627
		if ($sectorOrSectorID instanceof SmrSector) {
1628
			$sectorID = $sectorOrSectorID->getSectorID();
1629
		} else {
1630
			$sectorID = $sectorOrSectorID;
1631
		}
1632
		return $this->getPlottedCourse()->isInPath($sectorID);
1633
	}
1634
1635
	public function deletePlottedCourse() {
1636
		$this->plottedCourse = false;
1637
		$this->db->query('DELETE FROM player_plotted_course WHERE ' . $this->SQL . ' LIMIT 1');
1638
	}
1639
1640
	// Computes the turn cost and max misjump between current and target sector
1641
	public function getJumpInfo(SmrSector $targetSector) {
1642
		$path = Plotter::findDistanceToX($targetSector, $this->getSector(), true);
1643
		if ($path === false) {
1644
			create_error('Unable to plot from ' . $this->getSectorID() . ' to ' . $targetSector->getSectorID() . '.');
1645
		}
1646
		$distance = $path->getRelativeDistance();
1647
1648
		$turnCost = max(TURNS_JUMP_MINIMUM, IRound($distance * TURNS_PER_JUMP_DISTANCE));
1649
		$maxMisjump = max(0, IRound(($distance - $turnCost) * MISJUMP_DISTANCE_DIFF_FACTOR / (1 + $this->getLevelID() * MISJUMP_LEVEL_FACTOR)));
1650
		return array('turn_cost' => $turnCost, 'max_misjump' => $maxMisjump);
1651
	}
1652
1653
	public function __sleep() {
1654
		return array('accountID', 'gameID', 'sectorID', 'alignment', 'playerID', 'playerName');
1655
	}
1656
1657
	public function &getStoredDestinations() {
1658
		if (!isset($this->storedDestinations)) {
1659
			$this->storedDestinations = array();
1660
			$this->db->query('SELECT * FROM player_stored_sector WHERE ' . $this->SQL);
1661
			while ($this->db->nextRecord()) {
1662
				$this->storedDestinations[] = array(
1663
					'Label' => $this->db->getField('label'),
1664
					'SectorID' => $this->db->getInt('sector_id'),
1665
					'OffsetTop' => $this->db->getInt('offset_top'),
1666
					'OffsetLeft' => $this->db->getInt('offset_left')
1667
				);
1668
			}
1669
		}
1670
		return $this->storedDestinations;
1671
	}
1672
1673
1674
	public function moveDestinationButton($sectorID, $offsetTop, $offsetLeft) {
1675
1676
		if (!is_numeric($offsetLeft) || !is_numeric($offsetTop)) {
1677
			create_error('The position of the saved sector must be numeric!.');
1678
		}
1679
		$offsetTop = round($offsetTop);
1680
		$offsetLeft = round($offsetLeft);
1681
1682
		if ($offsetLeft < 0 || $offsetLeft > 500 || $offsetTop < 0 || $offsetTop > 300) {
1683
			create_error('The saved sector must be in the box!');
1684
		}
1685
1686
		$storedDestinations =& $this->getStoredDestinations();
1687
		foreach ($storedDestinations as &$sd) {
1688
			if ($sd['SectorID'] == $sectorID) {
1689
				$sd['OffsetTop'] = $offsetTop;
1690
				$sd['OffsetLeft'] = $offsetLeft;
1691
				$this->db->query('
1692
					UPDATE player_stored_sector
1693
						SET offset_left = ' . $this->db->escapeNumber($offsetLeft) . ', offset_top=' . $this->db->escapeNumber($offsetTop) . '
1694
					WHERE ' . $this->SQL . ' AND sector_id = ' . $this->db->escapeNumber($sectorID)
1695
				);
1696
				return true;
1697
			}
1698
		}
1699
1700
		create_error('You do not have a saved sector for #' . $sectorID);
1701
	}
1702
1703
	public function addDestinationButton($sectorID, $label) {
1704
1705
		if (!is_numeric($sectorID) || !SmrSector::sectorExists($this->getGameID(), $sectorID)) {
1706
			create_error('You want to add a non-existent sector?');
1707
		}
1708
1709
		// sector already stored ?
1710
		foreach ($this->getStoredDestinations() as $sd) {
1711
			if ($sd['SectorID'] == $sectorID) {
1712
				create_error('Sector already stored!');
1713
			}
1714
		}
1715
1716
		$this->storedDestinations[] = array(
1717
			'Label' => $label,
1718
			'SectorID' => (int)$sectorID,
1719
			'OffsetTop' => 1,
1720
			'OffsetLeft' => 1
1721
		);
1722
1723
		$this->db->query('
1724
			INSERT INTO player_stored_sector (account_id, game_id, sector_id, label, offset_top, offset_left)
1725
			VALUES (' . $this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber($this->getGameID()) . ', ' . $this->db->escapeNumber($sectorID) . ',' . $this->db->escapeString($label, true) . ',1,1)'
1726
		);
1727
	}
1728
1729
	public function deleteDestinationButton($sectorID) {
1730
		if (!is_numeric($sectorID) || $sectorID < 1) {
1731
			create_error('You want to remove a non-existent sector?');
1732
		}
1733
1734
		foreach ($this->getStoredDestinations() as $key => $sd) {
1735
			if ($sd['SectorID'] == $sectorID) {
1736
				$this->db->query('
1737
					DELETE FROM player_stored_sector
1738
					WHERE ' . $this->SQL . '
1739
					AND sector_id = ' . $this->db->escapeNumber($sectorID)
1740
				);
1741
				unset($this->storedDestinations[$key]);
1742
				return true;
1743
			}
1744
		}
1745
		return false;
1746
	}
1747
1748
	public function getExperienceRank() {
1749
		return $this->computeRanking('experience', $this->getExperience());
1750
	}
1751
	public function getKillsRank() {
1752
		return $this->computeRanking('kills', $this->getKills());
1753
	}
1754
	public function getDeathsRank() {
1755
		return $this->computeRanking('deaths', $this->getDeaths());
1756
	}
1757
	public function getAssistsRank() {
1758
		return $this->computeRanking('assists', $this->getAssists());
1759
	}
1760
	private function computeRanking($dbField, $playerAmount) {
1761
		$this->db->query('SELECT count(*) FROM player
1762
			WHERE game_id = ' . $this->db->escapeNumber($this->getGameID()) . '
1763
			AND (
1764
				'.$dbField . ' > ' . $this->db->escapeNumber($playerAmount) . '
1765
				OR (
1766
					'.$dbField . ' = ' . $this->db->escapeNumber($playerAmount) . '
1767
					AND player_name <= ' . $this->db->escapeString($this->getPlayerName()) . '
1768
				)
1769
			)');
1770
		$this->db->nextRecord();
1771
		$rank = $this->db->getInt('count(*)');
1772
		return $rank;
1773
	}
1774
}
1775