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
Pull Request — master (#1046)
by Dan
05:18
created

doTickerAssigns()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 29
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 20
nc 5
nop 3
dl 0
loc 29
rs 8.9777
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
function htmliseMessage($message) {
4
	$message = htmlentities($message, ENT_COMPAT, 'utf-8');
5
	$message = str_replace('&lt;br /&gt;', '<br />', $message);
6
	return $message;
7
}
8
9
function parseBoolean($check) {
10
	// Only negative strings are not implicitly converted to the correct bool
11
	if (is_string($check) && (strcasecmp($check, 'NO') == 0 || strcasecmp($check, 'FALSE') == 0)) {
12
		return false;
13
	}
14
	return (bool)$check;
15
}
16
17
function linkCombatLog($logID) {
18
	$container = Page::create('combat_log_viewer_verify.php');
19
	$container['log_id'] = $logID;
20
	return '<a href="' . $container->href() . '"><img src="images/notify.gif" width="14" height="11" border="0" title="View the combat log" /></a>';
21
}
22
23
/**
24
 * Converts a BBCode tag into some other text depending on the tag and value.
25
 * This is called in two stages: first with action BBCODE_CHECK (where the
26
 * returned value must be a boolean) and second, if the first check passes,
27
 * with action BBCODE_OUTPUT.
28
 */
29
function smrBBCode($bbParser, $action, $tagName, $default, $tagParams, $tagContent) {
0 ignored issues
show
Unused Code introduced by
The parameter $bbParser is not used and could be removed. ( Ignorable by Annotation )

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

29
function smrBBCode(/** @scrutinizer ignore-unused */ $bbParser, $action, $tagName, $default, $tagParams, $tagContent) {

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

Loading history...
30
	global $overrideGameID, $disableBBLinks;
31
	$session = Smr\Session::getInstance();
32
	try {
33
		switch ($tagName) {
34
			case 'combatlog':
35
				if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
36
					return is_numeric($default);
37
				}
38
				$logID = (int)$default;
39
				return linkCombatLog($logID);
40
			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...
41
			case 'player':
42
				if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
43
					return is_numeric($default);
44
				}
45
				$playerID = (int)$default;
46
				$bbPlayer = SmrPlayer::getPlayerByPlayerID($playerID, $overrideGameID);
47
				$showAlliance = isset($tagParams['showalliance']) ? parseBoolean($tagParams['showalliance']) : false;
48
				if ($disableBBLinks === false && $overrideGameID == $session->getGameID()) {
49
					return $bbPlayer->getLinkedDisplayName($showAlliance);
50
				}
51
				return $bbPlayer->getDisplayName($showAlliance);
52
			break;
53
			case 'alliance':
54
				if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
55
					return is_numeric($default);
56
				}
57
				$allianceID = (int)$default;
58
				$alliance = SmrAlliance::getAlliance($allianceID, $overrideGameID);
59
				if ($disableBBLinks === false && $overrideGameID == $session->getGameID()) {
60
					$container = Page::create('skeleton.php');
61
					$container['alliance_id'] = $alliance->getAllianceID();
62
					if ($session->hasGame() && $alliance->getAllianceID() == $session->getPlayer()->getAllianceID()) {
63
						$container['body'] = 'alliance_mod.php';
64
					} else {
65
						$container['body'] = 'alliance_roster.php';
66
					}
67
					return create_link($container, $alliance->getAllianceDisplayName());
68
				}
69
				return $alliance->getAllianceDisplayName();
70
			break;
71
			case 'race':
72
				$raceNameID = $default;
73
				foreach (Globals::getRaces() as $raceID => $raceInfo) {
74
					if ((is_numeric($raceNameID) && $raceNameID == $raceID)
75
						|| $raceNameID == $raceInfo['Race Name']) {
76
						if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
77
							return true;
78
						}
79
						$linked = $disableBBLinks === false && $overrideGameID == $session->getGameID();
80
						$player = $session->hasGame() ? $session->getPlayer() : null;
81
						return AbstractSmrPlayer::getColouredRaceNameOrDefault($raceID, $player, $linked);
82
					}
83
				}
84
			break;
85
			case 'servertimetouser':
86
				if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
87
					return true;
88
				}
89
				$timeString = $default;
90
				if ($timeString != '' && ($time = strtotime($timeString)) !== false) {
91
					$time += $session->getAccount()->getOffset() * 3600;
92
					return date($session->getAccount()->getDateTimeFormat(), $time);
93
				}
94
			break;
95
			case 'chess':
96
				if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
97
					return is_numeric($default);
98
				}
99
				$chessGameID = (int)$default;
100
				$chessGame = ChessGame::getChessGame($chessGameID);
101
				return '<a href="' . $chessGame->getPlayGameHREF() . '">chess game (' . $chessGame->getChessGameID() . ')</a>';
102
			break;
103
104
			case 'sector':
105
				if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
106
					return is_numeric($default);
107
				}
108
109
				$sectorID = (int)$default;
110
				$sectorTag = '<span class="sectorColour">#' . $sectorID . '</span>';
111
112
				if ($disableBBLinks === false
113
					&& $session->hasGame()
114
					&& $session->getGameID() == $overrideGameID
115
					&& SmrSector::sectorExists($overrideGameID, $sectorID)) {
116
					return '<a href="' . Globals::getPlotCourseHREF($session->getPlayer()->getSectorID(), $sectorID) . '">' . $sectorTag . '</a>';
117
				}
118
119
				return $sectorTag;
120
			break;
121
			case 'join_alliance':
122
				if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
123
					return is_numeric($default);
124
				}
125
				$allianceID = (int)$default;
126
				$alliance = SmrAlliance::getAlliance($allianceID, $overrideGameID);
127
				$container = Page::create('alliance_invite_accept_processing.php');
128
				$container['alliance_id'] = $alliance->getAllianceID();
129
				return '<div class="buttonA"><a class="buttonA" href="' . $container->href() . '">Join ' . $alliance->getAllianceDisplayName() . '</a></div>';
130
			break;
131
		}
132
	} catch (Throwable $e) {
133
		// If there's an error, we will silently display the original text
134
	}
135
	if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
136
		return false;
137
	}
138
	return htmlspecialchars($tagParams['_tag']) . $tagContent . htmlspecialchars($tagParams['_endtag']);
139
}
140
141
function xmlify($str) {
142
	$xml = htmlspecialchars($str, ENT_XML1, 'utf-8');
143
	return $xml;
144
}
145
146
function inify($text) {
147
	return str_replace(',', '', html_entity_decode($text));
148
}
149
150
function bbifyMessage($message, $noLinks = false) {
151
	static $bbParser;
152
	if (!isset($bbParser)) {
153
		$bbParser = new \Nbbc\BBCode();
154
		$bbParser->SetEnableSmileys(false);
155
		$bbParser->RemoveRule('wiki');
156
		$bbParser->RemoveRule('img');
157
		$bbParser->SetURLTarget('_blank');
158
		$bbParser->SetURLTargetable('override');
159
		$bbParser->setEscapeContent(false); // don't escape HTML, needed for News etc.
160
		$smrRule = array(
161
				'mode' => \Nbbc\BBCode::BBCODE_MODE_CALLBACK,
162
				'method' => 'smrBBCode',
163
				'class' => 'link',
164
				'allow_in' => Array('listitem', 'block', 'columns', 'inline'),
165
				'end_tag' => \Nbbc\BBCode::BBCODE_PROHIBIT,
166
				'content' => \Nbbc\BBCode::BBCODE_PROHIBIT,
167
			);
168
		$bbParser->AddRule('combatlog', $smrRule);
169
		$bbParser->AddRule('player', $smrRule);
170
		$bbParser->AddRule('alliance', $smrRule);
171
		$bbParser->AddRule('race', $smrRule);
172
		$bbParser->AddRule('servertimetouser', $smrRule);
173
		$bbParser->AddRule('chess', $smrRule);
174
		$bbParser->AddRule('sector', $smrRule);
175
		$bbParser->addRule('join_alliance', $smrRule);
176
	}
177
	global $disableBBLinks;
178
	if ($noLinks === true) {
179
		$disableBBLinks = true;
180
	} else {
181
		$disableBBLinks = false;
182
	}
183
	if (strpos($message, '[') !== false) { //We have BBCode so let's do a full parse.
184
		$message = $bbParser->parse($message);
185
		$message = str_replace('&lt;br /&gt;', '<br />', $message);
186
	} else { //Otherwise just convert newlines
187
		$message = nl2br($message, true);
188
	}
189
	return $message;
190
}
191
192
function create_error($message) {
193
	$container = Page::create('skeleton.php', 'error.php');
194
	$container['message'] = $message;
195
	if (USING_AJAX) {
196
		// To avoid the page just not refreshing when an error is encountered
197
		// during ajax updates, use javascript to auto-redirect to the
198
		// appropriate error page.
199
		$errorHREF = $container->href();
200
		// json_encode the HREF as a safety precaution
201
		$template = Smr\Template::getInstance();
202
		$template->addJavascriptForAjax('EVAL', 'location.href = ' . json_encode($errorHREF));
203
	}
204
	$container->go();
205
}
206
207
function create_link(Page|string $container, $text, $class = null) {
208
	return '<a' . ($class == null ? '' : ' class="' . $class . '"') . ' href="' . (is_string($container) ? $container : $container->href()) . '">' . $text . '</a>';
209
}
210
211
function create_submit_link(Page $container, $text) {
212
	return '<a href="' . $container->href() . '" class="submitStyle">' . $text . '</a>';
213
}
214
215
function get_colored_text_range($value, $maxValue, $text = null, $minValue = 0, $type = 'Game', $return_type = 'Normal') {
216
	if ($text == null) {
217
		$text = number_format($value);
218
	}
219
	if ($maxValue - $minValue == 0) {
220
		return $text;
221
	} else {
222
		$normalisedValue = IRound(510 * max(0, min($maxValue, $value) - $minValue) / ($maxValue - $minValue)) - 255;
223
	}
224
	if ($type == 'Game') {
225
		if ($normalisedValue < 0) {
226
			$r_component = 'ff';
227
			$g_component = dechex(255 + $normalisedValue);
228
			if (strlen($g_component) == 1) {
229
				$g_component = '0' . $g_component;
230
			}
231
		} else if ($normalisedValue > 0) {
232
			$g_component = 'ff';
233
			$r_component = dechex(255 - $normalisedValue);
234
			if (strlen($r_component) == 1) {
235
				$r_component = '0' . $r_component;
236
			}
237
		} else {
238
			$r_component = 'ff';
239
			$g_component = 'ff';
240
		}
241
		$colour = $r_component . $g_component . '00';
242
		if ($return_type == 'Colour') {
243
			return $colour;
244
		}
245
		return '<span style="color:#' . $colour . '">' . $text . '</span>';
246
	} elseif ($type == 'IRC') {
247
		//IRC color codes
248
		if ($normalisedValue == 255) {
249
			$colour = '[k03]';
250
		} elseif ($normalisedValue == -255) {
251
			$colour = '[k04]';
252
		} else {
253
			$colour = '[k08]';
254
		}
255
		if ($return_type == 'Colour') {
256
			return $colour;
257
		}
258
		return $colour . $text;
259
	}
260
}
261
262
function get_colored_text($value, $text = null, $type = 'Game', $return_type = 'Normal') {
263
	return get_colored_text_range($value, 300, $text, -300, $type, $return_type);
264
}
265
266
function word_filter($string) {
267
	static $words;
268
269
	if (!is_array($words)) {
270
		$db = Smr\Database::getInstance();
271
		$db->query('SELECT word_value, word_replacement FROM word_filter');
272
		$words = array();
273
		while ($db->nextRecord()) {
274
			$row = $db->getRow();
275
			$words[] = array('word_value' => '/' . str_replace('/', '\/', $row['word_value']) . '/i', 'word_replacement'=> $row['word_replacement']);
276
		}
277
	}
278
279
	foreach ($words as $word) {
280
		$string = preg_replace($word['word_value'], $word['word_replacement'], $string);
281
	}
282
283
	return $string;
284
}
285
286
// choose correct pluralization based on amount
287
function pluralise($word, $count = 0) {
288
	if ($count == 1) {
289
		return $word;
290
	}
291
	if (strtolower($word) == 'is') {
292
		return 'are';
293
	}
294
	return $word . 's';
295
}
296
297
/**
298
 * This function is a hack around the old style http forward mechanism.
299
 * It is also responsible for setting most of the global variables
300
 * (see loader.php for the initialization of the globals).
301
 */
302
function do_voodoo() {
303
	global $lock;
304
305
	$session = Smr\Session::getInstance();
306
	$var = $session->getCurrentVar();
307
308
	if (!defined('AJAX_CONTAINER')) {
309
		define('AJAX_CONTAINER', isset($var['AJAX']) && $var['AJAX'] === true);
310
	}
311
312
	if (!AJAX_CONTAINER && USING_AJAX && $session->hasChangedSN()) {
313
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
314
	}
315
//	ob_clean();
316
317
	// create account object
318
	$account = $session->getAccount();
319
320
	$db = Smr\Database::getInstance();
321
322
	if ($session->hasGame()) {
323
		if (SmrGame::getGame($session->getGameID())->hasEnded()) {
324
			Page::create('game_leave_processing.php', 'game_play.php', array('errorMsg' => 'The game has ended.'))->go();
325
		}
326
		// We need to acquire locks BEFORE getting the player information
327
		// Otherwise we could be working on stale information
328
		$db->query('SELECT sector_id FROM player WHERE account_id=' . $db->escapeNumber($account->getAccountID()) . ' AND game_id=' . $db->escapeNumber($session->getGameID()) . ' LIMIT 1');
329
		$db->requireRecord();
330
		$sector_id = $db->getInt('sector_id');
331
332
		global $locksFailed;
333
		if (!USING_AJAX //AJAX should never do anything that requires a lock.
334
//			&& !isset($var['url']) && ($var['body'] == 'current_sector.php' || $var['body'] == 'map_local.php') //Neither should CS or LM and they gets loaded a lot so should reduce lag issues with big groups.
335
			) {
336
			if (!$lock && !isset($locksFailed[$sector_id])) {
337
				if (!acquire_lock($sector_id)) {
338
					create_error('Failed to acquire sector lock');
339
				}
340
				//Refetch var info in case it changed between grabbing lock.
341
				$session->fetchVarInfo();
342
				if ($session->hasCurrentVar() === false) {
343
					if (ENABLE_DEBUG) {
344
						$db->query('INSERT INTO debug VALUES (\'SPAM\',' . $db->escapeNumber($account->getAccountID()) . ',0,0)');
345
					}
346
					create_error('Please do not spam click!');
347
				}
348
			}
349
		}
350
351
		// Now that they've acquire a lock we can move on
352
		$player = $session->getPlayer();
353
354
		if ($player->isDead() && $var['url'] != 'death_processing.php' && !isset($var['override_death'])) {
355
			Page::create('death_processing.php')->go();
356
		}
357
358
		// update turns on that player
359
		$player->updateTurns();
360
361
		if (!$player->isDead() && $player->getNewbieTurns() <= NEWBIE_TURNS_WARNING_LIMIT &&
362
			$player->getNewbieWarning() &&
363
			$var['url'] != 'newbie_warning_processing.php')
364
			Page::create('newbie_warning_processing.php')->go();
365
	}
366
367
	// Initialize the template
368
	$template = Smr\Template::getInstance();
369
370
	// Execute the engine files.
371
	// This is where the majority of the page-specific work is performed.
372
	$var->process();
373
374
	if ($session->hasGame()) {
375
		$template->assign('UnderAttack', $player->removeUnderAttack());
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $player does not seem to be defined for all execution paths leading up to this point.
Loading history...
376
	}
377
378
	if ($lock) { //Only save if we have the lock.
379
		SmrSector::saveSectors();
380
		SmrShip::saveShips();
381
		SmrPlayer::savePlayers();
382
		SmrForce::saveForces();
383
		SmrPort::savePorts();
384
		SmrPlanet::savePlanets();
385
		if (class_exists('WeightedRandom', false)) {
386
			WeightedRandom::saveWeightedRandoms();
387
		}
388
		//Update session here to make sure current page $var is up to date before releasing lock.
389
		$session->update();
390
		release_lock();
391
	}
392
393
	//Nothing below this point should require the lock.
394
395
	$template->assign('TemplateBody', $var['body']);
396
	if ($session->hasGame()) {
397
		$template->assign('ThisSector', $player->getSector());
398
		$template->assign('ThisPlayer', $player);
399
		$template->assign('ThisShip', $player->getShip());
400
	}
401
	$template->assign('ThisAccount', $account);
402
	if ($account->getCssLink() != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $account->getCssLink() of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
403
		$template->assign('ExtraCSSLink', $account->getCssLink());
404
	}
405
	doSkeletonAssigns($template, $db);
406
407
	// Set ajax refresh time
408
	$ajaxRefresh = $var['AllowAjax'] ?? true; // hack for bar_gambling_processing.php
409
	if (!$account->isUseAJAX()) {
410
		$ajaxRefresh = false;
411
	}
412
	if ($ajaxRefresh) {
413
		// If we can refresh, specify the refresh interval in millisecs
414
		if ($session->hasGame() && $player->canFight()) {
415
			$ajaxRefresh = AJAX_UNPROTECTED_REFRESH_TIME;
416
		} else {
417
			$ajaxRefresh = AJAX_DEFAULT_REFRESH_TIME;
418
		}
419
	}
420
	$template->assign('AJAX_ENABLE_REFRESH', $ajaxRefresh);
421
422
	$template->display($var['url'], USING_AJAX || AJAX_CONTAINER);
423
424
	$session->update();
425
426
	exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
427
}
428
429
//xdebug_dump_function_profile(2);
430
431
// This is hackish, but without row level locking it's the best we can do
432
function acquire_lock($sector) {
433
	global $lock, $locksFailed;
434
435
	if ($lock) {
436
		return true;
437
	}
438
439
	// Insert ourselves into the queue.
440
	$session = Smr\Session::getInstance();
441
	$db = Smr\Database::getInstance();
442
	$db->query('INSERT INTO locks_queue (game_id,account_id,sector_id,timestamp) VALUES(' . $db->escapeNumber($session->getGameID()) . ',' . $db->escapeNumber($session->getAccountID()) . ',' . $db->escapeNumber($sector) . ',' . $db->escapeNumber(Smr\Epoch::time()) . ')');
443
	$lock = $db->getInsertID();
444
445
	for ($i = 0; $i < 250; ++$i) {
446
		if (time() - Smr\Epoch::time() >= LOCK_DURATION - LOCK_BUFFER) {
447
			break;
448
		}
449
		// If there is someone else before us in the queue we sleep for a while
450
		$db->query('SELECT COUNT(*) FROM locks_queue WHERE lock_id<' . $db->escapeNumber($lock) . ' AND sector_id=' . $db->escapeNumber($sector) . ' AND game_id=' . $db->escapeNumber($session->getGameID()) . ' AND timestamp > ' . $db->escapeNumber(Smr\Epoch::time() - LOCK_DURATION));
451
		$locksInQueue = -1;
0 ignored issues
show
Unused Code introduced by
The assignment to $locksInQueue is dead and can be removed.
Loading history...
452
		if ($db->nextRecord() && ($locksInQueue = $db->getInt('COUNT(*)')) > 0) {
453
			//usleep(100000 + mt_rand(0,50000));
454
455
			// We can only have one lock in the queue, anything more means someone is screwing around
456
			$db->query('SELECT COUNT(*) FROM locks_queue WHERE account_id=' . $db->escapeNumber($session->getAccountID()) . ' AND sector_id=' . $db->escapeNumber($sector) . ' AND timestamp > ' . $db->escapeNumber(Smr\Epoch::time() - LOCK_DURATION));
457
			if ($db->nextRecord() && $db->getInt('COUNT(*)') > 1) {
458
				release_lock();
459
				$locksFailed[$sector] = true;
460
				create_error('Multiple actions cannot be performed at the same time!');
461
			}
462
463
			usleep(25000 * $locksInQueue);
464
			continue;
465
		} else {
466
			return true;
467
		}
468
	}
469
470
	release_lock();
471
	$locksFailed[$sector] = true;
472
	return false;
473
}
474
475
function release_lock() {
476
	global $lock;
477
478
	if ($lock) {
479
		$db = Smr\Database::getInstance();
480
		$db->query('DELETE from locks_queue WHERE lock_id=' . $db->escapeNumber($lock) . ' OR timestamp<' . $db->escapeNumber(Smr\Epoch::time() - LOCK_DURATION));
481
	}
482
483
	$lock = false;
484
}
485
486
function doTickerAssigns($template, $player, $db) {
487
	//any ticker news?
488
	if ($player->hasTickers()) {
489
		$ticker = array();
490
		$max = Smr\Epoch::time() - 60;
491
		$dateFormat = $player->getAccount()->getDateTimeFormat();
492
		if ($player->hasTicker('NEWS')) {
493
			//get recent news (5 mins)
494
			$db->query('SELECT time,news_message FROM news WHERE game_id = ' . $db->escapeNumber($player->getGameID()) . ' AND time >= ' . $max . ' ORDER BY time DESC LIMIT 4');
495
			while ($db->nextRecord()) {
496
				$ticker[] = array('Time' => date($dateFormat, $db->getInt('time')),
497
								'Message'=>$db->getField('news_message'));
498
			}
499
		}
500
		if ($player->hasTicker('SCOUT')) {
501
			$db->query('SELECT message_text,send_time FROM message
502
						WHERE account_id=' . $db->escapeNumber($player->getAccountID()) . '
503
						AND game_id=' . $db->escapeNumber($player->getGameID()) . '
504
						AND message_type_id=' . $db->escapeNumber(MSG_SCOUT) . '
505
						AND send_time>=' . $db->escapeNumber($max) . '
506
						AND sender_id NOT IN (SELECT account_id FROM player_has_ticker WHERE type='.$db->escapeString('BLOCK') . ' AND expires > ' . $db->escapeNumber(Smr\Epoch::time()) . ' AND game_id = ' . $db->escapeNumber($player->getGameID()) . ') AND receiver_delete = \'FALSE\'
507
						ORDER BY send_time DESC
508
						LIMIT 4');
509
			while ($db->nextRecord()) {
510
				$ticker[] = array('Time' => date($dateFormat, $db->getInt('send_time')),
511
								'Message'=>$db->getField('message_text'));
512
			}
513
		}
514
		$template->assign('Ticker', $ticker);
515
	}
516
}
517
518
function doSkeletonAssigns($template, $db) {
519
	$session = Smr\Session::getInstance();
520
	$account = $session->getAccount();
521
522
	$template->assign('CSSLink', $account->getCssUrl());
523
	$template->assign('CSSColourLink', $account->getCssColourUrl());
524
525
	$template->assign('FontSize', $account->getFontSize() - 20);
526
	$template->assign('timeDisplay', date($account->getDateTimeFormatSplit(), Smr\Epoch::time()));
527
528
	$container = Page::create('skeleton.php');
529
530
531
	if ($session->hasGame()) {
532
		$player = $session->getPlayer();
533
		$template->assign('GameName', SmrGame::getGame($session->getGameID())->getName());
534
		$template->assign('GameID', $session->getGameID());
535
536
		$template->assign('PlotCourseLink', Globals::getPlotCourseHREF());
537
538
		$template->assign('TraderLink', Globals::getTraderStatusHREF());
539
540
		$template->assign('PoliticsLink', Globals::getPoliticsHREF());
541
542
		$container['body'] = 'combat_log_list.php';
543
		$template->assign('CombatLogsLink', $container->href());
544
545
		$template->assign('PlanetLink', Globals::getPlanetListHREF($player->getAllianceID()));
546
547
		$container['body'] = 'forces_list.php';
548
		$template->assign('ForcesLink', $container->href());
549
550
		$template->assign('MessagesLink', Globals::getViewMessageBoxesHREF());
551
552
		$container['body'] = 'news_read_current.php';
553
		$template->assign('ReadNewsLink', $container->href());
554
555
		$container['body'] = 'galactic_post_current.php';
556
		$template->assign('GalacticPostLink', $container->href());
557
558
		$container['body'] = 'trader_search.php';
559
		$template->assign('SearchForTraderLink', $container->href());
560
561
		$container['body'] = 'rankings_player_experience.php';
562
		$template->assign('RankingsLink', $container->href());
563
564
		$container['body'] = 'hall_of_fame_new.php';
565
		$container['game_id'] = $player->getGameID();
566
		$template->assign('CurrentHallOfFameLink', $container->href());
567
	}
568
569
	$container = Page::create('skeleton.php', 'hall_of_fame_new.php');
570
	$template->assign('HallOfFameLink', $container->href());
571
572
	$template->assign('AccountID', $account->getAccountID());
573
	$template->assign('PlayGameLink', Page::create('game_leave_processing.php', 'game_play.php')->href());
574
575
	$template->assign('LogoutLink', Page::create('logoff.php')->href());
576
577
	$container = Page::create('game_leave_processing.php', 'admin_tools.php');
578
	$template->assign('AdminToolsLink', $container->href());
579
580
	$container = Page::create('skeleton.php', 'preferences.php');
581
	$template->assign('PreferencesLink', $container->href());
582
583
	$container['body'] = 'album_edit.php';
584
	$template->assign('EditPhotoLink', $container->href());
585
586
	$container['body'] = 'bug_report.php';
587
	$template->assign('ReportABugLink', $container->href());
588
589
	$container['body'] = 'contact.php';
590
	$template->assign('ContactFormLink', $container->href());
591
592
	$container['body'] = 'chat_rules.php';
593
	$template->assign('IRCLink', $container->href());
594
595
	$container['body'] = 'donation.php';
596
	$template->assign('DonateLink', $container->href());
597
598
599
600
	if ($session->hasGame()) {
601
		$db->query('SELECT message_type_id,COUNT(*) FROM player_has_unread_messages WHERE ' . $player->getSQL() . ' GROUP BY message_type_id');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $player does not seem to be defined for all execution paths leading up to this point.
Loading history...
602
603
		if ($db->getNumRows()) {
604
			$messages = array();
605
			while ($db->nextRecord()) {
606
				$messages[$db->getInt('message_type_id')] = $db->getInt('COUNT(*)');
607
			}
608
609
			$container = Page::create('skeleton.php', 'message_view.php');
610
611
			if (isset($messages[MSG_GLOBAL])) {
612
				$container['folder_id'] = MSG_GLOBAL;
613
				$template->assign('MessageGlobalLink', $container->href());
614
				$template->assign('MessageGlobalNum', $messages[MSG_GLOBAL]);
615
			}
616
617
			if (isset($messages[MSG_PLAYER])) {
618
				$container['folder_id'] = MSG_PLAYER;
619
				$template->assign('MessagePersonalLink', $container->href());
620
				$template->assign('MessagePersonalNum', $messages[MSG_PLAYER]);
621
			}
622
623
			if (isset($messages[MSG_SCOUT])) {
624
				$container['folder_id'] = MSG_SCOUT;
625
				$template->assign('MessageScoutLink', $container->href());
626
				$template->assign('MessageScoutNum', $messages[MSG_SCOUT]);
627
			}
628
629
			if (isset($messages[MSG_POLITICAL])) {
630
				$container['folder_id'] = MSG_POLITICAL;
631
				$template->assign('MessagePoliticalLink', $container->href());
632
				$template->assign('MessagePoliticalNum', $messages[MSG_POLITICAL]);
633
			}
634
635
			if (isset($messages[MSG_ALLIANCE])) {
636
				$container['folder_id'] = MSG_ALLIANCE;
637
				$template->assign('MessageAllianceLink', $container->href());
638
				$template->assign('MessageAllianceNum', $messages[MSG_ALLIANCE]);
639
			}
640
641
			if (isset($messages[MSG_ADMIN])) {
642
				$container['folder_id'] = MSG_ADMIN;
643
				$template->assign('MessageAdminLink', $container->href());
644
				$template->assign('MessageAdminNum', $messages[MSG_ADMIN]);
645
			}
646
647
			if (isset($messages[MSG_CASINO])) {
648
				$container['folder_id'] = MSG_CASINO;
649
				$template->assign('MessageCasinoLink', $container->href());
650
				$template->assign('MessageCasinoNum', $messages[MSG_CASINO]);
651
			}
652
653
			if (isset($messages[MSG_PLANET])) {
654
				$container = Page::create('planet_msg_processing.php');
655
				$template->assign('MessagePlanetLink', $container->href());
656
				$template->assign('MessagePlanetNum', $messages[MSG_PLANET]);
657
			}
658
		}
659
660
		$container = Page::create('skeleton.php', 'trader_search_result.php');
661
		$container['player_id'] = $player->getPlayerID();
662
		$template->assign('PlayerNameLink', $container->href());
663
664
		if (is_array(Globals::getHiddenPlayers()) && in_array($player->getAccountID(), Globals::getHiddenPlayers())) {
665
			$template->assign('PlayerInvisible', true);
666
		}
667
668
		// ******* Hardware *******
669
		$container = Page::create('skeleton.php', 'configure_hardware.php');
670
671
		$template->assign('HardwareLink', $container->href());
672
673
		// ******* Forces *******
674
		$template->assign('ForceDropLink', Page::create('skeleton.php', 'forces_drop.php')->href());
675
676
		$ship = $player->getShip();
677
		if ($ship->hasMines()) {
678
			$container = Page::create('forces_drop_processing.php');
679
			$container['owner_id'] = $player->getAccountID();
680
			$container['drop_mines'] = 1;
681
			$container->addVar('body', 'referrer');
682
			$template->assign('DropMineLink', $container->href());
683
		}
684
		if ($ship->hasCDs()) {
685
			$container = Page::create('forces_drop_processing.php');
686
			$container['owner_id'] = $player->getAccountID();
687
			$container['drop_combat_drones'] = 1;
688
			$container->addVar('body', 'referrer');
689
			$template->assign('DropCDLink', $container->href());
690
		}
691
692
		if ($ship->hasSDs()) {
693
			$container = Page::create('forces_drop_processing.php');
694
			$container['owner_id'] = $player->getAccountID();
695
			$container['drop_scout_drones'] = 1;
696
			$container->addVar('body', 'referrer');
697
			$template->assign('DropSDLink', $container->href());
698
		}
699
700
		$template->assign('CargoJettisonLink', Page::create('skeleton.php', 'cargo_dump.php')->href());
701
702
		$template->assign('WeaponReorderLink', Page::create('skeleton.php', 'weapon_reorder.php')->href());
703
704
	}
705
706
	// ------- VOTING --------
707
	$voteSites = array();
708
	foreach (VoteSite::getAllSites() as $site) {
709
		$voteSites[] = array(
710
			'img' => $site->getLinkImg($account->getAccountID(), $session->getGameID()),
711
			'url' => $site->getLinkUrl($account->getAccountID(), $session->getGameID()),
712
			'sn' => $site->getSN($account->getAccountID(), $session->getGameID()),
713
		);
714
	}
715
	$template->assign('VoteSites', $voteSites);
716
717
	// Determine the minimum time until the next vote across all sites
718
	$minVoteWait = VoteSite::getMinTimeUntilFreeTurns($account->getAccountID());
719
	if ($minVoteWait <= 0) {
720
		$template->assign('TimeToNextVote', 'now');
721
	} else {
722
		$template->assign('TimeToNextVote', 'in ' . format_time($minVoteWait, true));
723
	}
724
725
	// ------- VERSION --------
726
	$db->query('SELECT * FROM version ORDER BY went_live DESC LIMIT 1');
727
	$version = '';
728
	if ($db->nextRecord()) {
729
		$container = Page::create('skeleton.php', 'changelog_view.php');
730
		$version = create_link($container, 'v' . $db->getField('major_version') . '.' . $db->getField('minor_version') . '.' . $db->getField('patch_level'));
731
	}
732
733
	$template->assign('Version', $version);
734
	$template->assign('CurrentYear', date('Y', Smr\Epoch::time()));
735
}
736
737
/**
738
 * Convert an integer number of seconds into a human-readable time.
739
 * Seconds are omitted to avoid frequent and disruptive ajax updates.
740
 * Use short=true to use 1-letter units (e.g. "1h and 3m").
741
 * If seconds is negative, will append "ago" to the result.
742
 * If seconds is zero, will return only "now".
743
 * If seconds is <60, will prefix "less than" or "<" (HTML-safe).
744
 */
745
function format_time($seconds, $short = false) {
746
	if ($seconds == 0) {
747
		return "now";
748
	}
749
750
	if ($seconds < 0) {
751
		$past = true;
752
		$seconds = abs($seconds);
753
	} else {
754
		$past = false;
755
	}
756
757
	$minutes = ceil($seconds / 60);
758
	$hours = 0;
759
	$days = 0;
760
	$weeks = 0;
761
	if ($minutes >= 60) {
762
		$hours = floor($minutes / 60);
763
		$minutes = $minutes % 60;
764
	}
765
	if ($hours >= 24) {
766
		$days = floor($hours / 24);
767
		$hours = $hours % 24;
768
	}
769
	if ($days >= 7) {
770
		$weeks = floor($days / 7);
771
		$days = $days % 7;
772
	}
773
	$times = [
774
		'week' => $weeks,
775
		'day' => $days,
776
		'hour' => $hours,
777
		'minute' => $minutes,
778
	];
779
	$parts = [];
780
	foreach ($times as $unit => $amount) {
781
		if ($amount > 0) {
782
			if ($short) {
783
				$parts[] = $amount . $unit[0];
784
			} else {
785
				$parts[] = $amount . ' ' . pluralise($unit, $amount);
786
			}
787
		}
788
	}
789
790
	if (count($parts) == 1) {
791
		$result = $parts[0];
792
	} else {
793
		// e.g. 5h, 10m and 30s
794
		$result = join(', ', array_slice($parts, 0, -1)) . ' and ' . end($parts);
795
	}
796
797
	if ($seconds < 60) {
798
		$result = ($short ? '&lt;' : 'less than ') . $result;
799
	}
800
801
	if ($past) {
802
		$result .= ' ago';
803
	}
804
	return $result;
805
}
806
807
function number_colour_format($number, $justSign = false) {
808
	$formatted = '<span';
809
	if ($number > 0) {
810
		$formatted .= ' class="green">+';
811
	} else if ($number < 0) {
812
		$formatted .= ' class="red">-';
813
	} else {
814
		$formatted .= '>';
815
	}
816
	if ($justSign === false) {
817
		$decimalPlaces = 0;
818
		if (($pos = strpos((string)$number, '.')) !== false) {
819
			$decimalPlaces = strlen(substr((string)$number, $pos + 1));
820
		}
821
		$formatted .= number_format(abs($number), $decimalPlaces);
822
	}
823
	$formatted .= '</span>';
824
	return $formatted;
825
}
826
827
828
/**
829
 * Randomly choose an array key weighted by the array values.
830
 * Probabilities are relative to the total weight. For example:
831
 *
832
 * array(
833
 *    'A' => 1, // 10% chance
834
 *    'B' => 3, // 30% chance
835
 *    'C' => 6, // 60% chance
836
 * );
837
 */
838
function getWeightedRandom(array $choices) : string|int {
839
	// Normalize the weights so that their sum is much larger than 1.
840
	$maxWeight = max($choices);
841
	foreach ($choices as $key => $weight) {
842
		$choices[$key] = IRound($weight * 1000 / $maxWeight);
843
	}
844
845
	// Generate a random number that is lower than the sum of the weights.
846
	$rand = rand(1, array_sum($choices));
0 ignored issues
show
Bug introduced by
It seems like array_sum($choices) can also be of type double; however, parameter $max of rand() does only seem to accept integer, 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

846
	$rand = rand(1, /** @scrutinizer ignore-type */ array_sum($choices));
Loading history...
847
848
	// Subtract weights from the random number until it is negative,
849
	// then return the key associated with that weight.
850
	foreach ($choices as $key => $weight) {
851
		$rand -= $weight;
852
		if ($rand <= 0) {
853
			return $key;
854
		}
855
	}
856
	throw new Exception('Internal error computing weights');
857
}
858